Base64Coder.st
changeset 4753 5b849ae3a1a1
parent 4743 6bdaef8ec48a
child 4754 95158fac7fde
--- a/Base64Coder.st	Sun Sep 30 16:58:56 2018 +0200
+++ b/Base64Coder.st	Sun Sep 30 16:59:01 2018 +0200
@@ -179,9 +179,13 @@
     "because base64 decoding is used heavily in some protocols,
      a specially tuned version is provided here for the common case of decoding a string"
 
+    aStringOrStream isString ifTrue:[
+        ^ self fastDecodeString:aStringOrStream
+    ].    
     ^ super decode:aStringOrStream.
 
     "Created: / 30-09-2018 / 14:14:51 / Claus Gittinger"
+    "Modified: / 30-09-2018 / 16:58:21 / Claus Gittinger"
 !
 
 fastDecodeString:aString
@@ -203,96 +207,134 @@
     "because base64 decoding is used heavily in some protocols,
      a specially tuned version is provided here for the common case of decoding a string"
 
-    |decoding|
-    
+    |decoding revMapping|
+
+    revMapping := self reverseMapping.
+    revMapping isNil ifTrue:[
+        self initializeMappings.
+        revMapping := self reverseMapping.
+    ].    
 %{
-    char quickBuffer[512];
-    char *buffer = quickBuffer;
-    int bufferSize = sizeof(quickBuffer);
-    int outLen = 0;
-    int charBuffer = 0;
-    int _bits = 0;
-    int numChars = __stringSize(aString);
-    char *in = __stringVal(aString);
-    int i;
-    
-    for (i=0; i<numChars; i++) {
-        char ch = in[i];
-        int bits = -1;
-        
-        if (((unsigned)(ch - 'A')) <= 25) {
-            bits = ((unsigned)(ch - 'A')); goto ok;
-        } else if (((unsigned)(ch - 'a')) <= 25) {
-            bits = ((unsigned)(ch - 'a')) + 26; goto ok;
-        } else if (((unsigned)(ch - '0')) <= 9) {
-            bits = ((unsigned)(ch - '0')) + 34; goto ok;
-        } else if (ch == '+') {
-            bits = 0x3E; goto ok;
-        } else if (ch == '/') {
-            bits = 0x3F; goto ok;
-        }
-        if (bits >= 0) { 
-        ok:
-            charBuffer = (charBuffer << 6) | bits;
-            _bits += 6;
-            if (_bits == 24) {
-                if ((outLen + 3) > bufferSize) {
-                    if (buffer == quickBuffer) {
-                        buffer = (char *)malloc(bufferSize*2);
-                        memcpy(buffer, quickBuffer, bufferSize);
-                    } else {
-                        buffer = (char *)realloc(buffer, bufferSize*2);
+    // overallocate by 3
+#   define N_QUICKBUFFER 512
+    if (__isString(aString)
+     && __isByteArray(revMapping)) {
+        unsigned char *_revMapping = __stringVal(revMapping);;
+        int numInChars = __stringSize(aString);
+        char *in = __stringVal(aString);
+        unsigned char quickBuffer[N_QUICKBUFFER+3];
+        unsigned char *buffer = quickBuffer;
+        int bufferSize = N_QUICKBUFFER;
+        int outLen = 0;
+        int charBuffer = 0;
+        int nBitsOut = 0;
+        int i;
+
+        for (i=0; i<numInChars; i++) {
+            char ch = in[i];
+            int bits = -1;
+
+            if (ch <= 127) {
+                bits = _revMapping[(ch-1) & 0x7F];
+            }    
+
+            if ((unsigned)bits <= 0x3F) { 
+                charBuffer = (charBuffer << 6) | bits;
+                nBitsOut += 6;
+                if (nBitsOut == 24) {
+                    if ((outLen + 3) > bufferSize) {
+                        if (buffer == quickBuffer) {
+                            // overallocate by 3
+                            buffer = (unsigned char *)malloc(bufferSize*2+3);
+                            memcpy(buffer, quickBuffer, bufferSize);
+                        } else {
+                            buffer = (unsigned char *)realloc(buffer, bufferSize*2+3);
+                        }
+                        bufferSize = bufferSize * 2;
                     }
-                    bufferSize = bufferSize * 2;
-                }
-                buffer[outLen] = (charBuffer >> 16) & 0xFF;
-                buffer[outLen+1] = (charBuffer >> 8) & 0xFF;
-                buffer[outLen+2] = (charBuffer) & 0xFF;
-                charBuffer = 0;
-                outLen += 3;
-                _bits = 0;
-            }
-        } else {
-            if (ch == '=') {
-                // end mark
-                if (_bits == 12) {
-                    // data has been padded to 12, skip 4 bits
-                    charBuffer >>= 4;
-                    _bits -= 4;
-                } else if (_bits == 18) {
-                    // data has been padded to 18, skip 2 bits
-                    charBuffer >>= 2;
-                    _bits -= 2;
+                    buffer[outLen] = (charBuffer >> 16) & 0xFF;
+                    buffer[outLen+1] = (charBuffer >> 8) & 0xFF;
+                    buffer[outLen+2] = (charBuffer) & 0xFF;
+                    outLen += 3;
+                    charBuffer = nBitsOut = 0;
                 }
             } else {
-                // ignore
-            }    
+                if ((unsigned)bits == 0x40) {
+                    // end mark
+                    // because of overallocation, there is no need to check for buffer-full condition here
+                    if (nBitsOut == 12) {
+                        // data has been padded to 12, skip 4 bits
+                        // one more byte coming
+                        charBuffer >>= 4;
+                        nBitsOut -= 4;
+                        buffer[outLen] = (charBuffer) & 0xFF;
+                        outLen += 1;
+                    } else if (nBitsOut == 18) {
+                        // data has been padded to 18, skip 2 bits
+                        charBuffer >>= 2;
+                        nBitsOut -= 2;
+                        buffer[outLen] = (charBuffer >> 8) & 0xFF;
+                        buffer[outLen+1] = (charBuffer) & 0xFF;
+                        outLen += 2;
+                    }
+                } else {
+                    // ignore
+                }    
+            }
         }
-    }
-    
-    if (_bits != 0) {
-    }
-    
-    if (asStringBoolean == true) {
-        decoding = __MKSTRING_L(buffer, outLen);
-    } else {
-        decoding = __MKBYTEARRAY(buffer, outLen);
-    }
-    if (buffer != quickBuffer) {
-        free(buffer);
+
+        if (asStringBoolean == true) {
+            decoding = __MKSTRING_L(buffer, outLen);
+        } else {
+            decoding = __MKBYTEARRAY(buffer, outLen);
+        }
+        if (buffer != quickBuffer) {
+            free(buffer);
+        }
+        RETURN(decoding);
     }    
 %}.
-    ^ decoding.
-
+    decoding := super decode:aString.
+    asStringBoolean ifTrue:[
+        ^ decoding asString
+    ].    
+    ^ decoding
+    
     "
-     (Base64Coder encode:'queen%27s%20gambit') asString => 'cXVlZW4lMjdzJTIwZ2FtYml0'
+     (Base64Coder encode:'queen%27s%20gambit') => 'cXVlZW4lMjdzJTIwZ2FtYml0'
 
      (Base64Coder decode:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0') asString => 'queen%27s%20gambit'
      (Base64Coder fastDecodeString:'cXVlZW4lMjdzJTIwZ2FtYml0' asString:true) => 'queen%27s%20gambit'
+
+     (Base64Coder encode:'a') => 'YQ=='
+     (Base64Coder fastDecodeString:'YQ==' asString:true) => 'a'
+
+     (Base64Coder encode:'aa') => 'YWE='
+     (Base64Coder fastDecodeString:'YWE=' asString:true) => 'aa'
+
+     |data encoded|
+     data := ByteArray new:100000.
+     encoded := Base64Coder encode:data.
+     Time millisecondsToRun:[
+        10 timesRepeat:[
+            Base64Coder decode:encoded.
+        ]
+     ] 
+     
+     |data encoded|
+     data := ByteArray new:100000.
+     encoded := Base64Coder encode:data.
+     Time millisecondsToRun:[
+        10 timesRepeat:[
+            Base64Coder fastDecodeString:encoded.
+        ]
+     ]
+
     "
 
     "Created: / 30-09-2018 / 14:35:05 / Claus Gittinger"
+    "Modified (comment): / 30-09-2018 / 16:57:52 / Claus Gittinger"
 ! !
 
 !Base64Coder methodsFor:'encoding'!