2011-10-15 01:38:50 +04:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; ;;
|
2022-02-12 20:27:41 +03:00
|
|
|
;; Copyright (C) KolibriOS team 2004-2022. All rights reserved. ;;
|
2011-10-15 01:38:50 +04:00
|
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
|
|
;; ;;
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
$Revision$
|
|
|
|
|
|
|
|
|
2021-07-08 19:41:09 +03:00
|
|
|
; @brief Unpack LZMA-compressed data. C-style declaration of the function.
|
|
|
|
;
|
2021-07-08 19:57:24 +03:00
|
|
|
; ```void __stdcall unpack(void *packed_data, void *unpacked_data);```
|
2021-07-08 19:41:09 +03:00
|
|
|
;
|
|
|
|
; @param packed_data Data to unpack
|
|
|
|
; @param unpacked_data Buffer to hold unpacked data
|
|
|
|
; @returns Nothing
|
2011-10-15 01:38:50 +04:00
|
|
|
unpack:
|
|
|
|
pushad
|
|
|
|
mov esi, [esp+32+4]
|
|
|
|
mov edi, [esp+32+8]
|
|
|
|
mov eax, [esi+8]
|
|
|
|
and al, 0xC0
|
|
|
|
cmp al, 0xC0
|
|
|
|
jz .failed
|
|
|
|
mov eax, [esi+8]
|
|
|
|
push eax
|
|
|
|
add esi, 12
|
|
|
|
and al, not 0xC0
|
|
|
|
dec al
|
|
|
|
jz .lzma
|
|
|
|
.failed:
|
|
|
|
pop eax
|
|
|
|
popad
|
|
|
|
ret 8
|
|
|
|
.lzma:
|
|
|
|
call .lzma_unpack
|
|
|
|
.common:
|
|
|
|
pop eax
|
|
|
|
test al, 0x80
|
|
|
|
jnz .ctr1
|
|
|
|
test al, 0x40
|
|
|
|
jz .ok
|
|
|
|
lodsd
|
|
|
|
mov ecx, eax
|
|
|
|
jecxz .ok
|
|
|
|
mov dl, [esi]
|
|
|
|
mov esi, [esp+32+8]
|
|
|
|
.c1:
|
|
|
|
lodsb
|
|
|
|
sub al, 0E8h
|
|
|
|
cmp al, 1
|
|
|
|
ja .c1
|
|
|
|
cmp byte [esi], dl
|
|
|
|
jnz .c1
|
|
|
|
lodsd
|
|
|
|
; "bswap eax" is not supported on i386
|
|
|
|
shr ax, 8
|
|
|
|
ror eax, 16
|
|
|
|
xchg al, ah
|
|
|
|
sub eax, esi
|
|
|
|
add eax, [esp+32+8]
|
|
|
|
mov [esi-4], eax
|
|
|
|
loop .c1
|
|
|
|
.ok:
|
|
|
|
popad
|
|
|
|
ret 8
|
|
|
|
.ctr1:
|
|
|
|
lodsd
|
|
|
|
mov ecx, eax
|
|
|
|
jecxz .ok
|
|
|
|
mov dl, [esi]
|
|
|
|
mov esi, [esp+32+8]
|
|
|
|
.c2:
|
|
|
|
lodsb
|
|
|
|
@@:
|
|
|
|
cmp al, 0xF
|
|
|
|
jnz .f
|
|
|
|
lodsb
|
|
|
|
cmp al, 80h
|
|
|
|
jb @b
|
|
|
|
cmp al, 90h
|
|
|
|
jb @f
|
|
|
|
.f:
|
|
|
|
sub al, 0E8h
|
|
|
|
cmp al, 1
|
|
|
|
ja .c2
|
|
|
|
@@:
|
|
|
|
cmp byte [esi], dl
|
|
|
|
jnz .c2
|
|
|
|
lodsd
|
|
|
|
shr ax, 8
|
|
|
|
ror eax, 16
|
|
|
|
xchg al, ah
|
|
|
|
sub eax, esi
|
|
|
|
add eax, [esp+32+8]
|
|
|
|
mov [esi-4], eax
|
|
|
|
loop .c2
|
|
|
|
jmp .ok
|
|
|
|
|
|
|
|
.lzma_unpack:
|
|
|
|
|
|
|
|
.pb = 2 ; pos state bits
|
|
|
|
.lp = 0 ; literal pos state bits
|
|
|
|
.lc = 3 ; literal context bits
|
|
|
|
.posStateMask = ((1 shl .pb)-1)
|
|
|
|
.literalPosMask = ((1 shl .lp)-1)
|
|
|
|
|
|
|
|
.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
|
|
|
|
|
|
|
|
push edi
|
|
|
|
; int state=0;
|
|
|
|
xor ebx, ebx
|
|
|
|
mov [.previousByte], bl
|
|
|
|
; unsigned rep0=1,rep1=1,rep2=1,rep3=1;
|
|
|
|
mov eax, 1
|
|
|
|
mov edi, .rep0
|
|
|
|
stosd
|
|
|
|
stosd
|
|
|
|
stosd
|
|
|
|
stosd
|
|
|
|
; int len=0;
|
|
|
|
; result=0;
|
|
|
|
mov ecx, .Literal + (.LZMA_LIT_SIZE shl (.lc+.lp))
|
|
|
|
mov eax, .kBitModelTotal/2
|
|
|
|
mov edi, [.p]
|
|
|
|
rep stosd
|
|
|
|
; RangeDecoderInit
|
|
|
|
; rd->ExtraBytes = 0
|
|
|
|
; rd->Buffer = stream
|
|
|
|
; rd->BufferLim = stream+bufferSize
|
|
|
|
; rd->Range = 0xFFFFFFFF
|
|
|
|
pop edi
|
|
|
|
mov ebp, [esi-8] ; dest_length
|
|
|
|
add ebp, edi ; ebp = destination limit
|
|
|
|
lodsd
|
|
|
|
; rd->code_ = eax
|
|
|
|
mov [.code_], eax
|
|
|
|
or [.range], -1
|
|
|
|
.main_loop:
|
|
|
|
cmp edi, ebp
|
|
|
|
jae .main_loop_done
|
|
|
|
mov edx, edi
|
|
|
|
and edx, .posStateMask
|
|
|
|
mov eax, ebx
|
|
|
|
shl eax, .kNumPosBitsMax+2
|
|
|
|
lea eax, [.IsMatch*4 + eax + edx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
jc .1
|
|
|
|
movzx eax, [.previousByte]
|
|
|
|
if .literalPosMask
|
|
|
|
mov ah, dl
|
|
|
|
and ah, .literalPosMask
|
|
|
|
end if
|
|
|
|
shr eax, 8-.lc
|
|
|
|
imul eax, .LZMA_LIT_SIZE*4
|
|
|
|
add eax, .Literal*4
|
|
|
|
add eax, [.p]
|
|
|
|
cmp ebx, .kNumLitStates
|
|
|
|
jb .literal
|
|
|
|
xor edx, edx
|
|
|
|
sub edx, [.rep0]
|
|
|
|
mov dl, [edi + edx]
|
|
|
|
call .LzmaLiteralDecodeMatch
|
|
|
|
jmp @f
|
|
|
|
.literal:
|
|
|
|
call .LzmaLiteralDecode
|
|
|
|
@@:
|
|
|
|
mov [.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, [.IsRep*4 + ebx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
jnc .10
|
|
|
|
lea eax, [.IsRepG0*4 + ebx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
jc .111
|
|
|
|
mov eax, ebx
|
|
|
|
shl eax, .kNumPosBitsMax+2
|
|
|
|
lea eax, [.IsRep0Long*4 + eax + edx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
jc .1101
|
|
|
|
cmp bl, 7
|
|
|
|
setae bl
|
|
|
|
lea ebx, [9 + ebx + ebx]
|
|
|
|
xor edx, edx
|
|
|
|
sub edx, [.rep0]
|
|
|
|
mov al, [edi + edx]
|
|
|
|
stosb
|
|
|
|
mov [.previousByte], al
|
|
|
|
jmp .main_loop
|
|
|
|
.111:
|
|
|
|
lea eax, [.IsRepG1*4 + ebx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
mov eax, [.rep1]
|
|
|
|
jnc .l3
|
|
|
|
.l1:
|
|
|
|
lea eax, [.IsRepG2*4 + ebx*4]
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitDecode
|
|
|
|
mov eax, [.rep2]
|
|
|
|
jnc .l2
|
|
|
|
xchg [.rep3], eax
|
|
|
|
.l2:
|
|
|
|
push [.rep1]
|
|
|
|
pop [.rep2]
|
|
|
|
.l3:
|
|
|
|
xchg eax, [.rep0]
|
|
|
|
mov [.rep1], eax
|
|
|
|
.1101:
|
|
|
|
mov eax, .RepLencoder*4
|
|
|
|
add eax, [.p]
|
|
|
|
call .LzmaLenDecode
|
|
|
|
cmp bl, 7
|
|
|
|
setc bl
|
|
|
|
adc bl, bl
|
|
|
|
xor bl, 3
|
|
|
|
add bl, 8
|
|
|
|
jmp .repmovsb
|
|
|
|
.10:
|
|
|
|
mov eax, [.rep0]
|
|
|
|
xchg eax, [.rep1]
|
|
|
|
xchg eax, [.rep2]
|
|
|
|
xchg eax, [.rep3]
|
|
|
|
cmp bl, 7
|
|
|
|
setc bl
|
|
|
|
adc bl, bl
|
|
|
|
xor bl, 3
|
|
|
|
add bl, 7
|
|
|
|
mov eax, .Lencoder*4
|
|
|
|
add eax, [.p]
|
|
|
|
call .LzmaLenDecode
|
|
|
|
mov eax, .kNumLenToPosStates-1
|
|
|
|
cmp eax, ecx
|
|
|
|
jb @f
|
|
|
|
mov eax, ecx
|
|
|
|
@@:
|
|
|
|
push ecx
|
|
|
|
mov ecx, .kNumPosSlotBits
|
|
|
|
shl eax, cl
|
|
|
|
shl eax, 2
|
|
|
|
add eax, .PosSlot*4
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderBitTreeDecode
|
|
|
|
mov [.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 [.rep0], eax
|
|
|
|
pop edx
|
|
|
|
cmp edx, .kEndPosModelIndex
|
|
|
|
jae .l5
|
|
|
|
sub eax, edx
|
|
|
|
shl eax, 2
|
|
|
|
add eax, (.SpecPos - 1)*4
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderReverseBitTreeDecode
|
|
|
|
add [.rep0], ecx
|
|
|
|
jmp .l6
|
|
|
|
.l5:
|
|
|
|
sub ecx, .kNumAlignBits
|
|
|
|
call .RangeDecoderDecodeDirectBits
|
|
|
|
mov ecx, .kNumAlignBits
|
|
|
|
shl eax, cl
|
|
|
|
add [.rep0], eax
|
|
|
|
mov eax, .Align_*4
|
|
|
|
add eax, [.p]
|
|
|
|
call .RangeDecoderReverseBitTreeDecode
|
|
|
|
add [.rep0], ecx
|
|
|
|
.l6:
|
|
|
|
pop ecx
|
|
|
|
inc [.rep0]
|
|
|
|
jz .main_loop_done
|
|
|
|
.repmovsb:
|
|
|
|
add ecx, .kMatchMinLen
|
|
|
|
push esi
|
|
|
|
mov esi, edi
|
|
|
|
sub esi, [.rep0]
|
|
|
|
rep movsb
|
|
|
|
pop esi
|
|
|
|
mov al, [edi-1]
|
|
|
|
mov [.previousByte], al
|
|
|
|
jmp .main_loop
|
|
|
|
.main_loop_done:
|
|
|
|
ret
|
|
|
|
|
|
|
|
.RangeDecoderBitDecode:
|
|
|
|
; in: eax->prob
|
|
|
|
; out: CF=bit; destroys eax
|
|
|
|
push edx
|
|
|
|
mov edx, [.range]
|
|
|
|
shr edx, .kNumBitModelTotalBits
|
|
|
|
imul edx, [eax]
|
|
|
|
cmp [.code_], edx
|
|
|
|
jae .ae
|
|
|
|
mov [.range], edx
|
|
|
|
mov edx, .kBitModelTotal
|
|
|
|
sub edx, [eax]
|
|
|
|
shr edx, .kNumMoveBits
|
|
|
|
add [eax], edx
|
|
|
|
clc
|
|
|
|
.n:
|
|
|
|
lahf
|
|
|
|
cmp [.range], .kTopValue
|
|
|
|
jae @f
|
|
|
|
shl [.range], 8
|
|
|
|
shl [.code_], 8
|
|
|
|
lodsb
|
|
|
|
mov byte [.code_], al
|
|
|
|
@@:
|
|
|
|
sahf
|
|
|
|
pop edx
|
|
|
|
ret
|
|
|
|
.ae:
|
|
|
|
sub [.range], edx
|
|
|
|
sub [.code_], edx
|
|
|
|
mov edx, [eax]
|
|
|
|
shr edx, .kNumMoveBits
|
|
|
|
sub [eax], edx
|
|
|
|
stc
|
|
|
|
jmp .n
|
|
|
|
|
|
|
|
.RangeDecoderDecodeDirectBits:
|
|
|
|
; in: ecx=numTotalBits
|
|
|
|
; out: eax=result; destroys edx
|
|
|
|
xor eax, eax
|
|
|
|
.l:
|
|
|
|
shr [.range], 1
|
|
|
|
shl eax, 1
|
|
|
|
mov edx, [.code_]
|
|
|
|
sub edx, [.range]
|
|
|
|
jb @f
|
|
|
|
mov [.code_], edx
|
|
|
|
or eax, 1
|
|
|
|
@@:
|
|
|
|
cmp [.range], .kTopValue
|
|
|
|
jae @f
|
|
|
|
shl [.range], 8
|
|
|
|
shl [.code_], 8
|
|
|
|
push eax
|
|
|
|
lodsb
|
|
|
|
mov byte [.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
|
|
|
|
|
|
|
|
uglobal
|
|
|
|
align 4
|
|
|
|
;unpack.p rd unpack.LZMA_BASE_SIZE + (unpack.LZMA_LIT_SIZE shl (unpack.lc+unpack.lp))
|
|
|
|
unpack.p dd ?
|
|
|
|
unpack.code_ dd ?
|
|
|
|
unpack.range dd ?
|
|
|
|
unpack.rep0 dd ?
|
|
|
|
unpack.rep1 dd ?
|
|
|
|
unpack.rep2 dd ?
|
|
|
|
unpack.rep3 dd ?
|
|
|
|
unpack.previousByte db ?
|
|
|
|
endg
|