'Here's another Base 64 Decode function which I optimized for speed, short of getting really CPU specific. 'Most of my code follows my own personal tastes and conventions, 'but I think this routine is readable and presentable enough to share (being mostly assembly) and offers good speed 'although it has some convolutions where it allowed me to shave off an instruction (see comments) ' 'The function is intended for decoding, and not for verifying the encoded string's strict adherence to the Base64 spec. 'I implemented it in such a way as to be tolerant of any placement of carriage returns. 'The logic works out faster to just accept them where ever they are '(can handle them with the table, rather than having to keep track of where they should appear). 'The returns are there for the sake of transport, and I think there are email clients (or something during 'transport) out there that gets their placement somehow wrong and can cause problems for stricter decoders. 'Anyway as long as it can be decoded unambiguously, I prefer the routine to produce the full and accurate decode 'rather than tell me the encoding is less than perfect. ' 'Any input on further speeding up the main loop is welcome... FUNCTION Base64Decode(B64$,Decoded$) AS LONG 'Bill Walter 11-12-04 Function to decode Base64 Encoded data 'USES TRANSLATION TABLE TO TRANSLATE ASCII TO 6 BIT VALUE, OR SPECIAL HANDLING (128=IGNORE, 255=INVALID, 129=EOD) 'USES ECX REGISTER TO CYCLE THROUGH HANDLING BYTES 0 THRU 3 'Returns 0 if successful, or the (non-zero) position of the error in the encoded string #REGISTER NONE LOCAL RV&, B64_Byte AS BYTE PTR, B64_Beyond AS DWORD, Decoded_Byte AS BYTE PTR, Decoded_End AS DWORD B64_Beyond=LEN(B64$): Decoded$=STRING$((CEIL(B64_Beyond)/4)*3,0) Decoded_Byte=STRPTR(Decoded$): B64_Byte=STRPTR(B64$) B64_Beyond=B64_Beyond+B64_Byte ! PUSHAD ! CLD 'Need direction flag forward for LODSB & STOSB instructions ! MOV ESI,B64_Byte ! LEA EBX, B64_Decode_Trt ! MOV ECX,3 'SO CAN INCREMENT FIRST AND THEN START WITH 0 ! MOV EDI,Decoded_Byte B64_MAINLOOP: ! CMP ESI,B64_Beyond ! JZ B64_DONE ! LODSB ! XLATB ! TEST AL,128 ! JNZ B64_SPECIAL_CHAR 'translatable character ! INC ECX ! AND ECX,3 ! JZ B64_C0 'ON ECX GOTO B64_C0, B64_C1, B64_C2, B64_C3 ! JPE B64_C3 ! CMP ECX,2 ! JZ B64_C2 'REORDERED FOR BRANCHING EFFICIENCY, REORDER C0 THRU C3 FOR READABILITIY AND LOGICAL FLOW B64_C1: 'ASSUMES AH MUST BE ZERO (AL CONTAINS XLATB RESULT) ! SHL AX,4 ! OR EDX,EAX 'now DH holds our first decoded byte ! MOV AL,DH ! STOSB 'store to [EDI] string, leaving 4 bits in DL ! XOR EAX,EAX ! JMP B64_MAINLOOP B64_C0: ! SHL AX,10 ! MOV EDX,EAX 'SAVE TO EDX ! XOR EAX,EAX ! JMP B64_MAINLOOP B64_C2: 'ASSUMES AH MUST BE ZERO (AL CONTAINS XLATB RESULT) ! SHL AX,6 ! OR AH,DL 'NOW AH HOLDS SECOND BYTE ! XCHG AH,AL 'NOW AL " " " ! STOSB 'store to [EDI] string, leaving 2 bits in AH ! JMP B64_MAINLOOP B64_C3: ! OR AL,AH 'now AL holds third byte ! STOSB 'store to [EDI] string ! JMP B64_MAINLOOP B64_SPECIAL_CHAR: ! CMP AL,255 ! JZ B64_ERROR ! CMP AL,129 ! JNZ B64_MAINLOOP 'JUST IGNORE THE CR/LF's 'MUST BE AN EQUAL SIGN ! INC ECX ! AND ECX,3 ! CMP ECX,2 ! JGE B64_DONE 'IF ECX =2 OR 3, OK TO BE DONE. FULL BYTES ALREADY SAVED, ASSUME '=' MEANS MUST BE DONE 'ELSE EQUAL SIGN NOT VALID FOR POSITIONS 0 AND 1 B64_ERROR: 'RETURN LOCATION IN ENCODED DATA THAT CAUSED ERROR ! MOV EAX,ESI ! SUB EAX,b64_Byte ! MOV RV&,EAX ! JMP B64_DONE B64_Decode_Trt: ! DB 255,255,255,255,255,255,255,255,255,255,128,255,255,128,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 ! DB 255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,129,255,255,255 ! DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,255 ! DB 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,255 ! DB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 ! DB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 ! DB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 ! DB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 B64_DONE: ! MOV Decoded_end,EDI ! POPAD Decoded$=LEFT$(Decoded$,Decoded_End - Decoded_Byte) FUNCTION=RV& END FUNCTION