vtf-logo

EncodeToBase64.h

00001 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00002 //                                                encode to base 64
00003 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00004 //                                           by santiago v lombeyda
00005 //                                            cacr-caltech (c) 2004
00006 //
00007 //  base 64 encoders are very simple. all they do
00008 //  is take 6 bits at a time and translate them into
00009 //  an 8 bit char corresponding to letters A-Z a-z + /.
00010 //  total 64 bit ascii characters. the only issue is
00011 //  when the number of bits is not a multiple of 6. so,
00012 //  you simple do it 3 binary characters at a time into
00013 //  four chars, and if you do not have enough, you simply
00014 //  stuff 8 or 16 0 bits (1 or 2 chars) to add up to the
00015 //  wanted 24 bits that will become 32 bits (4 chars).
00016 //
00017 //  this implementation, takes advantage of the first and
00018 //  last bits to quickly encode them using one of 2 lookup
00019 //  char conversion tables. the middle two 6 bits are treated
00020 //  the usual way, converting them into 2 zero bits and then
00021 //  the lookup 6.
00022 //
00023 //  (is a memory lookup faster than 3 bit operations? maybe not)
00024 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00025 
00026 static const char* TABLE_BYTE_3_B64 ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ ";
00027 
00028 static const char* TABLE_BYTE_0_B64 ="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZaaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz0000111122223333444455556666777788889999++++//// ";
00029 
00030 # define encodeCHARToBase64(c) (((c)<=25)?(c+'A'):(\
00031                                 ((c)<=51)?(c+'a'-26):(\
00032                                 ((c)<=61)?(c+'0'-52):(\
00033                                 ((c)==61)?'+':'/'))))
00034 
00035 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00036 //                                                     isBigEndian
00037 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00038 bool isBigEndian() {
00039 # define IS_BIG_ENDIAN    2
00040 # define IS_LITTLE_ENDIAN 1
00041   static int checkedEndianess=0;
00042   if (checkedEndianess==0) {
00043     const int i=1;
00044     char *c=(char *)&i;
00045     if (c[sizeof(int)-1]==0) checkedEndianess=IS_LITTLE_ENDIAN;
00046     else checkedEndianess=IS_BIG_ENDIAN;
00047   }
00048   return (checkedEndianess==IS_BIG_ENDIAN);
00049 }
00050 
00051 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00052 //                                                  isLittleEndian
00053 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00054 bool isLittleEndian() {
00055   return !isBigEndian();
00056 }
00057 
00058 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00059 //                                                   encodeToBase64
00060 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00061 //void encodeToBase64(unsigned char *in3Bytes, unsigned char *out4Bytes) {
00062 //   if (in3Bytes==NULL || out4Bytes==NULL) return;
00063 //   out4Bytes[0]=TABLE_BYTE_0_B64[in3Bytes[0]];
00064 //   out4Bytes[1]=TABLE_BYTE_3_B64[((in3Bytes[0]&0x03)<<4)+
00065 //                                 ((in3Bytes[1]&0xf0)>>4)];
00066 //   out4Bytes[2]=TABLE_BYTE_3_B64[((in3Bytes[1]&0x0f)<<2)+
00067 //                                 ((in3Bytes[2]&0xc0)>>6)];
00068 //   out4Bytes[3]=TABLE_BYTE_3_B64[in3Bytes[2]];
00069 //}
00070 
00071 inline void encodeToBase64(unsigned char *in3Bytes, unsigned char *out4Bytes) {
00072    static int i;
00073    if (in3Bytes==NULL || out4Bytes==NULL) return;
00074    *(out4Bytes++)=TABLE_BYTE_0_B64[*in3Bytes];
00075      i= ( *(in3Bytes++)&0x03)<<4;
00076      i|=((*(in3Bytes)&0xf0)>>4);
00077    *(out4Bytes++)=TABLE_BYTE_3_B64[i];
00078      i= ( *(in3Bytes++)&0x0f)<<2;
00079      i|=((*(in3Bytes)&0xc0)>>6);
00080    *(out4Bytes++)=TABLE_BYTE_3_B64[i];
00081    *(out4Bytes++)=TABLE_BYTE_3_B64[*in3Bytes];
00082 }
00083 
00084 
00085 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00086 //                                                   encodeToBase64
00087 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00088 inline int encodeToBase64(unsigned int n, unsigned char *inBytes, unsigned char *outBytes) {
00089   static unsigned int m;
00090   static unsigned int i, j;
00091   if (inBytes==NULL || outBytes==NULL || n<=0) return 0;
00092   m=n-(n%3);
00093   for ( i=j=0; i<m; i+=3, j+=4)  encodeToBase64(inBytes+i,outBytes+j);
00094   if (m!=n) {
00095    char unsigned lastchars[3] = {0,0,0};
00096    lastchars[0]=inBytes[i];
00097    if ((n-m)==2) lastchars[1]=inBytes[i+1];
00098    encodeToBase64(lastchars,outBytes+j);
00099    outBytes[j+3]='=';
00100    if ((n-m)==1) outBytes[j+2]='=';
00101    j+=4;
00102   }
00103   return j;
00104 }
00105 
00106 
00107 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00108 //                                                runEncodeToBase64
00109 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00110 inline int runEncodeToBase64(int n, unsigned char *inBytes, unsigned char *outBytes, bool flushBuffer=false) {
00111   static int cachedChars=0;
00112   static unsigned char charCache[3];
00113   int l=0;
00114 
00115   // there are cached leftovers
00116   if (cachedChars>0) {
00117     // fill more
00118     if (n>0) { charCache[cachedChars++]=*inBytes; inBytes++; n--; }
00119     if (cachedChars<3 && n>0) { charCache[cachedChars++]=*inBytes; inBytes++; n--; }
00120     // if filled
00121     if (cachedChars==3 || flushBuffer) {
00122      l=encodeToBase64(cachedChars,charCache,outBytes);
00123      outBytes+=l;
00124      cachedChars=0;
00125     }
00126   }
00127   if (n==0) return l;
00128 
00129   int m=n-n%3;
00130   if (flushBuffer || n==m) {
00131      l+=encodeToBase64(n,inBytes,outBytes);
00132      return l;
00133   }
00134   // cache left overs
00135   charCache[cachedChars++]=inBytes[m];
00136   if (m+1<n) charCache[cachedChars++]=inBytes[m+1];
00137   l+=encodeToBase64(m,inBytes,outBytes);
00138    return l;
00139 }
00140 
00141 
00142 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00143 //                                                   flip N bytes
00144 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00145 #define flip2Bytes(str) {char c=str[1];str[1]=str[0];str[0]=c;}
00146 #define flip4Bytes(str) {char c=str[3];str[3]=str[0];str[0]=c; c=str[1];str[1]=str[2];str[2]=c;}
00147 #define flip8Bytes(str) {char c=str[7];str[7]=str[0];str[0]=c; \
00148                               c=str[6];str[6]=str[1];str[1]=c; \
00149                               c=str[5];str[5]=str[2];str[2]=c; \
00150                               c=str[4];str[4]=str[3];str[3]=c; }
00151 #define flipNBytes(n,str) {for (int _flip_i=n/2;_flip_i<n;_flip_i++) \
00152                              {char c=str[_flip_i];str[_flip_i]=str[n-1-_flip_i];str[n-1-_flip_i]=c;}};
00153 
00154 void flipBytes(int size, int n, unsigned char *data) {
00155   if (size==2)      for (int i=0; i<n; i++, data+=2)    {flip2Bytes(data);}
00156   else if (size==4) for (int i=0; i<n; i++, data+=4)    {flip4Bytes(data);}
00157   else if (size==8) for (int i=0; i<n; i++, data+=8)    {flip8Bytes(data);}
00158   else              for (int i=0; i<n; i++, data+=size) {flipNBytes(size,data);}
00159 }
00160 
00161 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00162 //                                              buffered f write
00163 // size_t fwrite(const  void  *ptr,  size_t  size,  size_t  nmemb,  FILE *stream);
00164 // size_t bufferedfwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream, bool flush=false);
00165 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00166 # define BUFFERED_FWRITE_BUFFER_SIZE 4194304
00167 
00168 inline size_t bufferedfwrite(const void *ptr, size_t size, size_t nmemb, std::ostream& stream, bool flush=false) {
00169 
00170   static unsigned long idx=0;
00171   static unsigned long ntowrite;
00172   static unsigned long ntocopy;
00173   static unsigned char * buffer=NULL;
00174 
00175   if (buffer==NULL) {
00176     buffer=(unsigned char *)malloc(BUFFERED_FWRITE_BUFFER_SIZE);
00177     if (buffer==NULL) {
00178       std::cerr<<"Could not allocate binary write buffer of size " << BUFFERED_FWRITE_BUFFER_SIZE << std::endl;
00179       exit(1);
00180     }
00181   }
00182 
00183   if (size==0 || nmemb==0) return 0;
00184 
00185   ntowrite=size*nmemb;
00186 
00187   if (idx==0 && flush)
00188     //return fwrite(ptr,size,nmemb,stream);
00189     return ((stream.write((char *)ptr,ntowrite)).fail()?0:ntowrite);
00190 
00191 
00192   if (ntowrite>=BUFFERED_FWRITE_BUFFER_SIZE*2) {
00193     //fwrite(buffer,1,idx,stream);
00194     stream.write((char *)buffer,idx);
00195     //fwrite(ptr,1,ntowrite,stream);
00196     stream.write((char *)ptr,ntowrite);
00197     ntowrite+=idx;
00198     idx=0;
00199     return ntowrite;
00200   }
00201 
00202   if (idx+ntowrite>BUFFERED_FWRITE_BUFFER_SIZE)
00203     ntocopy=BUFFERED_FWRITE_BUFFER_SIZE-idx;
00204   else
00205     ntocopy=ntowrite;
00206 
00207   memcpy(buffer+idx,ptr,ntocopy);
00208   idx+=ntocopy;
00209 
00210   if (flush || idx>=BUFFERED_FWRITE_BUFFER_SIZE) {
00211     //assert(idx<=BUFFERED_FWRITE_BUFFER_SIZE);
00212     //fwrite(buffer,1,idx,stream);
00213     stream.write((char *)buffer,idx);
00214     // if there was more data than buffer space
00215     if (ntocopy<ntowrite) {
00216       idx=0;
00217       if (flush)
00218          //return fwrite((unsigned char*)(ptr)+ntocopy,1,ntowrite-ntocopy,stream)+BUFFERED_FWRITE_BUFFER_SIZE;
00219          return ((stream.write((char *)(unsigned char*)(ptr)+ntocopy,ntowrite-ntocopy)).fail()?
00220                    0:ntowrite-ntocopy+BUFFERED_FWRITE_BUFFER_SIZE);
00221       idx=ntowrite-ntocopy;
00222       memcpy(buffer,(unsigned char*)(ptr)+ntocopy,idx);
00223       return BUFFERED_FWRITE_BUFFER_SIZE;
00224     }
00225     ntowrite=idx;
00226     idx=0;
00227     return ntowrite;
00228   }
00229   return 0;
00230 }
00231 
00232 
00233 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00234 //                                                                                           ENCODE TO BASE 64 AND WRITE
00235 // this function is supposed to be called with nice, LONG binary buffers, thus using just
00236 // one big loop.
00237 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00238 inline bool encodeToBase64AndWrite(unsigned char *ptr, long n, std::ostream& stream, bool flush=false) {
00239   static unsigned char * buffer=NULL;
00240   static unsigned int    nbuffered=0;
00241   static unsigned char * bufferptr=NULL;
00242   static unsigned char * bufferend=NULL;
00243 
00244   static unsigned char   charsbuffered[4];
00245   static unsigned int    ncharsbuffered=0;
00246 
00247   static unsigned int    v;
00248 
00249   //if (DEBUG) std::cerr<<"writing " << n <<" encoded chars " << std::endl;
00250 
00251   if (n==0 && ncharsbuffered==0 && nbuffered==0) return true;
00252 
00253   if (buffer==NULL) {
00254     buffer=(unsigned char *)malloc(BUFFERED_FWRITE_BUFFER_SIZE+4);
00255     if (buffer==NULL) {
00256       std::cerr<<"Could not allocate binary write buffer of size " << BUFFERED_FWRITE_BUFFER_SIZE << std::endl;
00257       exit(1);
00258     }
00259     bufferptr=buffer;
00260     bufferend=buffer+BUFFERED_FWRITE_BUFFER_SIZE;
00261   }
00262 
00263   // enough charsbuffered plus new to go into big output buffer
00264   if (ncharsbuffered>0 && (n+ncharsbuffered)>2) {
00265     charsbuffered[ncharsbuffered++]=*(ptr++);
00266      n--;
00267      if (ncharsbuffered<3) {
00268        charsbuffered[ncharsbuffered++]=*(ptr++);
00269        n--;
00270      }
00271      encodeToBase64(charsbuffered, bufferptr);
00272      nbuffered+=4;
00273      bufferptr+=4;
00274      ncharsbuffered=0;
00275   }
00276   while (n>2) {
00277     while (n>2 && bufferptr<bufferend) {
00278      *(bufferptr++)=TABLE_BYTE_0_B64[*ptr];
00279        v= ( *(ptr++)&0x03)<<4;
00280        v|=((*(ptr)&0xf0)>>4);
00281      *(bufferptr++)=TABLE_BYTE_3_B64[v];
00282        v= ( *(ptr++)&0x0f)<<2;
00283        v|=((*(ptr)&0xc0)>>6);
00284      *(bufferptr++)=TABLE_BYTE_3_B64[v];
00285      *(bufferptr++)=TABLE_BYTE_3_B64[*(ptr++)];
00286      nbuffered+=4;
00287      n-=3;
00288     }
00289     if (n>0 && n<3) {
00290       //asssert(ncharsbuffered==0);
00291       if (flush) {
00292         nbuffered+=encodeToBase64(n, ptr, bufferptr);
00293         ptr+=n;
00294         n=0;
00295       } else {
00296         charsbuffered[ncharsbuffered++]=*(ptr++);
00297         n--;
00298         if (n>0) {
00299           charsbuffered[ncharsbuffered++]=*(ptr++);
00300           n--;
00301         }
00302       }
00303       //assert(n==0);
00304     }
00305     if (bufferptr>=bufferend || flush) {
00306       if (stream.write((const char *)buffer,nbuffered).fail()) return false;
00307       bufferptr=buffer;
00308       nbuffered=0;
00309     }
00310   }
00311   if (n>0) {
00312     charsbuffered[ncharsbuffered++]=*(ptr++);
00313     n--;
00314     if (n>0) {
00315      charsbuffered[ncharsbuffered++]=*(ptr++);
00316      n--;
00317     }
00318   }
00319 
00320   //assert(n==0)
00321 
00322   if (ncharsbuffered>0 && flush) {
00323     nbuffered+=encodeToBase64(ncharsbuffered, charsbuffered, bufferptr);
00324     ncharsbuffered=0;
00325   }
00326   if (bufferptr>=bufferend || flush) {
00327     if (stream.write((const char *)buffer,nbuffered).fail()) return false;
00328     bufferptr=buffer;
00329     nbuffered=0;
00330   }
00331   // if (DEBUG) std::cerr<<"++ wrote " << nbuffered <<"/" << n << "/" << ncharsbuffered << " encoded chars " << std::endl;
00332 
00333   return true;
00334 }

Generated on Fri Aug 24 13:00:31 2007 for AMROC's HDF Tools - by  doxygen 1.4.7