#include "utf7.h" /* ASCII subsets */ static const unsigned char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const unsigned char safe[] = "'(),-.:?"; static const unsigned char optional[] = "!\"#$%&*;<=>@[]^_`{|}"; static const unsigned char space[] = " \t\n\r"; #define TRUE 1 #define FALSE 0 typedef int bool; #define NUMBYTES 256 #define CHARSIZE 16 /* character classes */ #define BASE64 0x01 #define SAFE 0x02 #define OPTIONAL 0x04 #define SPACE 0x08 static char inv_base64[128]; static char char_type[NUMBYTES]; static bool initialized; static void invert() { int i; const unsigned char *s; initialized = TRUE; for (i = 0; i < NUMBYTES; i++) char_type[i] = 0; for (s = base64; *s != '\0'; s++) { char_type[*s] |= BASE64; inv_base64[*s] = s - base64; } for (s = safe; *s != '\0'; s++) char_type[*s] |= SAFE; for (s = optional; *s != '\0'; s++) char_type[*s] |= OPTIONAL; for (s = space; *s != '\0'; s++) char_type[*s] |= SPACE; } static bool in_base64; static unsigned long bit_buffer; static int nbits; long utf7_getc(f) FILE *f; { int c; if (! initialized) invert(); for (;;) { if ((c = getc(f)) == EOF) return EOF; if (! in_base64) { if (c != '+') return c; if ((c = getc(f)) == EOF) return EOF; if (c == '-') return '+'; in_base64 = TRUE; nbits = 0; } /* now we're in Base64 mode */ while (char_type[c]&BASE64) { bit_buffer <<= 6; bit_buffer |= inv_base64[c]; nbits += 6; if (nbits >= 16) { nbits -= 16; return ((bit_buffer >> nbits)&0xffffL); } if ((c = getc(f)) == EOF) return EOF; } in_base64 = FALSE; if (c != '-') return c; } } /* * Sloppiness: * - uses same bit_buffer as utf7_getc(): change if both needed at once. * - assumes last character output is safe (e.g. newline) so no flush * is needed. */ void utf7_putc(c, f) unsigned int c; FILE *f; { if (! initialized) invert(); if (c <= 0x7f && (char_type[c] & (BASE64|SAFE|SPACE))) { if (in_base64) { if (nbits > 0) putc(base64[(bit_buffer<<(6-nbits))&0x3f], f); if ((char_type[c] & BASE64) || c == '-') putchar('-'); in_base64 = FALSE; } putc(c, f); if (c == '+') putc('-', f); } else { if (! in_base64) { putc('+', f); in_base64 = TRUE; nbits = 0; } bit_buffer <<= CHARSIZE; bit_buffer |= c; nbits += CHARSIZE; while (nbits >= 6) { nbits -= 6; putc(base64[(bit_buffer >> nbits)&0x3f], f); } } }