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 |