#include #include #include #include "debug.h" namespace xstream { namespace base64 { static const char dictionary[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const int eof = std::streambuf::traits_type::eof(); ostreambuf::ostreambuf(std::streambuf* sb, const unsigned int w, const char c):_sb(sb),delim(c),delim_w(w),col(0) { LOG("base64::ostreambuf (streambuf*)"); reset(); } void ostreambuf::reset() { LOG("base64::ostreambuf::reset"); setp(buf,buf+sizeof(buf)/sizeof(char)); } //no flush of base64 data, just flushes the streambuf it writes to int ostreambuf::sync() { LOG("base64::ostreambuf::sync"); return _sb->pubsync(); } static inline void encode(const char* in, char* out) { LOG("base64::encode"); static const unsigned int hi6 = ((1<<6)-1)<<2; static const unsigned int lo2 = (1<<2)-1; static const unsigned int hi4 = ((1<<4)-1)<<4; static const unsigned int lo4 = (1<<4)-1; static const unsigned int hi2 = ((1<<2)-1)<<6; static const unsigned int lo6 = (1<<6)-1; out[0] = dictionary[ (hi6&(in[0]))>>2 ]; out[1] = dictionary[ (lo2&(in[0]))<<4 | (hi4&(in[1]))>>4 ]; out[2] = dictionary[ (lo4&(in[1]))<<2 | (hi2&(in[2]))>>6]; out[3] = dictionary[ lo6&(in[2]) ]; } int ostreambuf::write(const char* buf, const size_t len){ unsigned int rcol = delim_w-col; int ret = 0; //XXX all these sputn calls need to be checked if(delim_w>0 && rcol<=len) { LOG("\t"<sputn(buf,rcol); ret = _sb->sputc(delim); ret = _sb->sputn(buf+rcol,len-rcol); col=len-rcol;; LOG("\tcol = "<sputn(buf,len); col+=len; } reset(); return ret; } int ostreambuf::overflow(const int c) { LOG("base64::ostreambuf::overflow ("<(c); pbump(1); return ret; return -1; } ostreambuf::~ostreambuf() { LOG("base64::~ostreambuf"); int av = available(); if(3==av) { //no need to do anything } else { char enc[4]; for(int i=0; ipubsync(); } //should search in constant time static inline char index(const char c) { static const int window = 'Z'- 'A' + 1 ; //if c is not in dict throw exception //could be a lot cleaner if no debugging was needed int d = c-'A'; int ret=-1; if(d>=0 && d=0 && d=0 && d<10) { ret=d+2*window; } else { if('+'==c) { ret=62; } else { if('/'==c) { ret=63; } } } } } if(-1==ret) { LOG("base64::index ("<>4; out[0]=c; c= (_in[1]&lo4)<<4; c|= (_in[2]&hi4)>>2; out[1]=c; c= (_in[2]&lo2)<<6; c|= _in[3]; out[2]=c; } istreambuf::istreambuf(std::streambuf* sb, const unsigned int d_w, const char d):_sb(sb),end(false),delim(d),delim_w(d_w),col(0) { LOG("base64::istreambuf (streambuf*)"); setg(buf,buf,buf); } int istreambuf::underflow() { LOG("base64::istreambuf::underflow"); if(end) { LOG("\tattempt to read from an ended stream"); return eof; } else { char enc[4+1]; int av = (delim_w-col); if(delim_w>0 && av<=4) { LOG("\texpecting delimiter at "<sgetn(enc,5); LOG("\tenc="<sgetn(enc,4); col+=4; if(4!=ret) { //XXX maybe I should throw an exception end=true; return eof; } } int len=3; if('='==enc[3]){ enc[3]='A'; //guard if('='==enc[2]){ len=1; enc[2]='A'; //guard }else{ len=2; } } if(3!=len){ end=true; } decode(enc,buf); setg(buf,buf,buf+len); return 0; } } istreambuf::~istreambuf() { LOG("base64::~istreambuf"); } }//namespace base64 }//namespace xstream