home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 25
/
CD_ASCQ_25_1095.iso
/
dos
/
prg
/
cpe50
/
comp386.asm
next >
Wrap
Assembly Source File
|
1995-05-09
|
24KB
|
1,014 lines
; ************************************
; * Compressor/decompressor routines *
; * 386+ version *
; ************************************
; the algorithm is my own invention except for the huffman part.
; * NEVER compress/decompress more than 32K of data!
; * leave about 33000 bytes in destination buffer!
IDEAL
P386
PUBLIC PackArea,UnpackArea
PUBLIC PasPack,PasUnpack
SEGMENT packer_text PAGE PUBLIC 'CODE'
ASSUME CS:packer_text
ASSUME FS:packer_data
MAX_VAL EQU 103h
PasPack:
PUSH BP
MOV BP,SP
PUSH DS
LDS SI,[BP+12]
LES DI,[BP+8]
MOV CX,[BP+6]
CALL FAR PackArea
POP DS
POP BP
RETF
PasUnpack:
PUSH BP
MOV BP,SP
PUSH DS
LDS SI,[BP+12]
LES DI,[BP+8]
MOV CX,[BP+6]
CALL FAR UnpackArea
POP DS
POP BP
RETF
PackArea: ; IN: DS:SI area to be packed, ES:DI dest buffer,
; at least same size+10. Restrict data size to 32KB!
; CX length
; returns packed len + headersize in AX
PUSH FS
MOV AX,SEG bitpos
MOV FS,AX
CALL Initialize
CALL FindRepetitions
OR AX,AX ; no length? strange...
JE PARE_HuffSrcOK
MOV DX,CX
MOV CX,AX
MOV SI,OFFSET tempbuf
MOV AX,SEG tempbuf
MOV DS,AX
PARE_HuffSrcOK:
PUSH DI
PUSh DX
ADD DI,12
CALL EncodeHuffman
POP DX
POP DI
MOV AX,'RC'
STOSW
MOV AX,'XU'
STOSW
MOV AX,'AP'
STOSW
MOV AX,'KC'
STOSW
MOV AX,[pckflg]
STOSW
MOV AX,DX
STOSW
MOV AX,CX
ADD AX,12 ; add header size
PARE_End:
POP FS
RETF
FindRepetitions: ; pack method 1, to tempbuf
PUSH ES ; returns packed length
PUSH DI
PUSH SI
PUSH CX
PUSH SEG tempbuf
POP ES
MOV DI,OFFSET tempbuf
XOR DX,DX
XOR BX,BX
FREP_Loop:
MOV EAX,[SI]
INC SI
DEC BX
CMP CX,6
JC FREP_Writeback
CALL FREP_FindEqual
CMP [relpos],0
JE FREP_Writeback
MOV AL,255
CALL WriteToTemp
XOR AL,AL
CMP [relpos],0feffh
RCL AL,1
CMP [rellen],260
RCL AL,1
XOR AL,1
CALL WriteToTemp
MOV AX,[relpos]
INC AX
CALL WriteToTemp
MOV AL,AH
CMP AL,0ffh
JE FREP_FE_RelB
CALL WriteToTemp
FREP_FE_RelB:
MOV AX,[rellen]
SUB AX,4
CALL WriteToTemp
MOV AL,AH
OR AL,AL
JE FREP_FE_SequenceOK
CALL WriteToTemp
FREP_FE_SequenceOK:
MOV BP,[rellen]
DEC BP ; one increment already done by
SUB CX,BP ; LODSB etc.
ADD SI,BP
SUB BX,BP
JMP FREP_LoopEnd
FREP_Writeback:
CALL WriteToTemp
CMP AL,0ffh
JNE FREP_LoopEnd
CALL WriteToTemp
FREP_LoopEnd:
LOOP FREP_Loop
XOR AX,AX
CMP DX,33000
JNC FREP_End
OR [pckflg],1
MOV AX,DX
FREP_End:
POP CX
POP SI
POP DI
POP ES
RET
FREP_FindEqual:
MOV [relpos],0 ; check if sequence occurred before
MOV [rellen],0 ; search for best occurrence!
MOV [relsave],0 ; in BX: max neg offset
PUSH DI
PUSH ES
PUSH BX
PUSH CX
PUSH DS
POP ES
MOV BP,CX
XCHG BX,CX
MOV BX,0ffffh
FREP_FE_OffLoop:
DEC BX
CMP BX,0fffah
JE FREP_FE_End
CMP BX,CX
JC FREP_FE_End
PUSH BX
MOV DI,SI
ADD DI,BX
PUSH CX
NEG CX
ADD CX,BX
SHR CX,2
INC CX
MOV BX,SI
FREP_FE_Loop:
JCXZ FREP_FE_LoopEnd
STD
REPNE SCASD
CLD
CMP EAX,[DI+4]
JNE FREP_FE_LoopEnd
PUSH BX
SUB BX,DI
SUB BX,4
NEG BX
CALL FREP_GetSequenceLen
POP BX
JMP FREP_FE_Loop
FREP_FE_LoopEnd:
POP CX
POP BX
JMP FREP_FE_OffLoop
FREP_FE_End:
POP CX
POP BX
POP ES
POP DI
RET
FREP_GetSequenceLen: ; in: DI+4: start of repetition; SI-1: thisbyte
PUSH DX ; BX: rel pos of DI
PUSH CX
PUSH SI
PUSH DI
ADD DI,5
MOV CX,BP
REPE CMPSB
NEG CX
ADD CX,BP
MOV DX,CX
CMP BX,0feffh
SBB DX,4
JC FREP_FE_TooShort
CMP DX,[relsave]
JC FREP_FE_TooShort
MOV [relsave],DX
MOV [relpos],BX
MOV [rellen],CX
FREP_FE_TooShort:
POP DI
POP SI
POP CX
POP DX
RET
WriteToTemp:
CMP DX,33000
JNC WTOT_Ret
INC DX
STOSB
WTOT_Ret:
RET
EncodeHuffman: ; DS:SI, ES:DI, CX: unpacked len
PUSH DX ; DX: max packed len
PUSH SI ; returns packed len in CX
PUSH DI ; and modifies pckflg
MOV [huffuplen],CX
CALL CountBytes
CALL GenTrie
CALL CalcLengths
CALL MakeCodes
CALL WriteCodes
CMP [Fault],0
JE ECOH_StartEncoding
JMP ECOH_Ooops
ECOH_StartEncoding:
XOR BX,BX
MOV [bitpos],0
ECOH_Loop:
XOR AH,AH
LODSB
TEST [pckflg],1
JZ ECOH_NormByte
CMP AL,255
JNE ECOH_NormByte
LODSB
DEC CX
CMP AL,255
JE ECOH_NormByte
MOV AH,1
PUSH AX
CALL EncodeByte
POP AX
XOR BP,BP
RCR AL,1
ADC BP,1
RCR AL,1
ADC BP,1
ECOH_ForceNorm:
XOR AH,AH
LODSB
CALL EncodeByte
DEC CX
DEC BP
JNE ECOH_ForceNorm
JMP ECOH_LoopEnd
ECOH_NormByte:
CALL EncodeByte
ECOH_LoopEnd:
CMP [Fault],0
JNE ECOH_Ooops
LOOP ECOH_Loop
CALL WriteLastHuffman
OR [pckflg],80h
JMP ECOH_Ret
ECOH_Ooops:
POP DI
POP SI
POP CX
MOV CX,[huffuplen]
PUSH CX
PUSH SI
PUSH DI
REP MOVSB
XOR DX,DX
ECOH_Ret:
POP DI
POP SI
POP CX
SUB CX,DX
RET
EncodeByte:
PUSH SI
PUSH DS
PUSH CX
MOV SI,SEG pckflg
MOV DS,SI
MOV SI,OFFSET code
ADD SI,AX
ADD SI,AX
MOV AX,[SI]
MOV CX,[bitpos]
PUSH AX
SHR AX,CL
OR BX,AX
POP AX
SUB SI,OFFSET code
ADD SI,OFFSET colen
ADD CX,[SI]
CMP CX,16
JC ECOB_BitLenOK
MOV [ES:DI],BH
MOV [ES:DI+1],BL
ADD DI,2
SUB DX,2
CMP DX,2
JC ECOB_Fault
SUB CX,[SI]
NEG CX
ADD CX,16
SHL AX,CL
MOV BX,AX
NEG CX
ADD CX,[SI]
AND CX,15
JMP ECOB_BitLenOK
ECOB_Fault:
MOV [Fault],1
ECOB_BitLenOK:
MOV [bitpos],CX
POP CX
POP DS
POP SI
RET
WriteLastHuffman:
PUSH DS
MOV AX,SEG bitpos
MOV DS,AX
CMP [bitpos],0
JE WLHU_Ret
MOV AL,BH
STOSB
DEC DX
CMP [bitpos],8
JC WLHU_Ret
MOV AL,BL
STOSB
DEC DX
WLHU_Ret:
POP DS
RET
CountBytes:
PUSH ES
PUSH SI
PUSH CX
PUSH DX
MOV AX,SEG tempbuf
MOV ES,AX
COBY_Loop:
XOR AH,AH
LODSB
TEST [pckflg],1
JZ COBY_NormByte
CMP AL,255
JNE COBY_NormByte
LODSB
CMP AL,255
JE COBY_NormByte
MOV AH,1
MOV BX,OFFSET bytecnt
ADD BX,AX
ADD BX,AX
INC [WORD PTR BX]
XOR DX,DX
RCR AL,1
ADC DX,1
RCR AL,1
ADC DX,1
XOR AH,AH
COBY_ForceNorm:
LODSB
MOV BX,OFFSET bytecnt
ADD BX,AX
ADD BX,AX
INC [WORD PTR BX]
DEC CX
DEC DX
JNE COBY_ForceNorm
JMP COBY_LoopEnd
COBY_NormByte:
MOV BX,OFFSET bytecnt
ADD BX,AX
ADD BX,AX
INC [WORD PTR BX]
COBY_LoopEnd:
LOOP COBY_Loop
POP DX
POP CX
POP SI
POP ES
RET
GenTrie:
PUSH DX
PUSH CX
PUSH SI
PUSH DI
PUSH DS
MOV AX,SEG Trie
MOV DS,AX
MOV DI,OFFSET Trie
MOV SI,OFFSET bytecnt
MOV CX,260
XOR BX,BX
MOV BP,0
GETR_Loop1:
LODSW
OR AX,AX
JE GETR_CountIszero
MOV [DI+0],BP
MOV [WORD PTR DI+2],0
MOV [WORD PTR DI+4],0
MOV [DI+6],AX ; 6: count
MOV [DI+8],BX ; 8: value
MOV BP,DI
ADD DI,10
GETR_CountIsZero:
INC BX
LOOP GETR_Loop1
MOV [Triestart],BP
MOV [FreeNodes],DI ; initialize free node list
MOV [WORD PTR DI],0
GETR_Loop2: ; build the tree
MOV SI,[Triestart]
CMP [WORD PTR SI],0
JNE GETR_DoLoop2
JMP GETR_L2Finished
GETR_DoLoop2:
MOV BX,SI
MOV SI,[SI]
MOV DI,SI
GETR_Loop3: ; find the two nodes with minimum
MOV DX,[DI+6] ; count entries
CMP DX,[BX+6]
JC GETR_BXDIOK
PUSH BX
MOV BX,DI
POP DI
GETR_BXDIOK:
MOV SI,[SI]
CMP SI,0
JE GETR_L3Finished
MOV DX,[SI+6]
CMP DX,[BX+6]
JNC GETR_Loop3
MOV BX,SI
JMP GETR_Loop3
GETR_L3Finished:
MOV SI,OFFSET Triestart
GETR_Loop4: ; remove these nodes from trie
CMP [WORD PTR SI],0
JE GETR_Loop4Finished
GETR_L4_Check:
CMP [SI],BX
JNE GETR_L4_NotBX
MOV BP,[BX]
MOV [SI],BP
JMP GETR_L4_Check
GETR_L4_NotBX:
CMP [SI],DI
JNE GETR_L4_NotDI
MOV BP,[DI]
MOV [SI],BP
JMP GETR_L4_Check
GETR_L4_NotDI:
MOV SI,[SI]
JMP GETR_Loop4
GETR_Loop4Finished:
MOV SI,[FreeNodes] ; get a free node
MOV AX,[SI]
MOV [FreeNodes],AX
MOV AX,[Triestart]
MOV [SI],AX
MOV [Triestart],SI
MOV DX,[BX+6] ; and initialize it
ADD DX,[DI+6]
MOV [SI+6],DX
MOV [WORD PTR SI+8],0ffffh
CMP [WORD PTR BX+8],0
JS GETR_NewLeftBranch
MOV AX,[FreeNodes]
MOV [BX],AX
MOV [FreeNodes],BX
MOV BX,[BX+8]
XOR [WORD PTR SI+8],4000h
GETR_NewLeftBranch:
MOV [SI+2],BX
CMP [WORD PTR DI+8],0
JS GETR_NewRightBranch
MOV AX,[FreeNodes]
MOV [DI],AX
MOV [FreeNodes],DI
MOV DI,[DI+8]
XOR [WORD PTR SI+8],2000h
GETR_NewRightBranch:
MOV [SI+4],DI
JMP GETR_Loop2
GETR_L2Finished:
POP DS
POP DI
POP SI
POP CX
POP DX
RET
CalcLengths:
PUSH SI
XOR AX,AX
MOV SI,[TrieStart]
CMP [WORD PTR FS:SI+8],0
JNS CLCL_OnlyOneByte
CALL CLCL_Recur
JMP CLCL_Ret
CLCL_OnlyOneByte:
MOV BX,[FS:SI+6]
ADD BX,BX
MOV [BX+colen],1
CLCL_Ret:
POP SI
RET
CLCL_Recur:
INC AX
PUSH SI
TEST [WORD PTR FS:SI+8],4000h
JNZ CLCL_RightDeeper
MOV BX,[FS:SI+2]
ADD BX,BX
MOV [BX+colen],AX
JMP CLCL_RightEnd
CLCL_RightDeeper:
MOV SI,[FS:SI+2]
CALL CLCL_Recur
CLCL_RightEnd:
POP SI
PUSH SI
TEST [WORD PTR FS:SI+8],2000h
JNZ CLCL_LeftDeeper
MOV BX,[FS:SI+4]
ADD BX,BX
MOV [BX+colen],AX
JMP CLCL_LeftEnd
CLCL_LeftDeeper:
MOV SI,[FS:SI+4]
CALL CLCL_Recur
CLCL_LeftEnd:
POP SI
DEC AX
RET
MakeCodes:
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSH CX
PUSH DX
MOV AX,SEG colen
MOV DS,AX
MOV ES,AX
MOV BP,8000h ; codeadd
MOV DX,0 ; code
MOV AX,1 ; clen
MOV SI,0 ; offset to codetab
MOV BX,0 ; mask
MACO_Loop:
ADD BX,BP
MOV DI,OFFSET colen
MOV CX,MAX_VAL+1
MACO_InnerLoop:
REPNE SCASW
JNE MACO_LengthOK
PUSH BX
MOV BX,DI
SUB BX,2+OFFSET colen
MOV [BX+code],DX
POP BX
MOV [SI+codetab],DX
MOV [SI+masktab],BX
ADD SI,2
ADD DX,BP
JCXZ MACO_LengthOK
JMP MACO_InnerLoop
MACO_LengthOK:
ROR BP,1
INC AX
CMP AX,16
JNE MACO_Loop
POP DX
POP CX
POP ES
POP DS
POP SI
POP DI
RET
WriteCodes:
PUSH CX
PUSH DS
MOV BX,SEG colen
MOV DS,BX
MOV BX,0
MOV CX,MAX_VAL+1
INC CX
SHR CX,1
WRCO_Loop:
MOV AX,[BX+colen]
SHL AX,4
OR AX,[BX+colen+2]
ADD BX,4
SUB DX,1
JNC WRCO_Write
MOV [Fault],1
JMP WRCO_End
WRCO_Write:
STOSB
LOOP WRCO_Loop
WRCO_End:
POP DS
POP CX
RET
; **************************************** decrunch
UnPackArea: ; DS:SI packed data ES:DI buffer CX buflen
PUSH FS ; out: CF set on error, AX unpacked len
MOV AX,SEG bitpos
MOV FS,AX
CALL Initialize
CALL GetUPparms
JNC UPAC_contd
JMP UPAC_Ret
UPAC_contd:
PUSH CX
PUSH ES
PUSH DI
PUSH SEG tempbuf
POP ES
MOV DI,OFFSET tempbuf
TEST [pckflg],80h
JZ UPAC_Loop
CALL ReadCodeLens
CALL MakeCodes
UPAC_Loop:
CALL ReadPackedByte
TEST [pckflg],1
JZ UPAC_SimpleWrite
UPAC_UnpackSeq:
CMP AL,255
JNE UPAC_SimpleWrite
CALL ReadPackedByte
CMP AL,255
JE UPAC_SimpleWrite
PUSH CX
MOV DL,AL
CALL JustReadPackedByte
MOV BL,AL
MOV BH,255
TEST DL,2
JZ UPAC_RelOK
CALL JustReadPackedByte
MOV BH,AL
UPAC_RelOK:
CALL JustReadPackedByte
MOV CL,AL
XOR CH,CH
TEST DL,1
JZ UPAC_LenOK
CALL JustReadPackedByte
MOV CH,AL
UPAC_LenOK:
POP DX
CMP DX,CX
JC UPAC_SeqFault ; a bowl of spaghetti
PUSH DX
PUSH DS
PUSH SI
PUSH ES
POP DS
MOV SI,DI
ADD SI,BX
ADD CX,4
MOV DX,CX
REP MOVSB
POP SI
POP DS
POP CX
SUB CX,DX
INC CX
JMP UPAC_LoopEnd
UPAC_SeqFault:
MOV CX,8000h
JMP UPAC_LoopEnd
UPAC_SimpleWrite:
STOSB
UPAC_LoopEnd:
DEC CX
JS UPAC_Unpacked
JNE UPAC_Loop
UPAC_Unpacked:
POP DI
POP ES
POP DX
OR CX,CX
JNE UPAC_Fault
PUSH DS
MOV SI,SEG tempbuf
MOV DS,SI
MOV SI,OFFSET tempbuf
MOV CX,DX
REP MOVSB
MOV AX,DX
POP DS
CLC
JMP UPAC_Ret
UPAC_Fault:
XOR AX,AX
STC
UPAC_Ret:
POP FS
RETF
GetUPParms:
PUSH ES
MOV AX,SEG tempbuf
MOV ES,AX
CMP [WORD PTR SI],'RC' ; magic word: CRUXPACK
JNE GUPA_End
CMP [WORD PTR SI+2],'XU'
JNE GUPA_End
CMP [WORD PTR SI+4],'AP'
JNE GUPA_End
CMP [WORD PTR SI+6],'KC'
JNE GUPA_End
MOV AX,[SI+8]
MOV [pckflg],AX
OR AH,AH ; version 0
JNZ GUPA_End
CMP CX,[SI+10]
JC GUPA_End
MOV CX,[SI+10]
ADD SI,12
CLC
JMP GUPA_Ret
GUPA_End:
STC
GUPA_Ret:
POP ES
RET
ReadCodeLens:
PUSH CX
PUSH ES
MOV CX,SEG colen
MOV ES,CX
MOV [HuffSpc],0ffffh
MOV [bitpos],0
MOV BX,0
MOV CX,MAX_VAL+1
INC CX
SHR CX,1
XOR AX,AX
RCOL_Loop:
LODSB
MOV DX,AX
SHR DX,4
AND AX,15
MOV [BX+colen],DX
MOV [BX+colen+2],AX
ADD BX,4
LOOP RCOL_Loop
POP ES
POP CX
RET
ReadPackedByte:
TEST [pckflg],80h
JNZ RPAB_Huff
LODSB
RET
RPAB_Huff:
CMP [HuffSpc],0ffffh
JE RPAB_HUFF_NoSpecial
MOV AX,[HuffSpc]
MOV [HuffSpc],0ffffh
RET
RPAB_HUFF_NoSpecial:
PUSH CX
PUSH DX
PUSH BX
MOV AX,[SI]
ROL AX,8
MOV CX,[bitpos]
SHL AX,CL
MOV DX,[SI+2]
ROL DX,8
NEG CX
ADD CX,16
SHR DX,CL
OR AX,DX
MOV BX,0
RPAB_HUFF_FindCode:
MOV DX,AX
AND DX,[BX+masktab]
CMP DX,[BX+codetab]
JE RPAB_Huff_FoundCode
ADD BX,2
JMP RPAB_HUFF_FindCode
RPAB_HUFF_FoundCode:
MOV DX,[BX+codetab]
MOV BX,0
RPAB_HUFF_FindByte:
CMP [BX+colen],0
JZ RPAB_HUFF_NotThis
CMP DX,[BX+code]
JE RPAB_HUFF_FoundByte
RPAB_HUFF_NotThis:
ADD BX,2
JMP RPAB_HUFF_FindByte
RPAB_HUFF_FoundByte:
MOV DX,[BX+colen]
ADD [bitpos],DX
CMP [bitpos],16
JC RPAB_HUFF_BPosOK
AND [bitpos],15
ADD SI,2
RPAB_HUFF_BPosOK:
MOV AX,BX
SHR AX,1
CMP AX,0ffh
JC RPAB_HUFF_AllOK
TEST [pckflg],1
JZ RPAB_Huff_AllOK
XOR AH,AH
MOV [HuffSpc],AX
MOV AX,0ffh
RPAB_HUFF_AllOK:
POP BX
POP DX
POP CX
RET
JustReadPackedByte:
TEST [pckflg],80h
JNZ JRPAB_Huff
LODSB
RET
JRPAB_Huff:
PUSH CX
PUSH DX
PUSH BX
MOV AX,[SI]
ROL AX,8
MOV CX,[bitpos]
SHL AX,CL
MOV DX,[SI+2]
ROL DX,8
NEG CX
ADD CX,16
SHR DX,CL
OR AX,DX
MOV BX,0
JRPAB_HUFF_FindCode:
MOV DX,AX
AND DX,[BX+masktab]
CMP DX,[BX+codetab]
JE JRPAB_Huff_FoundCode
ADD BX,2
JMP JRPAB_HUFF_FindCode
JRPAB_HUFF_FoundCode:
MOV DX,[BX+codetab]
MOV BX,0
JRPAB_HUFF_FindByte:
CMP [BX+colen],0
JZ JRPAB_HUFF_NotThis
CMP DX,[BX+code]
JE JRPAB_HUFF_FoundByte
JRPAB_HUFF_NotThis:
ADD BX,2
JMP JRPAB_HUFF_FindByte
JRPAB_HUFF_FoundByte:
MOV DX,[BX+colen]
ADD [bitpos],DX
CMP [bitpos],16
JC JRPAB_HUFF_BPosOK
AND [bitpos],15
ADD SI,2
JRPAB_HUFF_BPosOK:
MOV AX,BX
SHR AX,1
POP BX
POP DX
POP CX
RET
LoadPackedFile:
CALL Initialize
RETF
Initialize:
PUSH CX
PUSH DI
PUSH ES
PUSH SEG packer_d_start
POP ES
MOV DI,OFFSET packer_d_start
MOV CX,packer_d_end-packer_d_start
XOR AX,AX
REP STOSB
POP ES
POP DI
POP CX
RET
ENDS
SEGMENT packer_data PRIVATE PARA 'DATEN'
LABEL packer_d_start WORD
bytecnt DW 300 DUP (0)
colen DW 300 DUP (0)
code DW 300 DUP (0)
codetab DW 300 DUP (0)
masktab DW 300 DUP (0)
huffuplen DW ?
pckflg DW ?
relpos DW ?
rellen DW ?
relsave DW ?
HuffSpc DW ?
bitpos DW ?
Fault DW ?
FreeNodes DW ?
TrieStart DW ?
Trie DB 10*310 DUP (?)
tempbuf DB 33000 DUP (?)
LABEL packer_d_end WORD
ENDS
END