470 lines
13 KiB
PHP
470 lines
13 KiB
PHP
|
; 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
|