;************************************************************************************* ; MODULE: DECODE64.ASM DATE: JANUARY 27,1997 ; AUTHOR: SEAN M. KESSLER ; TARGET: 32 BIT FLAT MODEL ; FUNCTION : BASE64 DECODER ;************************************************************************************* .386 .MODEL FLAT INCLUDE devioctl.inc INCLUDE string.inc INCLUDE openfile.inc .DATA inputFile FileInfo <> outputFile FileInfo <> lineData DB 400h DUP(0) szDefaultOutputPathFileName DB 'IMAGE.JPG',00h szOutputPathFileName DB 0FFh DUP(0) szFileNameLiteral DB 'filename=',00h szOutBytes DB 04h DUP(0) szInputPathFileName DD ? szBase64ID DB '/9j/',00h szExtension DB '.JPG',00H szBase64Vector DB 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',00h szBase64End DB '---',00h num DD ? lineLength DD ? itemIndex DD ? itemCount DD ? numIndex DD ? valueItem DD ? .CODE _decodeBase64 proc near ; WORD decodeBase64(const char *szPathFileName,char *szPathDecodeFileName) push ebp ; save stack frame mov ebp,esp ; create new frame push esi ; save source index register push edi ; save destination index register mov itemCount,0000h ; initialize decoded counter to zero push dword ptr[ebp+8] ; save pathFileName pop szInputPathFileName ; restore into inputPathFileName cmp szInputPathFileName,0000h ; is the file na null je @@error ; if so then we've got an error FOPEN szInputPathFileName,inputFile,GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL cmp inputFile.FileInfo@@mhFileHandle,INVALID_HANDLE ; do we have a valid handle ? je @@error ; if the handle is invalid then we've got an error call _outputName ; get output file name STRCPY [ebp+0Ch],offset szOutputPathFileName ; copy szOutputPathFileName to supplied buffer @@search: ; search sync address FGETS inputFile,lineData ; get input line cmp eax,0000h ; did we read anything je @@end ; if not we're done STRSTR lineData,szFileNameLiteral ; look for "filename=" literal cmp eax,0000h ; did we find it jne @@nameFile ; if so then extract the filename STRNCMP szBase64ID,lineData ; compare line to base64 identifier cmp eax,0001h ; if we've got it then we start decoding je @@beginDecode ; jump to decode handler jmp @@search ; keep going @@nameFile: ; nameFile sync address push eax ; save address of filename literal push offset szOutputPathFileName ; save address of filename buffer call _nameFile ; extract the file name add esp,08h ; reset stack frame jmp @@search ; keep going @@beginDecode: ; begin decode sync address FOPEN offset szOutputPathFileName,outputFile,GENERIC_WRITE,FILE_SHARE_READ,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL @@continueDecode: ; continue decode sync address STRLEN lineData ; get length of lineData dec eax ; decrement line length mov lineLength,eax ; move line length into lineLength mov itemIndex,0000h ; set itemIndex to zero @@itemLoop: ; itemLoop sync address mov valueItem,0000h ; set valueItem to zero mov esi,offset lineData ; move ptr lineData to esi register add esi,itemIndex ; add itemIndex to address cmp byte ptr[esi+02h],'=' ; is pChar[2] equal to '='? je @@assignOne ; if so then num=1 cmp byte ptr[esi+03h],'=' ; else if pChar[3]='=' je @@assignTwo ; then num=2 mov num,0003h ; otherwise num=3 jmp @@assignContinue ; continue @@assignOne: ; assignment sync address mov num,0001h ; assign 1 to num jmp @@assignContinue ; continue @@assignTwo: ; assignment sync address mov num,0002h ; assign two to num jmp @@assignContinue ; continue @@assignContinue: ; end assignment sync address mov numIndex,0000h ; set numIndex to zero @@numLoop: ; numIndex loop sync address xor eax,eax ; clear out eax mov edi,numIndex ; move numIndex into destination index mov al,byte ptr[esi+edi] ; get the byte at pChar[numIndex] STRCHR szBase64Vector,eax ; ::strchar(szBase64Vector,pChar[numIndex]) cmp eax,0000h ; did we find the token je @@end ; if not then we've got an error mov edi,eax ; move address of found token to edi (pTok) sub edi,offset szBase64Vector ; perform (pTok-szBase64Vector) result to edi mov eax,0003h ; move 3 into eax sub eax,numIndex ; perform (3-numIndex) result to eax mov edx,0006h ; move 6 into edx imul eax,edx ; perform (3-numIndex)*6 result to eax mov cl,al ; move shift value into cl register shl edi,cl ; perform (pTok-smszVec)<<((3-numIndex)*6) result to edi add valueItem,edi ; valueItem+=(pTok-smszVec)<<((3-numIndex)*6) inc numIndex ; increment numIndex mov eax,numIndex ; move numIndex into eax register cmp eax,num ; compare numIndex to num jle @@numLoop ; loop through <= operation mov numIndex,0002h ; set numIndex to 2 @@nextNumLoop: ; next numLoop sync address mov esi,offset szOutBytes ; move szOutBytes address into esi mov edi,numIndex ; move numIndex into edi mov eax,valueItem ; move valueItem into eax register and eax,000000FFh ; apply bit mask mov byte ptr[esi+edi],al ; set byte in szOutBytes shr valueItem,08h ; shift valueItem right 8 bytes dec numIndex ; decrement numIndex cmp numIndex,0000h ; compare numIndex to zero jge @@nextNumLoop ; if >=0 keep going mov esi,offset szOutBytes ; move szOutBytes to esi xor edi,edi ; clear edi @@writeLoop: ; writeLoop sync address FWRITE outputFile,byte ptr[esi+edi] ; write out the byte inc edi ; increment edi cmp edi,num ; compare edi to num jl @@writeLoop ; if it's less then keep going add itemIndex,0004h ; increment itemIndex by four mov eax,itemIndex ; move itemIndex to eax cmp eax,lineLength ; compare itemIndex to lineLength jl @@itemLoop ; if it's less that keep going FGETS inputFile,lineData ; get another line cmp eax,0000h ; did we get a line? je @@end ; if not then we're done STRNCMP lineData,szBase64End ; look for trailer signature cmp eax,0001h ; if we found it then another image may follow je @@prepNewImage ; flush and close current output file jmp @@continueDecode ; otherwise keep going @@prepNewImage: ; prepNewImage sync address inc itemCount ; increment decoded counter FFLUSH outputFile ; flush output file CLOSEHANDLE outputFile.FileInfo@@mhFileHandle ; close output file mov outputFile.FileInfo@@mhFileHandle,INVALID_HANDLE ; invalidate the handle jmp @@search ; try to decode another image @@end: ; end sync address cmp outputFile.FileInfo@@mhFileHandle,INVALID_HANDLE ; is this a valid handle je @@closePrimary ; is handle is invalid, just close the input file FFLUSH outputFile ; flush the output file CLOSEHANDLE outputFile.FileInfo@@mhFileHandle ; close output file @@closePrimary: ; close primary sync address CLOSEHANDLE inputFile.FileInfo@@mhFileHandle ; close input file @@error: ; error sync address mov eax,itemCount ; move decoded count to eax register pop edi ; restore destination index register pop esi ; restore source index register pop ebp ; restore prior stack frame retn ; return near to caller _decodeBase64 endp _nameFile proc near push ebp ; save stack frame mov ebp,esp ; create new frame push esi ; save source index register push edi ; save destination index register mov edi,[ebp+8] ; move dest string to destination index register mov esi,[ebp+0Ch] ; move source string to source index register @@NAMEFILEquoteLoop: ; first quote loop control mov al,byte ptr[esi] ; move byte into al cmp al,00h ; is it null? je @@NAMEFILEerror ; if it's null then we've got an error cmp al,'"' ; is it the first quote ? je @@NAMEFILEreadFile ; if so then get the filename inc esi ; increment along esi jmp @@NAMEFILEquoteLoop ; keep going @@NAMEFILEreadFile: ; read file name sync address inc esi ; skip past the first quote mov al,byte ptr[esi] ; read from file name cmp al,'"' ; is the byte the closing quote? je @@NAMEFILEreadEnd ; if so then we're done cmp al,00h ; is the byte a null byte? je @@NAMEFILEreadEnd ; if so then we're done mov byte ptr[edi],al ; store the byte in destination inc edi ; increment along destination jmp @@NAMEFILEreadFile ; keep going @@NAMEFILEreadEnd: ; read end sync address mov byte ptr[edi],00h ; null terminate the string mov eax,0001h ; set return code jmp @@NAMEFILEend ; we're done @@NAMEFILEerror: ; error sync address xor eax,eax ; set error return @@NAMEFILEend: ; end proc sync address pop edi ; restore destination index register pop esi ; restore source index register pop ebp ; restore prior stack frame retn ; return near to caller _nameFile endp _outputName proc near push ebp ; save stack frame mov ebp,esp ; create new frame push esi ; save source index register push edi ; save destination index register mov esi,szInputPathFileName ; set esi to input name address mov edi,offset szOutputPathFileName ; set edi to output name address xor ecx,ecx ; clear ecx for indexing @@copyLoop: ; copy loop sync address mov al,[esi+ecx] ; get byte from source to al cmp al,00h ; is this a null byte je @@copyDone ; if so then we're done copying mov byte ptr[edi],al ; store the byte into destination inc edi ; increment destination inc ecx ; increment source index jmp @@copyLoop ; loop through the string @@copyDone: ; copy done sync address mov byte ptr[edi],00h ; set null terminator ifdef TASM STRCHR szOutputPathFileName,'.' ; look for extension marker else STRCHR offset szOutputPathFileName,'.' ; look for extension marker endif cmp eax,0000h ; did we find it? je @@nameError ; if not then we set output name to default mov byte ptr[eax],0000h ; otherwise terminate the string STRCAT szOutputPathFileName,szExtension ; cat the string with ".jpg" jmp @@outputDone ; we're done @@nameError: ; nameError sync address STRLEN szDefaultOutputPathFileName ; get the length of the default file name MEMCPY offset szOutputPathFileName,offset szDefaultOutputPathFileName,eax ; set output file name to default @@outputDone: ; outputDone sync address pop edi ; restore destination index pop esi ; restore source index pop ebp ; restore previous stack frame retn ; return near to caller _outputName endp public _decodeBase64 END