--- 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'!