kolibrios/programs/fs/kfar/trunk/kfar_arc/lzma.inc
Evgeny Grechnikov (Diamond) 44e90288dd KFar 0.65: fixed error handler
KFar_Arc 0.16: fixed crash when handling some extremely big 7z+lzma archives

git-svn-id: svn://kolibrios.org@1122 a494cfbc-eb01-0410-851d-a64ba20cac60
2009-07-02 21:50:45 +00:00

609 lines
13 KiB
PHP

; LZMA decoder for *.7z archives.
; Based on C decoder in LZMA SDK (c) Igor Pavlov.
; Portions by Diamond, 2006, 2007.
lzma_decoder:
virtual at 0
.outStream rb streamInfo.size
.inStream dd ?
; RangeDecoder data
.inLen dd ?
.inPtr dd ?
.code dd ?
.range dd ?
; parameters
.pb db ? ; pos state bits (0 - 4)
.lp db ? ; literal pos state bits (0 - 4)
.lc db ? ; literal context bits (0 - 8)
.previousByte db ?
.posStateMask dd ? ; (1 shl .pb)-1
.literalPosMask dd ? ; (1 shl .lp)-1
; constants
.kNumPosBitsMax = 4
.kNumPosStatesMax = (1 shl .kNumPosBitsMax)
.kLenNumLowBits = 3
.kLenNumLowSymbols = (1 shl .kLenNumLowBits)
.kLenNumMidBits = 3
.kLenNumMidSymbols = (1 shl .kLenNumMidBits)
.kLenNumHighBits = 8
.kLenNumHighSymbols = (1 shl .kLenNumHighBits)
.LenChoice = 0
.LenChoice2 = 1
.LenLow = 2
.LenMid = (.LenLow + (.kNumPosStatesMax shl .kLenNumLowBits))
.LenHigh = (.LenMid + (.kNumPosStatesMax shl .kLenNumMidBits))
.kNumLenProbs = (.LenHigh + .kLenNumHighSymbols)
.kNumStates = 12
.kNumLitStates = 7
.kStartPosModelIndex = 4
.kEndPosModelIndex = 14
.kNumFullDistances = (1 shl (.kEndPosModelIndex/2))
.kNumPosSlotBits = 6
.kNumLenToPosStates = 4
.kNumAlignBits = 4
.kAlignTableSize = (1 shl .kNumAlignBits)
.kMatchMinLen = 2
.IsMatch = 0
.IsRep = (.IsMatch + (.kNumStates shl .kNumPosBitsMax))
.IsRepG0 = (.IsRep + .kNumStates)
.IsRepG1 = (.IsRepG0 + .kNumStates)
.IsRepG2 = (.IsRepG1 + .kNumStates)
.IsRep0Long = (.IsRepG2 + .kNumStates)
.PosSlot = (.IsRep0Long + (.kNumStates shl .kNumPosBitsMax))
.SpecPos = (.PosSlot + (.kNumLenToPosStates shl .kNumPosSlotBits))
.Align_ = (.SpecPos + .kNumFullDistances - .kEndPosModelIndex)
.Lencoder = (.Align_ + .kAlignTableSize)
.RepLencoder = (.Lencoder + .kNumLenProbs)
.Literal = (.RepLencoder + .kNumLenProbs)
LZMA_BASE_SIZE = 1846 ; must be ==Literal
LZMA_LIT_SIZE = 768
.kNumTopBits = 24
.kTopValue = (1 shl .kNumTopBits)
.kNumBitModelTotalBits = 11
.kBitModelTotal = (1 shl .kNumBitModelTotalBits)
.kNumMoveBits = 5
; variables
.continue dd ?
.ecx dd ?
.outEnd dd ?
.dictSize dd ?
.state dd ?
.rep0 dd ?
.rep1 dd ?
.rep2 dd ?
.rep3 dd ?
.p rd LZMA_BASE_SIZE
.basesize = $
; rd LZMA_LIT_SIZE shl (.lc+.lp)
end virtual
.fillBuf:
mov ebp, eax
mov ebx, [ebp+.state]
jecxz .nodata
add ecx, edi
mov [ebp+.outEnd], ecx
mov esi, [ebp+.inPtr]
jmp [ebp+.continue]
.nodata:
popad
ret
.start:
mov eax, [ebp+.inStream]
call fillBuf
mov esi, [eax+streamInfo.bufPtr]
mov eax, [eax+streamInfo.bufDataLen]
sub eax, 5
jb return.err
mov [ebp+.inLen], eax
inc esi
lodsd
bswap eax
mov [ebp+.code], eax
or [ebp+.range], -1
.main_loop:
cmp edi, [ebp+.outEnd]
jae .main_loop_done
mov edx, edi
and edx, [ebp+.posStateMask]
mov eax, ebx
shl eax, .kNumPosBitsMax
add eax, edx
lea eax, [ebp + .p + .IsMatch*4 + eax*4]
call .RangeDecoderBitDecode
jc .1
movzx eax, [ebp+.previousByte]
mov ah, dl
and ah, byte [ebp+.literalPosMask]
mov cl, 8
sub cl, [ebp+.lc]
shr eax, cl
imul eax, LZMA_LIT_SIZE*4
lea eax, [ebp + eax + .p+.Literal*4]
cmp ebx, .kNumLitStates
jb .literal
mov edx, edi
sub edx, [ebp+.rep0]
jc .before_buf
cmp edx, [ebp+streamInfo.bufPtr]
jb .before_buf
@@:
mov dl, [edx]
call .LzmaLiteralDecodeMatch
jmp .got_byte
.before_buf:
add edx, [ebp+streamInfo.bufSize]
cmp edx, [ebp+streamInfo.bufPtr]
jb return.err
jmp @b
.literal:
call .LzmaLiteralDecode
.got_byte:
mov [ebp+.previousByte], al
stosb
mov al, bl
cmp bl, 4
jb @f
mov al, 3
cmp bl, 10
jb @f
mov al, 6
@@: sub bl, al
jmp .main_loop
.1:
lea eax, [ebp + .p + .IsRep*4 + ebx*4]
call .RangeDecoderBitDecode
jnc .10
lea eax, [ebp + .p + .IsRepG0*4 + ebx*4]
call .RangeDecoderBitDecode
jc .111
mov eax, ebx
shl eax, .kNumPosBitsMax
add eax, edx
lea eax, [ebp + .p + .IsRep0Long*4 + eax*4]
call .RangeDecoderBitDecode
jc .1101
cmp bl, 7
setae bl
lea ebx, [9 + ebx + ebx]
mov edx, edi
sub edx, [ebp+.rep0]
jc @f
cmp edx, [ebp+streamInfo.bufPtr]
jae .copy_byte
@@:
add edx, [ebp+streamInfo.bufSize]
cmp edx, [ebp+streamInfo.bufPtr]
jb return.err
.copy_byte:
mov al, [edx]
stosb
mov [ebp+.previousByte], al
jmp .main_loop
.111:
lea eax, [ebp + .p + .IsRepG1*4 + ebx*4]
call .RangeDecoderBitDecode
mov eax, [ebp+.rep1]
jnc .l3
.l1:
lea eax, [ebp + .p + .IsRepG2*4 + ebx*4]
call .RangeDecoderBitDecode
mov eax, [ebp+.rep2]
jnc .l2
xchg [ebp+.rep3], eax
.l2:
push [ebp+.rep1]
pop [ebp+.rep2]
.l3:
xchg eax, [ebp+.rep0]
mov [ebp+.rep1], eax
.1101:
lea eax, [ebp + .p + .RepLencoder*4]
call .LzmaLenDecode
cmp bl, 7
setc bl
adc bl, bl
xor bl, 3
add bl, 8
jmp .repmovsb
.10:
mov eax, [ebp+.rep0]
xchg eax, [ebp+.rep1]
xchg eax, [ebp+.rep2]
xchg eax, [ebp+.rep3]
cmp bl, 7
setc bl
adc bl, bl
xor bl, 3
add bl, 7
lea eax, [ebp + .p + .Lencoder*4]
call .LzmaLenDecode
mov eax, .kNumLenToPosStates-1
cmp eax, ecx
jb @f
mov eax, ecx
@@:
push ecx
mov ecx, .kNumPosSlotBits
shl eax, cl
lea eax, [ebp + .p+.PosSlot*4 + eax*4]
call .RangeDecoderBitTreeDecode
mov [ebp+.rep0], ecx
cmp ecx, .kStartPosModelIndex
jb .l6
push ecx
mov eax, ecx
and eax, 1
shr ecx, 1
or eax, 2
dec ecx
shl eax, cl
mov [ebp+.rep0], eax
pop edx
cmp edx, .kEndPosModelIndex
jae .l5
sub eax, edx
lea eax, [ebp + .p + (.SpecPos - 1)*4 + eax*4]
call .RangeDecoderReverseBitTreeDecode
add [ebp+.rep0], ecx
jmp .l6
.l5:
sub ecx, .kNumAlignBits
call .RangeDecoderDecodeDirectBits
mov ecx, .kNumAlignBits
shl eax, cl
add [ebp+.rep0], eax
lea eax, [ebp+.p+.Align_*4]
call .RangeDecoderReverseBitTreeDecode
add [ebp+.rep0], ecx
.l6:
pop ecx
inc [ebp+.rep0]
jz .main_loop_done
.repmovsb:
add ecx, .kMatchMinLen
.repmovsbz:
push esi
.repmovsbr:
mov eax, [ebp+.rep0]
cmp eax, [ebp+.dictSize]
ja return.err
mov esi, edi
sub esi, eax
jc .repmovsb0a
mov eax, [ebp+streamInfo.bufPtr]
sub eax, esi
ja .repmovsb0
mov eax, [ebp+.outEnd]
sub eax, edi
jz .done1
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
pop ecx
jz .repmovsb1
.done1:
pop [ebp+.inPtr]
mov [ebp+.state], ebx
mov [ebp+.ecx], ecx
mov [ebp+.continue], .restart_repmovsb
popad
ret
.repmovsb0a:
mov eax, [ebp+streamInfo.bufPtr]
sub eax, esi
.repmovsb0:
mov edx, [ebp+.dictSize]
; cmp edx, [ebp+streamInfo.bufSize]
; jnz return.err
add esi, edx
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
mov eax, [ebp+.outEnd]
sub eax, edi
jz .done2
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
pop ecx
jnz .repmovsbr
.repmovsb1:
pop esi
mov al, [edi-1]
mov [ebp+.previousByte], al
jmp .main_loop
.done2:
pop ecx
jmp .done1
.main_loop_done:
mov [ebp+.state], ebx
mov [ebp+.continue], .main_loop
mov [ebp+.inPtr], esi
popad
ret
.restart_repmovsb:
mov ecx, [ebp+.ecx]
jmp .repmovsbz
.RangeDecoderBitDecode:
; in: eax->prob
; out: CF=bit; destroys eax
push edx
mov edx, [ebp+.range]
shr edx, .kNumBitModelTotalBits
imul edx, [eax]
cmp [ebp+.code], edx
jae .ae
mov [ebp+.range], edx
mov edx, .kBitModelTotal
sub edx, [eax]
shr edx, .kNumMoveBits
add [eax], edx
clc
.n:
lahf
cmp [ebp+.range], .kTopValue
jae @f
shl [ebp+.range], 8
shl [ebp+.code], 8
sub [ebp+.inLen], 1
js .refill1
.refilled1:
lodsb
mov byte [ebp+.code], al
@@:
sahf
pop edx
ret
.ae:
sub [ebp+.range], edx
sub [ebp+.code], edx
mov edx, [eax]
shr edx, .kNumMoveBits
sub [eax], edx
stc
jmp .n
.refill1:
push eax
call .refill
pop eax
jmp .refilled1
.refill:
mov eax, [ebp+.inStream]
cmp dword [eax+streamInfo.fullSize+4], 0
jnz @f
cmp dword [eax+streamInfo.fullSize], 0
jz return.err
@@:
call fillBuf
mov esi, [eax+streamInfo.bufPtr]
mov eax, [eax+streamInfo.bufDataLen]
dec eax
js return.err
mov [ebp+.inLen], eax
ret
.refill2:
call .refill
jmp .refilled2
.RangeDecoderDecodeDirectBits:
; in: ecx=numTotalBits
; out: eax=result; destroys edx
xor eax, eax
.l:
shr [ebp+.range], 1
shl eax, 1
mov edx, [ebp+.code]
sub edx, [ebp+.range]
jb @f
mov [ebp+.code], edx
or eax, 1
@@:
cmp [ebp+.range], .kTopValue
jae @f
shl [ebp+.range], 8
shl [ebp+.code], 8
push eax
dec [ebp+.inLen]
js .refill2
.refilled2:
lodsb
mov byte [ebp+.code], al
pop eax
@@:
loop .l
ret
.LzmaLiteralDecode:
; in: eax->probs
; out: al=byte; destroys edx
push ecx
mov ecx, 1
@@:
push eax
lea eax, [eax+ecx*4]
call .RangeDecoderBitDecode
pop eax
adc cl, cl
jnc @b
.LzmaLiteralDecode.ret:
mov al, cl
pop ecx
ret
.LzmaLiteralDecodeMatch:
; in: eax->probs, dl=matchByte
; out: al=byte; destroys edx
push ecx
mov ecx, 1
.LzmaLiteralDecodeMatch.1:
add dl, dl
setc ch
push eax
lea eax, [eax+ecx*4+0x100*4]
call .RangeDecoderBitDecode
pop eax
adc cl, cl
jc .LzmaLiteralDecode.ret
xor ch, cl
test ch, 1
mov ch, 0
jnz @b
jmp .LzmaLiteralDecodeMatch.1
.LzmaLenDecode:
; in: eax->prob, edx=posState
; out: ecx=len
push eax
add eax, .LenChoice*4
call .RangeDecoderBitDecode
pop eax
jnc .0
push eax
add eax, .LenChoice2*4
call .RangeDecoderBitDecode
pop eax
jc @f
mov ecx, .kLenNumMidBits
shl edx, cl
lea eax, [eax + .LenMid*4 + edx*4]
call .RangeDecoderBitTreeDecode
add ecx, .kLenNumLowSymbols
ret
@@:
add eax, .LenHigh*4
mov ecx, .kLenNumHighBits
call .RangeDecoderBitTreeDecode
add ecx, .kLenNumLowSymbols + .kLenNumMidSymbols
ret
.0:
mov ecx, .kLenNumLowBits
shl edx, cl
lea eax, [eax + .LenLow*4 + edx*4]
.RangeDecoderBitTreeDecode:
; in: eax->probs,ecx=numLevels
; out: ecx=length; destroys edx
push ebx
mov edx, 1
mov ebx, edx
@@:
push eax
lea eax, [eax+edx*4]
call .RangeDecoderBitDecode
pop eax
adc dl, dl
add bl, bl
loop @b
sub dl, bl
pop ebx
mov ecx, edx
ret
.RangeDecoderReverseBitTreeDecode:
; in: eax->probs,ecx=numLevels
; out: ecx=length; destroys edx
push ebx ecx
mov edx, 1
xor ebx, ebx
@@:
push eax
lea eax, [eax+edx*4]
call .RangeDecoderBitDecode
lahf
adc edx, edx
sahf
rcr ebx, 1
pop eax
loop @b
pop ecx
rol ebx, cl
mov ecx, ebx
pop ebx
ret
; LZMA parameters:
; db lc + 9 * (lp + 5 * pb)
; dd dictionarySize
lzma_get_buf_size:
cmp dword [esi-4], 5
jb return.err
push ecx
lodsb
aam 9
mov cl, al
mov al, ah
aam 5
add cl, al
mov eax, LZMA_LIT_SIZE
shl eax, cl
lea eax, [lzma_decoder.basesize+eax*4]
pop ecx
mov edx, [esi]
ret
lzma_init_decoder:
lodsb
aam 9
mov [ebp+lzma_decoder.lc], al
mov al, ah
aam 5
mov [ebp+lzma_decoder.lp], al
mov [ebp+lzma_decoder.pb], ah
cmp ah, lzma_decoder.kNumPosBitsMax
ja return.err
mov cl, ah
lodsd
mov [ebp+lzma_decoder.dictSize], eax
push 1
pop eax
shl eax, cl
dec eax
mov [ebp+lzma_decoder.posStateMask], eax
mov cl, [ebp+lzma_decoder.lp]
push 1
pop eax
shl eax, cl
dec eax
mov [ebp+lzma_decoder.literalPosMask], eax
mov [ebp+streamInfo.fillBuf], lzma_decoder.fillBuf
mov [ebp+lzma_decoder.continue], lzma_decoder.start
xor eax, eax
mov [ebp+lzma_decoder.previousByte], al
mov [ebp+lzma_decoder.state], eax
inc eax
lea edi, [ebp+lzma_decoder.rep0]
stosd
stosd
stosd
mov eax, LZMA_LIT_SIZE
mov cl, [ebp+lzma_decoder.lc]
add cl, [ebp+lzma_decoder.lp]
shl eax, cl
lea ecx, [eax+lzma_decoder.Literal]
mov eax, lzma_decoder.kBitModelTotal/2
lea edi, [ebp+lzma_decoder.p]
rep stosd
ret