Base64Coder.st
changeset 4753 5b849ae3a1a1
parent 4743 6bdaef8ec48a
child 4754 95158fac7fde
equal deleted inserted replaced
4752:5392065bde5a 4753:5b849ae3a1a1
   177 
   177 
   178 decode:aStringOrStream
   178 decode:aStringOrStream
   179     "because base64 decoding is used heavily in some protocols,
   179     "because base64 decoding is used heavily in some protocols,
   180      a specially tuned version is provided here for the common case of decoding a string"
   180      a specially tuned version is provided here for the common case of decoding a string"
   181 
   181 
       
   182     aStringOrStream isString ifTrue:[
       
   183         ^ self fastDecodeString:aStringOrStream
       
   184     ].    
   182     ^ super decode:aStringOrStream.
   185     ^ super decode:aStringOrStream.
   183 
   186 
   184     "Created: / 30-09-2018 / 14:14:51 / Claus Gittinger"
   187     "Created: / 30-09-2018 / 14:14:51 / Claus Gittinger"
       
   188     "Modified: / 30-09-2018 / 16:58:21 / Claus Gittinger"
   185 !
   189 !
   186 
   190 
   187 fastDecodeString:aString
   191 fastDecodeString:aString
   188     "because base64 decoding is used heavily in some protocols,
   192     "because base64 decoding is used heavily in some protocols,
   189      a specially tuned version is provided here for the common case of decoding a string"
   193      a specially tuned version is provided here for the common case of decoding a string"
   201 
   205 
   202 fastDecodeString:aString asString:asStringBoolean
   206 fastDecodeString:aString asString:asStringBoolean
   203     "because base64 decoding is used heavily in some protocols,
   207     "because base64 decoding is used heavily in some protocols,
   204      a specially tuned version is provided here for the common case of decoding a string"
   208      a specially tuned version is provided here for the common case of decoding a string"
   205 
   209 
   206     |decoding|
   210     |decoding revMapping|
   207     
   211 
       
   212     revMapping := self reverseMapping.
       
   213     revMapping isNil ifTrue:[
       
   214         self initializeMappings.
       
   215         revMapping := self reverseMapping.
       
   216     ].    
   208 %{
   217 %{
   209     char quickBuffer[512];
   218     // overallocate by 3
   210     char *buffer = quickBuffer;
   219 #   define N_QUICKBUFFER 512
   211     int bufferSize = sizeof(quickBuffer);
   220     if (__isString(aString)
   212     int outLen = 0;
   221      && __isByteArray(revMapping)) {
   213     int charBuffer = 0;
   222         unsigned char *_revMapping = __stringVal(revMapping);;
   214     int _bits = 0;
   223         int numInChars = __stringSize(aString);
   215     int numChars = __stringSize(aString);
   224         char *in = __stringVal(aString);
   216     char *in = __stringVal(aString);
   225         unsigned char quickBuffer[N_QUICKBUFFER+3];
   217     int i;
   226         unsigned char *buffer = quickBuffer;
   218     
   227         int bufferSize = N_QUICKBUFFER;
   219     for (i=0; i<numChars; i++) {
   228         int outLen = 0;
   220         char ch = in[i];
   229         int charBuffer = 0;
   221         int bits = -1;
   230         int nBitsOut = 0;
   222         
   231         int i;
   223         if (((unsigned)(ch - 'A')) <= 25) {
   232 
   224             bits = ((unsigned)(ch - 'A')); goto ok;
   233         for (i=0; i<numInChars; i++) {
   225         } else if (((unsigned)(ch - 'a')) <= 25) {
   234             char ch = in[i];
   226             bits = ((unsigned)(ch - 'a')) + 26; goto ok;
   235             int bits = -1;
   227         } else if (((unsigned)(ch - '0')) <= 9) {
   236 
   228             bits = ((unsigned)(ch - '0')) + 34; goto ok;
   237             if (ch <= 127) {
   229         } else if (ch == '+') {
   238                 bits = _revMapping[(ch-1) & 0x7F];
   230             bits = 0x3E; goto ok;
   239             }    
   231         } else if (ch == '/') {
   240 
   232             bits = 0x3F; goto ok;
   241             if ((unsigned)bits <= 0x3F) { 
   233         }
   242                 charBuffer = (charBuffer << 6) | bits;
   234         if (bits >= 0) { 
   243                 nBitsOut += 6;
   235         ok:
   244                 if (nBitsOut == 24) {
   236             charBuffer = (charBuffer << 6) | bits;
   245                     if ((outLen + 3) > bufferSize) {
   237             _bits += 6;
   246                         if (buffer == quickBuffer) {
   238             if (_bits == 24) {
   247                             // overallocate by 3
   239                 if ((outLen + 3) > bufferSize) {
   248                             buffer = (unsigned char *)malloc(bufferSize*2+3);
   240                     if (buffer == quickBuffer) {
   249                             memcpy(buffer, quickBuffer, bufferSize);
   241                         buffer = (char *)malloc(bufferSize*2);
   250                         } else {
   242                         memcpy(buffer, quickBuffer, bufferSize);
   251                             buffer = (unsigned char *)realloc(buffer, bufferSize*2+3);
   243                     } else {
   252                         }
   244                         buffer = (char *)realloc(buffer, bufferSize*2);
   253                         bufferSize = bufferSize * 2;
   245                     }
   254                     }
   246                     bufferSize = bufferSize * 2;
   255                     buffer[outLen] = (charBuffer >> 16) & 0xFF;
   247                 }
   256                     buffer[outLen+1] = (charBuffer >> 8) & 0xFF;
   248                 buffer[outLen] = (charBuffer >> 16) & 0xFF;
   257                     buffer[outLen+2] = (charBuffer) & 0xFF;
   249                 buffer[outLen+1] = (charBuffer >> 8) & 0xFF;
   258                     outLen += 3;
   250                 buffer[outLen+2] = (charBuffer) & 0xFF;
   259                     charBuffer = nBitsOut = 0;
   251                 charBuffer = 0;
       
   252                 outLen += 3;
       
   253                 _bits = 0;
       
   254             }
       
   255         } else {
       
   256             if (ch == '=') {
       
   257                 // end mark
       
   258                 if (_bits == 12) {
       
   259                     // data has been padded to 12, skip 4 bits
       
   260                     charBuffer >>= 4;
       
   261                     _bits -= 4;
       
   262                 } else if (_bits == 18) {
       
   263                     // data has been padded to 18, skip 2 bits
       
   264                     charBuffer >>= 2;
       
   265                     _bits -= 2;
       
   266                 }
   260                 }
   267             } else {
   261             } else {
   268                 // ignore
   262                 if ((unsigned)bits == 0x40) {
   269             }    
   263                     // end mark
       
   264                     // because of overallocation, there is no need to check for buffer-full condition here
       
   265                     if (nBitsOut == 12) {
       
   266                         // data has been padded to 12, skip 4 bits
       
   267                         // one more byte coming
       
   268                         charBuffer >>= 4;
       
   269                         nBitsOut -= 4;
       
   270                         buffer[outLen] = (charBuffer) & 0xFF;
       
   271                         outLen += 1;
       
   272                     } else if (nBitsOut == 18) {
       
   273                         // data has been padded to 18, skip 2 bits
       
   274                         charBuffer >>= 2;
       
   275                         nBitsOut -= 2;
       
   276                         buffer[outLen] = (charBuffer >> 8) & 0xFF;
       
   277                         buffer[outLen+1] = (charBuffer) & 0xFF;
       
   278                         outLen += 2;
       
   279                     }
       
   280                 } else {
       
   281                     // ignore
       
   282                 }    
       
   283             }
   270         }
   284         }
   271     }
   285 
   272     
   286         if (asStringBoolean == true) {
   273     if (_bits != 0) {
   287             decoding = __MKSTRING_L(buffer, outLen);
   274     }
   288         } else {
   275     
   289             decoding = __MKBYTEARRAY(buffer, outLen);
   276     if (asStringBoolean == true) {
   290         }
   277         decoding = __MKSTRING_L(buffer, outLen);
   291         if (buffer != quickBuffer) {
   278     } else {
   292             free(buffer);
   279         decoding = __MKBYTEARRAY(buffer, outLen);
   293         }
   280     }
   294         RETURN(decoding);
   281     if (buffer != quickBuffer) {
       
   282         free(buffer);
       
   283     }    
   295     }    
   284 %}.
   296 %}.
   285     ^ decoding.
   297     decoding := super decode:aString.
   286 
   298     asStringBoolean ifTrue:[
   287     "
   299         ^ decoding asString
   288      (Base64Coder encode:'queen%27s%20gambit') asString => 'cXVlZW4lMjdzJTIwZ2FtYml0'
   300     ].    
       
   301     ^ decoding
       
   302     
       
   303     "
       
   304      (Base64Coder encode:'queen%27s%20gambit') => 'cXVlZW4lMjdzJTIwZ2FtYml0'
   289 
   305 
   290      (Base64Coder decode:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
   306      (Base64Coder decode:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
   291      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
   307      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
   292      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0' asString:true) => 'queen%27s%20gambit'
   308      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0' asString:true) => 'queen%27s%20gambit'
       
   309 
       
   310      (Base64Coder encode:'a') => 'YQ=='
       
   311      (Base64Coder fastDecodeString:'YQ==' asString:true) => 'a'
       
   312 
       
   313      (Base64Coder encode:'aa') => 'YWE='
       
   314      (Base64Coder fastDecodeString:'YWE=' asString:true) => 'aa'
       
   315 
       
   316      |data encoded|
       
   317      data := ByteArray new:100000.
       
   318      encoded := Base64Coder encode:data.
       
   319      Time millisecondsToRun:[
       
   320         10 timesRepeat:[
       
   321             Base64Coder decode:encoded.
       
   322         ]
       
   323      ] 
       
   324      
       
   325      |data encoded|
       
   326      data := ByteArray new:100000.
       
   327      encoded := Base64Coder encode:data.
       
   328      Time millisecondsToRun:[
       
   329         10 timesRepeat:[
       
   330             Base64Coder fastDecodeString:encoded.
       
   331         ]
       
   332      ]
       
   333 
   293     "
   334     "
   294 
   335 
   295     "Created: / 30-09-2018 / 14:35:05 / Claus Gittinger"
   336     "Created: / 30-09-2018 / 14:35:05 / Claus Gittinger"
       
   337     "Modified (comment): / 30-09-2018 / 16:57:52 / Claus Gittinger"
   296 ! !
   338 ! !
   297 
   339 
   298 !Base64Coder methodsFor:'encoding'!
   340 !Base64Coder methodsFor:'encoding'!
   299 
   341 
   300 nextPutByte:aByte
   342 nextPutByte:aByte