/* This file is in the public domain. */ #include #include #include "b64.h" typedef struct b64rstate B64RSTATE; typedef struct b64wstate B64WSTATE; typedef struct b64wwrap B64WWRAP; struct b64rstate { int (*get)(void *); void *arg; int done; unsigned char buf[3]; int fill; int ptr; } ; struct b64wstate { void (*put)(void *, int); void *arg; unsigned char buf[3]; int fill; } ; struct b64wwrap { void *b64; FILE *f; } ; static const unsigned char b64chars[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static int b64val(char c) { switch (c) { case 'A': return( 0); break; case 'B': return( 1); break; case 'C': return( 2); break; case 'D': return( 3); break; case 'E': return( 4); break; case 'F': return( 5); break; case 'G': return( 6); break; case 'H': return( 7); break; case 'I': return( 8); break; case 'J': return( 9); break; case 'K': return(10); break; case 'L': return(11); break; case 'M': return(12); break; case 'N': return(13); break; case 'O': return(14); break; case 'P': return(15); break; case 'Q': return(16); break; case 'R': return(17); break; case 'S': return(18); break; case 'T': return(19); break; case 'U': return(20); break; case 'V': return(21); break; case 'W': return(22); break; case 'X': return(23); break; case 'Y': return(24); break; case 'Z': return(25); break; case 'a': return(26); break; case 'b': return(27); break; case 'c': return(28); break; case 'd': return(29); break; case 'e': return(30); break; case 'f': return(31); break; case 'g': return(32); break; case 'h': return(33); break; case 'i': return(34); break; case 'j': return(35); break; case 'k': return(36); break; case 'l': return(37); break; case 'm': return(38); break; case 'n': return(39); break; case 'o': return(40); break; case 'p': return(41); break; case 'q': return(42); break; case 'r': return(43); break; case 's': return(44); break; case 't': return(45); break; case 'u': return(46); break; case 'v': return(47); break; case 'w': return(48); break; case 'x': return(49); break; case 'y': return(50); break; case 'z': return(51); break; case '0': return(52); break; case '1': return(53); break; case '2': return(54); break; case '3': return(55); break; case '4': return(56); break; case '5': return(57); break; case '6': return(58); break; case '7': return(59); break; case '8': return(60); break; case '9': return(61); break; case '+': return(62); break; case '/': return(63); break; } return(-1); } static void b64w_flush(B64WSTATE *s) { unsigned int v; switch (s->fill) { case 0: break; case 1: (*s->put)(s->arg,b64chars[s->buf[0]>>2]); (*s->put)(s->arg,b64chars[(s->buf[0]<<4)&63]); (*s->put)(s->arg,'='); (*s->put)(s->arg,'='); break; case 2: v = (s->buf[0] << 8) | s->buf[1]; (*s->put)(s->arg,b64chars[v>>10]); (*s->put)(s->arg,b64chars[(v>>4)&63]); (*s->put)(s->arg,b64chars[(v<<2)&63]); (*s->put)(s->arg,'='); break; case 3: v = (s->buf[0] << 16) | (s->buf[1] << 8) | s->buf[2]; (*s->put)(s->arg,b64chars[v>>18]); (*s->put)(s->arg,b64chars[(v>>12)&63]); (*s->put)(s->arg,b64chars[(v>>6)&63]); (*s->put)(s->arg,b64chars[v&63]); break; } s->fill = 0; } void *b64r_init(int (*rfn)(void *), void *arg) { B64RSTATE *s; s = malloc(sizeof(B64RSTATE)); s->get = rfn; s->arg = arg; s->done = 0; s->fill = 0; s->ptr = 0; return(s); } int b64r_get(void *sv) { B64RSTATE *s; unsigned int ibuf; int i; int c; s = sv; if (s->ptr < s->fill) return(s->buf[s->ptr++]); if (s->done) return(s->done); for (i=0;i<4;i++) { c = (*s->get)(s->arg); if (c == B64R_ERR) { s->done = B64R_ERR; return(B64R_ERR); } if (c == B64R_EOF) break; c = b64val(c); if (c < 0) { s->done = B64R_ERR; return(B64R_ERR); } ibuf = (ibuf << 6) + c; } switch (i) { case 0: s->done = B64R_EOF; return(B64R_EOF); break; case 1: s->done = B64R_ERR; return(B64R_ERR); break; case 2: s->buf[0] = (ibuf >> 4) & 0xff; s->fill = 1; s->done = B64R_EOF; break; case 3: s->buf[0] = (ibuf >> 10) & 0xff; s->buf[1] = (ibuf >> 2) & 0xff; s->fill = 2; s->done = B64R_EOF; break; case 4: s->buf[0] = (ibuf >> 16) & 0xff; s->buf[1] = (ibuf >> 8) & 0xff; s->buf[2] = ibuf & 0xff; s->fill = 3; break; } s->ptr = 1; return(s->buf[0]); } void b64r_done(void *sv) { free(sv); } void *b64w_init(void (*wfn)(void *, int), void *arg) { B64WSTATE *s; s = malloc(sizeof(B64WSTATE)); s->put = wfn; s->arg = arg; s->fill = 0; return(s); } void b64w_put(void *sv, int ch) { B64WSTATE *s; s = sv; s->buf[s->fill++] = ch & 0xff; if (s->fill > 2) b64w_flush(s); } void b64w_done(void *sv) { b64w_flush(sv); free(sv); } int b64_stdio_get(void *fv) { int c; FILE *f; f = fv; c = getc(f); switch (c) { case '=': do c = getc(f); while (c == '='); /* fall through */ case ' ': case '\n': ungetc(c,f); return(B64R_EOF); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 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': case '+': case '/': return(c); break; case EOF: return(B64R_EOF); break; default: return(B64R_ERR); break; } } void b64_stdio_put(void *fv, int ch) { putc(ch,(FILE *)fv); /* XXX cast should be unnecessary! */ } int b64_read_blob(FILE *f, void **blobp, int *lenp) { void *v; unsigned char *b; int l; int n; int c; v = b64r_init(b64_stdio_get,f); b = 0; l = 0; n = 0; while (1) { c = b64r_get(v); switch (c) { case B64R_ERR: free(b); return(0); break; case B64R_EOF: *blobp = b; *lenp = l; return(1); break; } if (l >= n) b = realloc(b,n=l+64); b[l++] = c; } } void b64_write_blob(FILE *f, const void *blob, int len) { void *v; int i; v = b64w_init(b64_stdio_put,f); for (i=0;ib64,buf[i]); return(len); } static int b64wwrap_fc(void *wv) { B64WWRAP *w; w = wv; if (w->b64) b64w_done(w->b64); free(w); return(0); } static void b64wwrap_put(void *wv, int ch) { putc(ch,((B64WWRAP *)wv)->f); } FILE *b64w_wrap(FILE *inner) { B64WWRAP *w; FILE *f; w = malloc(sizeof(B64WWRAP)); if (w == 0) return(0); w->b64 = 0; w->f = inner; f = funopen(w,0,&b64wwrap_fw,0,&b64wwrap_fc); if (f == 0) { free(w); return(0); } w->b64 = b64w_init(&b64wwrap_put,w); if (w->b64 == 0) { fclose(f); return(0); } return(f); }