0,0 → 1,581 |
; 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 |
xor edx, edx |
sub edx, [ebp+.rep0] |
mov dl, [edi + edx] |
call .LzmaLiteralDecodeMatch |
jmp @f |
.literal: |
call .LzmaLiteralDecode |
@@: |
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] |
xor edx, edx |
sub edx, [ebp+.rep0] |
mov al, [edi + 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] |
jae return.err |
mov esi, edi |
sub esi, eax |
mov eax, [ebp+streamInfo.bufPtr] |
sub eax, esi |
ja .repmovsb0 |
mov eax, [ebp+.outEnd] |
sub eax, edi |
push ecx |
cmp ecx, eax |
jb @f |
mov ecx, eax |
@@: |
sub [esp], ecx |
rep movsb |
pop ecx |
jz .repmovsb1 |
pop [ebp+.inPtr] |
mov [ebp+.state], ebx |
mov [ebp+.ecx], ecx |
mov [ebp+.continue], .restart_repmovsb |
popad |
ret |
.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 |
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 |
.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 |