; Branch filters for 7-Zip archives: BCJ and BCJ2. ; Ported from C++ sources of 7-Zip (c) Igor Pavlov. virtual at 0 bcj_decoder: .outStream rb streamInfo.size .inStream dd ? .inPtr dd ? .inSize dd ? .nowPos dd ? ; offset in stream .prevPos dd ? ; pointer in buffer .prevMask db ? .numRest db ? rw 1 .dwordRest dd ? .tempSize dd ? .tempDword dd ? .size = $ end virtual bcj_get_buf_size: mov eax, bcj_decoder.size mov edx, 0x4000 ret bcj_init_decoder: mov [ebp+streamInfo.fillBuf], bcj_fillBuf xor edx, edx mov [ebp+bcj_decoder.inPtr], edx mov [ebp+bcj_decoder.inSize], edx mov [ebp+bcj_decoder.prevPos], edx mov [ebp+bcj_decoder.nowPos], edx mov [ebp+bcj_decoder.numRest], dl ret bcj_fillBuf: add [eax+bcj_decoder.nowPos], ecx mov ebp, ecx ; save output size mov esi, [eax+bcj_decoder.inPtr] mov ebx, [eax+bcj_decoder.inStream] mov ecx, [eax+bcj_decoder.inSize] add esi, [ebx+streamInfo.bufPtr] mov ebx, eax cmp [eax+bcj_decoder.prevPos], 0 jz @f add [eax+bcj_decoder.prevPos], edi @@: cmp [ebx+bcj_decoder.numRest], 0 jz .mainloop sub ebp, 1 js .mainloopdone dec [ebx+bcj_decoder.numRest] mov eax, [ebx+bcj_decoder.dwordRest] stosb shr eax, 8 mov [ebx+bcj_decoder.dwordRest], eax jmp @b .mainloop: sub ebp, 1 js .mainloopdone sub ecx, 1 js .refill1 .filled1: lodsb .filled2: stosb cmp al, 0xE8 jz .filter cmp al, 0xE9 jnz .mainloop .filter: and [ebx+bcj_decoder.tempSize], 0 sub ecx, 4 jb .nopos js .nopos2 lodsd push eax .posok: xor edx, edx mov eax, edi sub eax, [ebx+bcj_decoder.prevPos] cmp eax, 5 ja .maskok movzx edx, [ebx+bcj_decoder.prevMask] @@: and edx, 0x77 add edx, edx sub eax, 1 jnz @b .maskok: mov [ebx+bcj_decoder.prevMask], dl mov [ebx+bcj_decoder.prevPos], edi mov al, [esp+3] add al, 1 cmp al, 2 jae .miss cmp dl, 0x20 jae .miss2 lea eax, [edx-1] test eax, edx jnz .miss2 pop eax shr edx, 1 push ecx mov cl, [bcj_kMaskToBitNumber+edx] iglobal bcj_kMaskToBitNumber db 24,16,8,8,0,0,0,0 endg @@: sub eax, [ebx+bcj_decoder.nowPos] add eax, [ebx+streamInfo.bufDataLen] sub eax, edi sub eax, 4 add eax, [ebx+streamInfo.bufPtr] cmp cl, 24 jz @f push eax shr eax, cl add al, 1 cmp al, 2 pop eax jae @f mov edx, 0x100 shl edx, cl sub edx, 1 xor eax, edx jmp @b @@: pop ecx shl eax, 7 sar eax, 7 sub ebp, 4 jb .finalize_dword stosd jmp .mainloop .miss2: or [ebx+bcj_decoder.prevMask], 10h .miss: or [ebx+bcj_decoder.prevMask], 1 cmp [ebx+bcj_decoder.tempSize], 0 jz @f lea esi, [ebx+bcj_decoder.tempDword] pop dword [esi] mov ecx, [ebx+bcj_decoder.tempSize] jmp .mainloop @@: pop eax sub esi, 4 add ecx, 4 jmp .mainloop .finalize_dword: add ebp, 4 mov [ebx+bcj_decoder.numRest], 4 @@: dec ebp js .save_dword stosb dec [ebx+bcj_decoder.numRest] shr eax, 8 jmp @b .save_dword: mov [ebx+bcj_decoder.dwordRest], eax .mainloopdone: mov eax, [ebx+bcj_decoder.prevPos] test eax, eax jz .noprev sub eax, edi mov [ebx+bcj_decoder.prevPos], eax .noprev: mov eax, [ebx+bcj_decoder.inStream] sub esi, [eax+streamInfo.bufPtr] mov [ebx+bcj_decoder.inPtr], esi mov [ebx+bcj_decoder.inSize], ecx popad ret .refill1: cmp ecx, -1 jz .refill0 lodsb cmp ecx, -4 jnz @f mov ecx, [ebx+bcj_decoder.inStream] mov esi, [ecx+streamInfo.bufPtr] mov ecx, [ecx+streamInfo.bufDataLen] @@: jmp .filled2 .refill0: mov eax, [ebx+bcj_decoder.inStream] call fillBuf mov esi, [eax+streamInfo.bufPtr] mov ecx, [eax+streamInfo.bufDataLen] sub ecx, 1 js return.err jmp .filled1 .nopos: mov eax, [ebx+bcj_decoder.inStream] cmp dword [eax+streamInfo.fullSize+4], 0 jnz .hasdata push ecx add ecx, dword [eax+streamInfo.fullSize] pop ecx jc .hasdata add ecx, 4 jmp .mainloop .hasdata: mov [ebx+bcj_decoder.tempSize], ecx push 0 push edi lea edi, [esp+4] add ecx, 4 rep movsb sub esi, ebx sub esi, 1 cmp esi, bcj_decoder.tempDword+4 jbe @f call fillBuf @@: mov esi, [eax+streamInfo.bufPtr] mov ecx, [ebx+bcj_decoder.tempSize] neg ecx rep movsb pop edi mov ecx, [eax+streamInfo.bufDataLen] add ecx, [ebx+bcj_decoder.tempSize] cmp [ebx+bcj_decoder.tempSize], -4 jnz .posok and [ebx+bcj_decoder.tempSize], 0 jmp .posok .nopos2: mov eax, [ebx+bcj_decoder.inStream] add ecx, 4 jmp .hasdata virtual at 0 bcj2_decoder: .outStream rb streamInfo.size .mainInStream dd ? .callStream dd ? .jumpStream dd ? .rangeDecoder dd ? .dwordRest dd ? .prevByte db ? .numRest db ? .bInited db ? rb 1 .inPtr dd ? .inSize dd ? .callPtr dd ? .jumpPtr dd ? .callSize dd ? .jumpSize dd ? .rangeDecPtr dd ? .rangeDecSize dd ? .nowPos dd ? .range dd ? .code dd ? .statusE9Decoder dd ? .statusJccDecoder dd ? .statusE8Decoder rd 256 .size = $ end virtual bcj2_get_buf_size: mov eax, bcj2_decoder.size mov edx, 0x4000 ret bcj2_init_decoder: mov [ebp+streamInfo.fillBuf], bcj2_fillBuf mov eax, lzma_decoder.kBitModelTotal/2 mov ecx, 256+1+1 lea edi, [ebp+bcj2_decoder.statusE9Decoder] rep stosd mov dword [ebp+bcj2_decoder.prevByte], ecx mov [ebp+bcj2_decoder.inSize], ecx mov [ebp+bcj2_decoder.callSize], ecx mov [ebp+bcj2_decoder.jumpSize], ecx mov [ebp+bcj2_decoder.rangeDecSize], ecx mov [ebp+bcj2_decoder.nowPos], ecx ret bcj2_fillBuf.init: mov eax, [eax+bcj2_decoder.rangeDecoder] call fillBuf mov edx, [eax+streamInfo.bufDataLen] sub edx, 5 jb return.err mov [ebp+bcj2_decoder.rangeDecSize], edx mov edx, [eax+streamInfo.bufPtr] add edx, 5 mov [ebp+bcj2_decoder.rangeDecPtr], edx mov edx, [edx-4] bswap edx mov [ebp+bcj2_decoder.code], edx or [ebp+bcj2_decoder.range], -1 mov [ebp+bcj2_decoder.bInited], 1 mov eax, ebp jmp bcj2_fillBuf.inited bcj2_fillBuf: mov ebp, eax cmp [eax+bcj2_decoder.bInited], 0 jz .init .inited: add [eax+bcj2_decoder.nowPos], ecx mov esi, [eax+bcj2_decoder.inPtr] @@: cmp [ebp+bcj2_decoder.numRest], 0 jz .mainloop sub ecx, 1 js .mainloopdone dec [ebp+bcj2_decoder.numRest] mov eax, [ebp+bcj2_decoder.dwordRest] stosb mov [ebp+bcj2_decoder.prevByte], al shr eax, 8 mov [ebp+bcj2_decoder.dwordRest], eax jmp @b .mainloop: sub ecx, 1 js .mainloopdone sub [ebp+bcj2_decoder.inSize], 1 js .refill1 .filled1: lodsb stosb cmp al, 0xE8 jz .e8 cmp al, 0xE9 jz .e9 cmp [ebp+bcj2_decoder.prevByte], 0xF mov [ebp+bcj2_decoder.prevByte], al jnz .mainloop and al, 0xF0 cmp al, 0x80 jnz .mainloop .jcc: lea eax, [ebp+bcj2_decoder.statusJccDecoder] call .RangeDecoderBitDecode jnc .mainloop jmp .getptrj .e8: movzx eax, al xchg al, [ebp+bcj2_decoder.prevByte] lea eax, [ebp+bcj2_decoder.statusE8Decoder+eax*4] call .RangeDecoderBitDecode jnc .mainloop lea eax, [ebp+bcj2_decoder.callPtr] jmp .getptr .e9: mov [ebp+bcj2_decoder.prevByte], al lea eax, [ebp+bcj2_decoder.statusE9Decoder] call .RangeDecoderBitDecode jnc .mainloop .getptrj: lea eax, [ebp+bcj2_decoder.jumpPtr] .getptr: sub dword [eax+8], 4 js .refill2 .filled2: add dword [eax], 4 mov eax, [eax] mov eax, [eax-4] bswap eax sub eax, [ebp+bcj2_decoder.nowPos] add eax, [ebp+streamInfo.bufDataLen] sub eax, edi sub eax, 4 add eax, [ebp+streamInfo.bufPtr] sub ecx, 4 jb .finalize_dword stosd shr eax, 24 mov [ebp+bcj2_decoder.prevByte], al jmp .mainloop .finalize_dword: add ecx, 4 mov [ebp+bcj2_decoder.numRest], 4 @@: dec ecx js .save_dword stosb dec [ebp+bcj2_decoder.numRest] shr eax, 8 jmp @b .save_dword: mov [ebp+bcj2_decoder.dwordRest], eax .mainloopdone: mov [ebp+bcj2_decoder.inPtr], esi popad ret .refill1: mov eax, [ebp+bcj2_decoder.mainInStream] call fillBuf mov edx, [eax+streamInfo.bufDataLen] dec edx js return.err mov [ebp+bcj2_decoder.inSize], edx mov esi, [eax+streamInfo.bufPtr] jmp .filled1 .refill2: push eax mov eax, [eax-bcj2_decoder.callPtr+bcj2_decoder.callStream] call fillBuf mov edx, [eax+streamInfo.bufDataLen] sub edx, 4 js return.err push [eax+streamInfo.bufPtr] mov eax, [esp+4] pop dword [eax] pop eax mov [eax+8], edx jmp .filled2 .refill3: push eax mov eax, [ebp+bcj2_decoder.rangeDecoder] call fillBuf mov edx, [eax+streamInfo.bufDataLen] dec edx js return.err mov [ebp+bcj2_decoder.rangeDecSize], edx mov edx, [eax+streamInfo.bufPtr] mov [ebp+bcj2_decoder.rangeDecPtr], edx pop eax jmp .filled3 .RangeDecoderBitDecode: ; in: eax->prob ; out: CF=bit; destroys eax,edx mov edx, [ebp+bcj2_decoder.range] shr edx, lzma_decoder.kNumBitModelTotalBits imul edx, [eax] cmp [ebp+bcj2_decoder.code], edx jae .ae mov [ebp+bcj2_decoder.range], edx mov edx, lzma_decoder.kBitModelTotal sub edx, [eax] shr edx, lzma_decoder.kNumMoveBits add [eax], edx clc .n: lahf cmp [ebp+bcj2_decoder.range], lzma_decoder.kTopValue jae @f shl [ebp+bcj2_decoder.range], 8 shl [ebp+bcj2_decoder.code], 8 dec [ebp+bcj2_decoder.rangeDecSize] js .refill3 .filled3: mov edx, [ebp+bcj2_decoder.rangeDecPtr] mov al, [edx] add edx, 1 mov [ebp+bcj2_decoder.rangeDecPtr], edx mov byte [ebp+bcj2_decoder.code], al @@: sahf ret .ae: sub [ebp+bcj2_decoder.range], edx sub [ebp+bcj2_decoder.code], edx mov edx, [eax] shr edx, lzma_decoder.kNumMoveBits sub [eax], edx stc jmp .n