/* * aegis - project change supervisor * Copyright (C) 1999, 2001 Peter Miller; * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * MANIFEST: functions to manipulate base64s */ #include <input/base64.h> #include <input/private.h> #include <stracc.h> typedef struct input_base64_ty input_base64_ty; struct input_base64_ty { input_ty inherited; input_ty *deeper; int close_on_close; long pos; int residual_bits; int residual_value; int eof; }; static void input_base64_destructor _((input_ty *)); static void input_base64_destructor(fp) input_ty *fp; { input_base64_ty *this; this = (input_base64_ty *)fp; if (this->close_on_close) input_delete(this->deeper); this->deeper = 0; /* paranoia */ } static long input_base64_read _((input_ty *, void *, size_t)); static long input_base64_read(fp, data, len) input_ty *fp; void *data; size_t len; { input_base64_ty *this; int c; unsigned char *cp; unsigned char *end; size_t nbytes; this = (input_base64_ty *)fp; if (this->eof) return 0; cp = data; end = cp + len; while (cp < end) { while (this->residual_bits < 8) { c = input_getc(this->deeper); switch (c) { case ' ': case '\t': case '\r': case '\n': continue; case '=': this->eof = 1; goto done; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': /* * This next statement is not portable to * non-ascii character sets, because A-Z * are not guaranteed to be continuous. */ c = c - 'A'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': /* * This next statement is not portable to * non-ascii character sets, because a-z * are not guaranteed to be continuous. */ c = c - 'a' + 26; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = c - '0' + 52; break; case '+': c = 62; break; case '/': c = 63; break; default: if (c < 0) { if (this->residual_bits != 0) input_fatal_error(fp, "base64: residual bits != 0"); this->eof = 1; goto done; } input_fatal_error(fp, "base64: invalid character"); /* NOTREACHED */ } this->residual_value = (this->residual_value << 6) + c; this->residual_bits += 6; } this->residual_bits -= 8; *cp++ = (this->residual_value >> this->residual_bits); } done: nbytes = (cp - (unsigned char *)data); this->pos += nbytes; return nbytes; } static long input_base64_tell _((input_ty *)); static long input_base64_tell(deeper) input_ty *deeper; { input_base64_ty *this; this = (input_base64_ty *)deeper; return this->pos; } static struct string_ty *input_base64_name _((input_ty *)); static struct string_ty * input_base64_name(fp) input_ty *fp; { input_base64_ty *this; this = (input_base64_ty *)fp; return input_name(this->deeper); } static long input_base64_length _((input_ty *)); static long input_base64_length(fp) input_ty *fp; { return -1; } static input_vtbl_ty vtbl = { sizeof(input_base64_ty), input_base64_destructor, input_base64_read, input_base64_tell, input_base64_name, input_base64_length, }; input_ty * input_base64(deeper, coc) input_ty *deeper; int coc; { input_ty *result; input_base64_ty *this; result = input_new(&vtbl); this = (input_base64_ty *)result; this->deeper = deeper; this->close_on_close = !!coc; this->pos = 0; this->residual_bits = 0; this->residual_value = 0; this->eof = 0; return result; } int input_base64_recognise(ifp) input_ty *ifp; { int result; int c; stracc_t buffer; /* * There are only a few characters which ara acceptable to * the base64 filter. Any others are conclusive evidence * of wrongness. */ result = 1; stracc_constructor(&buffer); stracc_open(&buffer); while (buffer.length < 8000) { c = input_getc(ifp); if (c < 0) break; stracc_char(&buffer, c); switch (c) { case '\t': case '\n': case '\r': case ' ': case '+': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '=': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': continue; default: result = 0; break; } break; } input_unread(ifp, buffer.buffer, buffer.length); stracc_destructor(&buffer); return result; }