sprinter-unzip/unzip.asm
2024-06-21 09:43:51 +03:00

2322 lines
44 KiB
NASM

; ====================================================
; PKUNZIP utility for Sprinter version 0.7
; Created by Aleksey Gavrilenko 09.02.2002
; Procedure deflate by Michail Kondratyev
; ====================================================
; Set to 1 to turn debug ON with DeZog VSCode plugin
; Set to 0 to compile .EXE
DEBUG EQU 0
EXE_VERSION EQU 0
SLDOPT COMMENT WPMEM, LOGPOINT, ASSERTION
DEVICE NOSLOT64K
IF DEBUG == 1
include "bios.asm"
include "test_data.asm"
DS 0x80, 0
ENDIF
; DSS RST Entry
DSS EQU 0x10
; DSS Functions
DSS_CREATE_FILE EQU 0x0B
DSS_OPEN_FILE EQU 0x11
DSS_CLOSE_FILE EQU 0x12
DSS_READ_FILE EQU 0x13
DSS_WRITE EQU 0x14
DSS_MOVE_FP_CP EQU 0x0115
DSS_FIND_FIRST EQU 0x0119
DSS_FIND_NEXT EQU 0x011A
DSS_MKDIR EQU 0x1B
DSS_CHDIR EQU 0x1D
DSS_CURDIR EQU 0x1E
DSS_EXIT EQU 0x41
DSS_PCHARS EQU 0x5C
; DSS Error codes
E_FILE_EXISTS EQU 7
E_FILE_NOT_FOUND EQU 3
; Memory pages
PAGE0_ADDR EQU 0x0000
PAGE1_ADDR EQU 0x4000
PAGE2_ADDR EQU 0x8000
PAGE3_ADDR EQU 0xC000
; Sprinter ports
; to switch mem pages
PAGE0 EQU 0x82
PAGE1 EQU 0xA2
PAGE2 EQU 0xC2
PAGE3 EQU 0xE2
BRD_SND EQU 0xFE ; WR_BRD?
; Other
; Max number of Code Length codes
NR_CL EQU 19
MAX_CL EQU 16
NR_LIT EQU 288
NR_DIST EQU 32
ORG 0x8080
EXE_HEADER
DB "EXE"
DB EXE_VERSION ; EXE Version
DW 0x0080 ; Code offset
DW 0
DW 0 ; Primary loader size
DW 0 ; Reserved
DW 0
DW 0
DW START ; Loading Address
DW START ; Entry Point
DW STACK_TOP ; Stack address
DS 106, 0 ; Reserved
ORG 0x8100
STACK_TOP
; ====================================================
; MAIN Entry point
; ====================================================
START
IF DEBUG == 1
LD IX,CMD_LINE2
ENDIF
PUSH IX ; IX ptr to cmd line
POP HL
INC HL ; Skip size of Command line
LD DE,PATH_INPUT
CALL GET_CMD_PARAM
JR C,INVALID_CMDLINE
LD DE,PATH_OUTPUT
CALL GET_CMD_PARAM
JR NC,IS_SEC_PAR
LD HL,PATH_INPUT ; In and out is same
LD DE,PATH_OUTPUT
LD BC,256
LDIR
IS_SEC_PAR
; split path and file name
LD HL,PATH_OUTPUT
CALL SPLIT_PATH_FILE
JR START_L1
INVALID_CMDLINE
LD HL,START_MESSAGE ; "PKUNZIP utility for Sprinter
LD C,DSS_PCHARS
RST DSS
LD BC,DSS_EXIT
RST DSS
START_L1
LD A,(PATH_INPUT) ; ToDo: No parameters, It is already checked before?
AND A
JR Z,INVALID_CMDLINE
LD HL,START_MESSAGE ; "PKUNZIP utility for Sprinter
LD C,DSS_PCHARS
RST DSS
LD HL,PATH_INPUT
CALL SPLIT_PATH_FILE ; get zip file path and name from first cmd line parameter
JP C,ERR_FILE_OP
LD HL,MSG_INP_PATH ; "Input path:"
LD C,DSS_PCHARS
RST DSS
LD HL,PATH_INPUT
LD C,DSS_PCHARS
RST DSS
LD HL,MSG_EOL ; '\r'
LD C,DSS_PCHARS
RST DSS
LD HL,MSG_OUT_PATH ; "Out path:"
LD C,DSS_PCHARS
RST DSS
LD HL,PATH_OUTPUT
LD C,DSS_PCHARS
RST DSS
LD HL,MSG_EOL ; '\r'
LD C,DSS_PCHARS
RST DSS
IN A,(PAGE0)
LD (SAVE_P0),A
; Change dir to input file directory
LD HL,PATH_INPUT
LD C,DSS_CHDIR
RST DSS
JP C,ERR_FILE_OP
; Find first file by specified name or mask (*.zip for example)
LD HL,FILE_SPEC
LD DE,FF_WORK_BUF ; Work buffer
LD BC,DSS_FIND_FIRST ; FIND_FIRST
LD A,0x2f ; Attrs
RST DSS
JP C,ERR_FILE_OP ; File not found
JR OPEN_ZIP_FILE
; ----------------------------------------------------
DO_NEXT_FILE
LD DE,FF_WORK_BUF
LD BC,DSS_FIND_NEXT ; FIND_NEXT
RST DSS
JR NC,OPEN_ZIP_FILE
CP E_FILE_NOT_FOUND
JP NZ,ERR_FILE_OP
LD HL,MSG_DEPAC_COMPLT ; "\r\nDepaking complited\r\n\n"
LD C,DSS_PCHARS
RST DSS
LD BC,DSS_EXIT
RST DSS
OPEN_ZIP_FILE
LD HL,FF_FILE_NAME
XOR A
LD C,DSS_OPEN_FILE
RST DSS
JP C,ERR_FILE_OP
LD (FH_INP),A
LD HL,MSG_DEPAC_FILE ; "Depaking file: "
LD C,DSS_PCHARS
RST DSS
LD HL,FF_FILE_NAME
LD C,DSS_PCHARS
RST DSS
RD_LOCAL_HDR
CALL READ_HEADERS
JR C,ERR_IN_ZIP
AND A ; it is LFH?
JP Z,DO_OUT_FNAME
; it is not local file header, but central directory
; close input file and go to next file
CLOSE_AND_NXT
LD A,(FH_INP)
LD C,DSS_CLOSE_FILE
RST DSS
JP C,ERR_FILE_OP
XOR A
LD (FH_INP),A
JR DO_NEXT_FILE
ERR_IN_ZIP
LD HL,MSG_ERR_IN_ZIP ; "\r\nError in ZIP!\r\n"
LD C,DSS_PCHARS
RST DSS
JR CLOSE_AND_NXT
; Build full file name from output path and zip local header
DO_OUT_FNAME
LD HL,PATH_OUTPUT
LD DE,TEMP_BUFFR
LD BC,256
LDIR
LD HL,MSG_EOL ; '\r'
LD C,DSS_PCHARS
RST DSS
LD HL,TEMP_BUFFR
XOR A
; find end of path
FND_PATH_CPY_END
CP (HL) ; HL => TEMP_BUFFR
JR Z,END_PATH_CPY
INC HL
JR FND_PATH_CPY_END
; check last symbol is '\'' and add if not
END_PATH_CPY
DEC HL
LD A,(HL)
CP "\\"
JR Z,IS_DIR_SEP
INC HL
LD (HL),"\\"
IS_DIR_SEP
INC HL
LD (HL),0x0 ; mark end of string
LD DE,ENTRY_FILE_NAME
ADD_FNAME_TO_PATH
LD A,(DE) ; =>ENTRY_FILE_NAME
LD (HL),A ; =>TEMP_BUFFR + 1
INC HL
INC DE
; check end of file name
AND A
JR NZ,ADD_FNAME_TO_PATH
; replace UNIX slash to DOS back slash
LD HL,TEMP_BUFFR
CHK_SLASH
LD A,(HL) ; HL => TEMP_BUFFR
CP '/'
JR NZ,SYM_NO_BSLASH
LD (HL),"\\"
SYM_NO_BSLASH
INC HL
AND A
JR NZ,CHK_SLASH
; Output compression method to screen
LD HL,(LH_PARAMS)
LD A,H
OR A
JR NZ,COMP_PARAMS_EMP
LD A,L
CP 9
JR NC,COMP_PARAMS_EMP
LD HL,MSG_STORED ; "Stored: "
AND A
JR Z,OUT_COMP_MSG
LD HL,MSG_UNSHRINK ; "Unshrinkin: "
DEC A
JR Z,OUT_COMP_MSG
LD HL,MSG_REDUCED ; "Reduced: "
DEC A
JR Z,OUT_COMP_MSG
DEC A
JR Z,OUT_COMP_MSG
DEC A
JR Z,OUT_COMP_MSG
DEC A
JR Z,OUT_COMP_MSG
LD HL,MSG_IMPLODING ; "Imploding: "
DEC A
JR Z,OUT_COMP_MSG
LD HL,MSG_TOKENIZING ; "Tokenizing: "
DEC A
JR Z,OUT_COMP_MSG ; Method 8 - Deflate|Inflate
LD HL,MSG_INFLATING ; "Inflanting: "
OUT_COMP_MSG
LD C,DSS_PCHARS
RST DSS ; Out compression type
LD HL,TEMP_BUFFR ; Out output file name
LD C,DSS_PCHARS
RST DSS
LD A,(LH_PARAMS)
AND A
JR Z,C_SUPPORTED
CP 8 ; DEFLATE
JR Z,C_SUPPORTED
LD HL,MSG_RESERVD_METHOD ; " Reserved metod!"
LD C,DSS_PCHARS
RST DSS
; move file pointer to next local header in zip file
MV_TO_NEXT_LH
LD HL,(LH_COMP_SIZE_H)
LD IX,(LH_COMP_SIZE_L)
LD BC,DSS_MOVE_FP_CP ; MOVE_FP from Current Pos
LD A,(FH_INP)
RST DSS
JP C,ERR_FILE_OP
JP RD_LOCAL_HDR
COMP_PARAMS_EMP
LD HL,MSG_UNKNOWN ; "Unknown: "
LD C,DSS_PCHARS
RST DSS
JR MV_TO_NEXT_LH
DIR_OR_EMPTY
LD HL,TEMP_BUFFR
CALL MAKE_FILE_PATH
OUT (BRD_SND),A
JP C,ERR_FILE_OP
JP RD_LOCAL_HDR
; Supported compression method. Stored or Deflate
C_SUPPORTED
LD HL,(LH_COMP_SIZE_L)
LD (BYTES_REMAINS_L),HL
LD DE,(LH_COMP_SIZE_H)
LD (BYTES_REMAINS_H),DE
LD HL,0xffff
LD (CRC32_L),HL
LD (CRC32_H),HL
LD HL,0x0
LD (DW_COUNTER_L),HL
LD (DW_COUNTER_H),HL
LD HL,(LH_COMP_SIZE_L)
LD DE,(LH_COMP_SIZE_H)
LD A,H
OR L
OR D
OR E
JR Z,DIR_OR_EMPTY
LD HL,TEMP_BUFFR
; check end of file name for '\'
XOR A
LD BC,0x80
CPIR ; Find end of string (zero byte)
DEC HL
DEC HL ; HL points to last string char
LD A,(HL) ; HL => TEMP_0
CP "\\" ; it is directory separator?
JR Z,DIR_OR_EMPTY
; create output file and jump to ok, or try to create dir
; and then create output file
LD HL,TEMP_BUFFR
XOR A
LD C,DSS_CREATE_FILE
RST DSS
JR NC,OK_CREATE_FILE
CP E_FILE_EXISTS ; FM = 7?
JR Z,ERR_FILE_EXIST
; separate output file path and name
LD HL,TEMP_BUFFR
CALL SPLIT_PATH_FILE
JP C,ERR_FILE_OP
; make output directory
LD HL,TEMP_BUFFR ; HL => output file path
CALL MAKE_FILE_PATH
JP C,ERR_FILE_OP
; change dir to output directory
LD HL,TEMP_BUFFR
LD C,DSS_CHDIR
RST DSS
JP C,ERR_FILE_OP
; create output file
LD HL,FILE_SPEC
XOR A
LD C,DSS_CREATE_FILE
RST DSS
JR NC,OK_CREATE_FILE
CP E_FILE_EXISTS
JP NZ,ERR_FILE_OP
; If file exists, notify user, and jump to next file
ERR_FILE_EXIST
LD HL,MSG_FILE_EXISTS ; " File exists!"
LD C,DSS_PCHARS
RST DSS
JP MV_TO_NEXT_LH
OK_CREATE_FILE
LD (FH_OUT),A
CALL FL_DECOMP ; Call decompression routine
LD B,0x4
LD DE,LH_CRC32
LD HL,CRC32_L
LD B,0x4 ; TODO: Remove exltra B=4
; Compare CRC32 from header and calculated for output file
CRC_CMP
LD A,(DE) ; DE => LH_CRC32
XOR (HL) ; HL => CRC32
INC HL
INC DE
INC A
JR NZ, CRC_CHK_ERR
DJNZ CRC_CMP
; CRC Ok, close output file and go to next header
LD HL, MSG_OK_CR_LF ; ' '
LD C, DSS_PCHARS
RST DSS
LD A,(FH_OUT)
LD C, DSS_CLOSE_FILE
RST DSS
JP C,ERR_FILE_OP
XOR A
LD (FH_OUT),A ; mark File Manipulator as 0 - closed
JP RD_LOCAL_HDR
CRC_CHK_ERR
; Notify user about possible error and go to next header
LD HL,MSG_ERR_CRC ; " Error CRC!"
LD C,DSS_PCHARS
RST DSS
LD A,(FH_OUT)
LD C,DSS_CLOSE_FILE
RST DSS
JP C,ERR_FILE_OP
JP RD_LOCAL_HDR
; ----------------------------------------------------
; ZIP Local File Header:
; +0 sw Signature 0x04034b50
; +2 w Version to extract
; +4 w general purpose flag
; +8 w compression method
; +10 w MTIME
; +12 w MDATE
; +14 dw CRC32
; +18 dw Compressed Size
; +22 dw UncompressedSize
; +26 w FileName Len (n)
; +28 w Extra field Len (m)
; +30 n FileName
; +30+n m Extra Field
; ----------------------------------------------------
; STRUCT LH_PARAM_STRUCT
; VERSION WORD
; GPP_FLAG WORD
; COMP_METHOD WORD
; MTIME WORD
; MDATE WORD
; CRC32 DWORD
; COMP_SIZE DWORD
; UCOMP_SIZE DWORD
; FNAME_LEN WORD
; EXTRA_LEN WORD
; FILENAME BYTE
; ENDS
; ----------------------------------------------------
; Read local file header to buffer
; Out: CF=0 - Ok
; A=0x00 - for LocalHileHeader
; A=0xff - for CentralDirectory
; CF=1 - Error
; ----------------------------------------------------
READ_HEADERS
LD A,(FH_INP)
LD HL,TEMP_BUFFR ; DST ADDR
LD DE,30 ; BYTES COUNT
LD C,DSS_READ_FILE
RST DSS
JP C,ERR_FILE_OP
; Check Local file header signature 0x04034b50
LD IX,TEMP_BUFFR
LD A,(IX+0) ; IX =>TEMP_BUFFR
CP 50h
JR NZ,ERR_LH_SIGN
LD A,(IX+1)
CP 4Bh
JR NZ,ERR_LH_SIGN
LD A,(IX+2)
CP 03h
JP NZ,NO_LOCAL_FH ; TODO: Check it!
LD A,(IX+3)
CP 04h
JR NZ,ERR_LH_SIGN
LD HL,TEMP_BUFFR+8 ; From compression method to unc
LD DE,LH_PARAMS ; move to LH_PARAMS
LD BC,18
LDIR
LD E,(IX+0x1A) ; offset LH_FN_LEN_L
LD D,(IX+0x1B) ; offset LH_FN_LEN_H
PUSH DE ; File Name Len
LD HL,LH_FILENAME ; File Name ptr
LD A,(FH_INP)
LD C,DSS_READ_FILE
RST DSS
JP C,ERR_FILE_OP
POP DE
LD HL,LH_FILENAME
ADD HL,DE
LD (HL),0x0 ; Mark end of string fileName
LD HL,LH_FILENAME
INC E
LD B,0x0
LD C,E
LD DE,ENTRY_FILE_NAME
LDIR
LD HL,LH_EXTRA_LEN_L ; Extra field len
LD E,(HL)
INC HL
LD D,(HL)
LD A,(GPP_FLAG) ; GPP Flag
AND 0x8 ; bit 3 flag, 1 - have optional data desc
JR Z,NO_DATA_DSCR
EX DE,HL
LD DE,12 ; Skip data descriptor (3 word)
; crc32 dw, compressedsize dw, size dw
ADD HL,DE
EX DE,HL
; no optrional data descriptor
NO_DATA_DSCR
LD HL,LH_FILENAME
LD A,(FH_INP)
LD C,DSS_READ_FILE
RST DSS
JP C,ERR_FILE_OP
XOR A
RET
ERR_LH_SIGN
SCF
RET
; it is non local file header
NO_LOCAL_FH
CP 0x01 ; it is CentralDirectory FH?
JR NZ,NO_CENTRAL_DIR
LD A,(IX+3) ; TMP_BUFFR+3
CP 0x02 ; valid sign 0x02014b50?
JR NZ,ERR_LH_SIGN
LD A,0xff
AND A
RET
NO_CENTRAL_DIR
CP 0x05 ; is End of central directory?
JR NZ,ERR_LH_SIGN
LD A,(IX+3) ; TMP_BUFFR+3
CP 0x06 ; valid sign 0x06054b50?
JR NZ,ERR_LH_SIGN
LD A,0xff
AND A
RET
; ----------------------------------------------------
; Read next command line parameter
; Inp: HL - pointer to cmd line position
; DE - pointer to buffer to place parameter
; Out: CF = 1 if no more parameters
; ----------------------------------------------------
GET_CMD_PARAM
PUSH DE
FIRST_SPACE
LD A,(HL)
INC HL
AND A
JR Z,PARAM_EOL
; skip first space
CP ' '
JR Z,FIRST_SPACE
DEC HL
PARAM_MOV
; move parameter to buffer pointed by DE byte by byte
; until space or 0 reached
LD A,(HL)
AND A
JR Z,PARAM_EOL
CP ' '
JR Z,PARAM_EOL
LD (DE),A
INC HL
INC DE
JR PARAM_MOV
PARAM_EOL
; set end of string marker 0 at parameter end
XOR A
LD (DE),A
POP DE
; if parameter is empty, return CF=1
LD A,(DE)
AND A
RET NZ
SCF
RET
; ----------------------------------------------------
; Split filepath for path and file specification
; (file name, or mask *.zip)
; Inp: HL - Ptr to filepath, zero ended
; Out: CF=1 - Error
; CF=0 - FILE_SPEC and trunc filepath to path
; ----------------------------------------------------
SPLIT_PATH_FILE
PUSH HL
; check next 128 bytes to find 0 - end of string
LD BC,0x0080
LD A,B
CPIR
LD A,C
AND A
JR NZ,EOS_FOUND
POP HL
; return error flag
LD A,0x10
SCF
RET
EOS_FOUND
; find back for last back slash \
LD C,0x80
LD A,"\\"
CPDR
LD A,C
AND A
JR NZ,BKSL_FOUND
POP HL
; copy 13 symbols of filepath to FILE_SPEC. 'filename.zip',0
LD BC,13
LD DE,FILE_SPEC
LDIR
AND A ; CF=0
RET
BKSL_FOUND
; path + filename
; copy filename to FILE_SPEC
INC HL ; HL => '\'
LD DE,FILE_SPEC
LD C,13
INC HL ; HL => first symbol of filename
PUSH HL
LDIR
POP HL
; mark path endto last symbol of path
LD (HL),0x0
POP HL
AND A ; CF=0
RET
; ----------------------------------------------------
MAKE_FILE_PATH
PUSH DE
PUSH BC
LD D,H
LD E,L
FIND_SPEC
LD A,(DE)
CP "\\"
JR Z,L_PATH_SPEC
CP ':'
JR Z,L_DRV_SPEC
AND A
JR Z,L_PATH_SPEC
CP ' '
JR Z,L_PATH_SPEC
INC DE
JR FIND_SPEC
L_DRV_SPEC
INC DE
INC DE
LD A,(DE)
CP ' '
JR Z,L_SPC_END
AND A
JR Z,L_SPC_END
JR FIND_SPEC
L_PATH_SPEC
LD A,(DE)
PUSH AF
PUSH DE
XOR A
LD (DE),A
DEC DE
LD A,(DE)
CP "\\"
SCF
CCF
JR Z,L_PATH_DS
PUSH HL
LD C,DSS_MKDIR
RST DSS
POP HL
L_PATH_DS
POP DE
JR NC,L_DIR_NOT_EXST
CP 0xf ; Directory exist?
JR Z,L_DIR_NOT_EXST
LD L,A
POP AF
LD (DE),A
POP BC
POP DE
LD A,L
SCF
RET
L_DIR_NOT_EXST
POP AF
LD (DE),A
INC DE
AND A
JR Z,L_SPC_END
CP ' '
JR NZ,FIND_SPEC
L_SPC_END
POP BC
POP DE
XOR A
RET
; ----------------------------------------------------
; Main code Variables and Constants
; ----------------------------------------------------
; Local header parameters from zip file storage
LH_PARAMS:
LH_METHOD:
DW 0
LH_MTIME:
DW 0
LH_DATE:
DW 0
LH_CRC32:
DW 0,0
LH_COMP_SIZE_L:
DW 0
LH_COMP_SIZE_H:
DW 0
LH_UCOMP_SIZE_L:
DW 0
LH_UCOMP_SIZE_H:
DW 0
START_MESSAGE:
DB "PKUNZIP utility for Sprinter version 0.7\r\n"
DB "Created by Aleksey Gavrilenko 09.02.2002\r\n"
DB "Procedure deflate by Michail Kondratyev\r\n\r\n", 0
MSG_INP_PATH:
DB "Input path:", 0
MSG_OUT_PATH:
DB "Out path:", 0
MSG_EOL
DB "\r\n", 0
MSG_DEPAC_COMPLT:
DB "\r\nDepaking complited\r\n\n",0
MSG_DEPAC_FILE:
DB "Depaking file: ", 0
MSG_ERR_CRC:
DB " Error CRC!", 0
MSG_OK_CR_LF
DB " OK", 0
MSG_FILE_EXISTS:
DB " File exists!", 0
MSG_RESERVD_METHOD:
DB " Reserved metod!", 0
MSG_INFLATING
DB "Inflanting: ", 0
MSG_TOKENIZING
DB "Tokenizing: ", 0
MSG_IMPLODING
DB "Imploding: ", 0
MSG_REDUCED
DB "Reduced: ", 0
MSG_UNSHRINK
DB "Unshrinkin: ", 0
MSG_STORED
DB "Stored: ", 0
MSG_UNKNOWN
DB "Unknown: ", 0
MSG_WRONG_DEV
DB "Wrong device!\r\n", 0
MSG_FILE_NOT_FND
DB "File not found!\r\n", 0
MSG_WRONG_PATH
DB "Wrong path!\r\n", 0
MSG_FWRONG_FM
DB "Wrong file manipulator!\r\n", 0
MSG_NO_SPACE_FM
DB "Not space for file manipulator!\r\n", 0
MSG_FILE_EXISTS2
DB "File exist!\r\n", 0
MSG_RDONLY
DB "Read only!\r\n", 0
MSG_ERR_ROOT
DB "Error ROOT!\r\n", 0
MSG_NO_SPACE
DB "No space!\r\n", 0
MSG_PATH_EXISTS
DB "Path exists!\r\n", 0
MSG_WRONG_NAME
DB "Wrong name!\r\n", 0
MSG_FATAL_ERR
DB "Fatal error!\r\n", 0
MSG_ERR_IN_ZIP
DB "\r\nError in ZIP!\r\n", 0
MSG_BAD_TABLE
DB " File has bad table!", 0
; RAM page for decompression needsFindFi
WORK_P0
DB 0Ah
; To save memory PAGE0 state
SAVE_P0
DB 0
; File handler for input file
FH_INP
DB 0
; File handler for output file
FH_OUT
DB 0
; First parameter: Path to file
PATH_INPUT
DS 256, 0
; Second parameter: Path to .zip file
PATH_OUTPUT
DS 256, 0
; Work buffer for FindFist/FindNext op (256bytes)
FF_WORK_BUF
DS 33,0
FF_FILE_NAME
DS 223, 0
; Output file name from zip local header
ENTRY_FILE_NAME
DS 256, 0
FILE_SPEC
DS 13, 0
CRC32_L
DW 0
CRC32_H
DW 0
DW_COUNTER_L
DW 0
DW_COUNTER_H
DW 0
; ----------------------------------------------------
; End Main code Variables and Constants
; ----------------------------------------------------
; ----------------------------------------------------
; Load BC Bytes to (HL) from input file
; ----------------------------------------------------
LOAD_DATA_BLK
PUSH BC
POP DE
PUSH HL
BYTES_REMAINS_H+* LD IX,0x0
BYTES_REMAINS_L+* LD HL,0x0
LD A,IXH
OR IXL
JR NZ,L_IX_N0
PUSH HL
SBC HL,DE
POP HL
JR NC,L_IX_N0
LD E,L
LD D,H
L_IX_N0
OR A
SBC HL,DE
JR NC,LD_NXT_BLK
DEC IX
LD_NXT_BLK
LD (BYTES_REMAINS_H),IX
LD (BYTES_REMAINS_L),HL
LD A,D
OR E
POP HL
RET Z
LD A,(SAVE_P0) ; Restore Page0 before DSS call
OUT (PAGE0),A
LD C,DSS_READ_FILE
LD A,(FH_INP)
RST DSS
JP C,ERR_FILE_OP
DI
LD A,(WORK_P0) ; Restore our work Page0
OUT (PAGE0),A
RET
; ----------------------------------------------------
FL_DECOMP
LD A,(LH_PARAMS)
AND A
JP NZ,DECOMPRESS
; file stored without compression
DC_NEXT_BLK
LD HL,PAGE1_ADDR
LD BC,16384 ; BC - bytes to read
CALL UC_READ
LD A,D ; DE - bytes readed
OR E
RET Z
LD HL,PAGE1_ADDR
LD B,D
LD C,E
PUSH DE
CALL UPD_CRC
POP DE
LD HL,PAGE1_ADDR
; A - File handle; HL - buffer; DE - count
LD C,DSS_WRITE
LD A,(FH_OUT)
RST DSS
JP C,ERR_FILE_OP
JR DC_NEXT_BLK
; ----------------------------------------------------
; Read block of uncompressed data
; HL - buffer to out
; BC - count of bytes to read
; ----------------------------------------------------
UC_READ
PUSH BC
POP DE ; DE = BC
PUSH HL
LD IX,(BYTES_REMAINS_H)
LD HL,(BYTES_REMAINS_L)
LD A,IXH
OR IXL
JR NZ,RD_UNTL_END
PUSH HL
SBC HL,DE
POP HL
JR NC,RD_UNTL_END
LD E,L
LD D,H
RD_UNTL_END
OR A
SBC HL,DE
JR NC,RD_DE_BYTES
DEC IX
RD_DE_BYTES
LD (BYTES_REMAINS_H),IX
LD (BYTES_REMAINS_L),HL
LD A,D ; if DE != 0 -> read else ret
OR E
POP HL
RET Z
; HL - адрес в памяти
; DE - количество читаемых байт
LD C,DSS_READ_FILE
LD A,(FH_INP)
RST DSS
JP C,ERR_FILE_OP
RET
; ----------------------------------------------------
; Handle errors with file operations
; ----------------------------------------------------
ERR_FILE_OP
SUB 0x2
LD HL,MSG_WRONG_DEV ; "Wrong device!\r\n"
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_FILE_NOT_FND ; "File not found!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_WRONG_PATH ; "Wrong path!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_FWRONG_FM ; "Wrong file manipulator!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_NO_SPACE_FM ; "Not space for file manipulato
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_FILE_EXISTS2 ; "File exist!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_RDONLY ; "Read only!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_ERR_ROOT ; "Error ROOT!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_NO_SPACE ; "No space!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_PATH_EXISTS ; "Path exists!\r\n"
SUB 0x5
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_WRONG_NAME ; "Wrong name!\r\n"
DEC A
JR Z,ERR_MSG_AND_EXIT
LD HL,MSG_FATAL_ERR ; "Fatal error!\r\n"
; Output error message to screen and exit
ERR_MSG_AND_EXIT
LD C,DSS_PCHARS
RST DSS
LD A,(FH_INP)
AND A
JR Z,IF_ALRDY_CL
LD C,DSS_CLOSE_FILE
RST DSS
; Input file already closed
IF_ALRDY_CL
LD A,(FH_OUT)
AND A
JR Z,OF_ALRDY_CL
LD C,DSS_CLOSE_FILE
RST DSS
; Output file already closed
OF_ALRDY_CL
LD BC,DSS_EXIT
RST DSS
; - Terminate program
; ----------------------------------------------------
; Switch pages and do inflate
; ----------------------------------------------------
DECOMPRESS
DI
LD (SAVE_SP),SP
LD A,(WORK_P0) ; = 0Ah
OUT (PAGE0),A
CALL INFLATE
LD A,(SAVE_P0)
OUT (PAGE0),A
EI
RET
; ----------------------------------------------------
; ZIP file has invalid data format
; ----------------------------------------------------
F_HAS_BAD_TAB
SAVE_SP+* LD SP,0x0
LD HL,(NXT_WRD_PTR)
CALL WRITE_BUFF
LD A,(SAVE_P0)
OUT (PAGE0),A
EI
LD HL,MSG_BAD_TABLE ; " File has bad table!"
LD C,DSS_PCHARS
RST DSS
RET
; ----------------------------------------------------
; Inp: BC - count
; HL - addr
; Out: DE - Next word ptr
; ----------------------------------------------------
SUB_UNCOMP_7
LD A,C
OR B
RET Z
NXT_WRD_PTR+* LD DE,0x0000
HAZ_BYTEZ
LD A,(HL)
LD (DE),A
INC DE
PUSH DE
PUSH HL
LD (NXT_WRD_PTR),DE
LD HL,0x8000
OR A
SBC HL,DE
JR Z,NO_BYTEZ
POP HL
POP DE
CONT_BYTEZ
CPI ; CP A,(HL) DEC BC
JP PE,HAZ_BYTEZ
LD (NXT_WRD_PTR),DE
RET
NO_BYTEZ
CALL BUFF_IS_FULL
POP HL
POP DE
LD DE,(NXT_WRD_PTR)
JR CONT_BYTEZ
; ----------------------------------------------------
PUT_A_TO_BUFF
PUSH HL
LD HL,(NXT_WRD_PTR)
LD (HL),A
INC HL
LD (NXT_WRD_PTR),HL
LD A,H
CP 80h ; < 0x8000 ?
POP HL
RET C
; ----------------------------------------------------
BUFF_IS_FULL
PUSH HL
PUSH DE
PUSH BC
PUSH AF
LD HL,(NXT_WRD_PTR)
LD (NXT_WRD),HL
CALL FLUSH_BUFF
LD (NXT_WRD_PTR),HL
POP AF
POP BC
POP DE
POP HL
RET
INC_DW_COUNTER
PUSH HL
PUSH DE
PUSH AF
; inc (0x8b05) if wrapped, inc hi byte
LD HL,(DW_COUNTER_L)
LD DE,0x1
ADD HL,DE
LD (DW_COUNTER_L),HL
JR NC,SUNK_NO_WRAP
LD HL,(DW_COUNTER_H)
INC HL
LD (DW_COUNTER_H),HL
SUNK_NO_WRAP
POP AF
POP DE
POP HL
RET
; ----------------------------------------------------
; Load next block of compressed data to TEMP_BUFFR
; ----------------------------------------------------
LOAD_NXT_BLOCK
PUSH HL
PUSH DE
PUSH BC
PUSH IX
LD HL,TEMP_BUFFR
LD (TMP_BUFFER_ADDR),HL
LD BC,4095
CALL LOAD_DATA_BLK
POP IX
POP BC
POP DE
POP HL
RET
; ----------------------------------------------------
; Update CRC32
; HL - ptr to byte buffer
; BC - bytes in buffer
; ----------------------------------------------------
UPD_CRC
LD A,B
OR C
RET Z
PUSH HL
LD HL,(CRC32_H)
LD DE,(CRC32_L)
CRC_NXT_BYTE
EX (SP),HL
LD A,(HL)
INC HL
EX (SP),HL
XOR E
LD IXL,A
LD IXH,0x3F
ADD IX,IX
ADD IX,IX
LD A,D
XOR (IX+0x0) ; CRC32 Table ref 3F00*4=0xFC00
LD E,A
LD A,L
XOR (IX+0x1)
LD D,A
LD A,H
XOR (IX+0x2)
LD L,A
LD H,(IX+0x3)
DEC BC
LD A,C
OR B
JR NZ,CRC_NXT_BYTE
LD (CRC32_H),HL
LD (CRC32_L),DE
POP HL
RET
; ----------------------------------------------------
WRITE_BUFF
LD A,H
OR L
RET Z ; ret if HL=0
LD A,H
CP 0x40
JR NC,WR_4000 ; bytes > 0x4000?
EX DE,HL
PUSH DE
; Store P3, switch to out P3 and original P0
IN A,(PAGE3)
PUSH AF
LD A,(WORK_P0) ; =0Ah
OUT (PAGE3),A
LD A,(SAVE_P0)
OUT (PAGE0),A
; Write DC bytes from (HL) to A file handler
LD HL,PAGE3_ADDR
LD C,DSS_WRITE
LD A,(FH_OUT)
RST DSS
JP C,ERR_FILE_OP
; Restore P3 and our P0
POP AF
OUT (PAGE3),A
DI
LD A,(WORK_P0) ; = 0Ah
OUT (PAGE0),A
; Update CRC for buffer
POP BC
LD HL,0x0
CALL UPD_CRC
LD HL,0x0
RET
WR_4000
PUSH HL
; Store P3, switch to out P3 and original P0
IN A,(PAGE3)
PUSH AF
LD A,(WORK_P0) ; = 0Ah
OUT (PAGE3),A
LD A,(SAVE_P0)
OUT (PAGE0),A
; Write DC bytes from (HL) to A file handler
LD DE,0x4000
LD HL,PAGE3_ADDR
LD C,DSS_WRITE
LD A,(FH_OUT)
RST DSS
JP C,ERR_FILE_OP
; Restore P3 and our P0
POP AF
OUT (PAGE3),A
DI
LD A,(WORK_P0) ; = 0Ah
OUT (PAGE0),A
POP HL
PUSH HL
; DE=HL-0x4000
LD DE,0x4000
AND A
SBC HL,DE
JR Z,NO_B_TO_WR
EX DE,HL
LD A,(SAVE_P0)
OUT (PAGE0),A
; Write remains DC bytes from (HL)=0x4000
LD HL,0x4000
LD C,DSS_WRITE
LD A,(FH_OUT)
RST DSS
JP C,ERR_FILE_OP
DI
LD A,(WORK_P0)
OUT (PAGE0),A
NO_B_TO_WR
POP BC
LD HL,0x0
; Update CRC for buffer
CALL UPD_CRC
LD HL,0x0
RET
FILL_3
DS TEMP_BUFFR-FILL_3, 0
ORG 0xB000
; 4096 bytes buffer AFFF-BFFF
TEMP_BUFFR
DS 6, 0
GPP_FLAG
DB 0, 0
TEMP_BUFFR_8
DS 18, 0
LH_FN_LEN_L
DB 0
LH_FN_LEN_H
DB 0
LH_EXTRA_LEN_L
DB 0
LH_EXTRA_LEN_H
DB 0
LH_FILENAME
DS 1024, 0
;PAGE3_ADDR
ALIGN 16384, 0
ORG 0xC000
DS 4096, 0
DS 91,0
; ----
BUFF_2
DS 167,0
MODE_STORED
LD A,B
; ALIGN to 8 bit
CP 0x8
CALL NZ,GET_RIGHT_A_BITS
EX DE,HL
CALL GET_NEXT_8B ; Get LEN_L
LD E,D
CALL GET_NEXT_8B ; Get LEN_H
LD A,D
XOR H
LD D,A
LD A,E
XOR L
AND D
INC A
JP NZ,F_HAS_BAD_TAB
CALL GET_NEXT_8B ; Get NLEN?
EX DE,HL
; Move next DE bytes from input buffer to output
TMP_BUFFER_ADDR+* LD HL,0x0000
DEC HL
DO_NXT_CHR
LD A,(HL) ; HL => TEMP_BUFFR
INC HL ; HL =>TEMP_BUFFR + 1
CALL PUT_A_TO_BUFF
PUSH HL
LD BC,0x4001
ADD HL,BC
POP HL
JR NC,NO_WRAP
CALL LOAD_NXT_BLOCK
LD HL,TEMP_BUFFR
NO_WRAP
DEC DE
LD A,D
OR E
JR NZ,DO_NXT_CHR
LD (TMP_BUFFER_ADDR),HL
POP DE
JR DO_NEXT_BLOCK
; ----------------------------------------------------
INFLATE
XOR A
LD (ZIP_EOF),A
CALL LOAD_NXT_BLOCK
LD HL,0x0
LD (NXT_WRD_PTR),HL
DO_NEXT_BLOCK
LD HL,(TMP_BUFFER_ADDR)
LD E,(HL)
INC HL
LD (TMP_BUFFER_ADDR),HL
CALL GET_NEXT_8B ; DE = next 16 bit from inp; b=8
DO_NEXT_BLK
ZIP_EOF+* LD A,0x0 ; 0Ah - work mem blk in page0
OR A
JR NZ,ZIP_END ; non zero last blk
CALL DE_DIV_2_Bm1 ; DE>>1; B-- E0 -> CY
LD HL,ZIP_EOF
RR (HL) ; CY -> 7bit
CALL READ_HUFF_BLOCK
SU_L2
CALL NEXT_SYM
LD A,H
OR A
JR NZ,SU_L3
LD A,L
CALL PUT_A_TO_BUFF
JR SU_L2
SU_L3
DEC A
OR L
JR Z,DO_NEXT_BLK
DEC H
INC HL
INC HL
PUSH HL ; HL => BUFF_2
CALL SUB_UNCOMP_6
INC HL
POP AF
PUSH BC
PUSH DE
PUSH AF
POP BC
EX DE,HL
LD HL,(NXT_WRD_PTR)
OR A
SBC HL,DE
JR NC,SU_L6
EX DE,HL
LD HL,0x0
OR A
SBC HL,DE
PUSH HL ; HL => BUFF_2 + 1
NXT_WRD+* LD HL,0x0
ADD HL,DE
POP DE
EX DE,HL
PUSH HL ; HL => BUFF_2 + 1
CP A
SBC HL,BC
POP HL
EX DE,HL
JR NC,SU_L6
EX DE,HL
PUSH BC ; BC => BUFF_2
EX (SP),HL
POP BC
AND A
SBC HL,BC
PUSH HL
EX DE,HL
CALL SUB_UNCOMP_7
LD HL,0x0000
POP BC
SU_L6
CALL SUB_UNCOMP_7
LD A,(NXT_WRD_PTR+1) ;+1!
CP 0x80
CALL NC,BUFF_IS_FULL
POP DE
POP BC
JR SU_L2
ZIP_END
LD HL,(NXT_WRD_PTR)
; ----------------------------------------------------
FLUSH_BUFF
LD DE,0x0000
JP WRITE_BUFF
; ----------------------------------------------------
; Data definitions block for LZ77
; ----------------------------------------------------
FILL_1
DS 33, 0
; Code Lengths Order
CL_ORDER
DB 16, 17, 18, 0, 8, 7, 9, 6
DB 10, 5, 11, 4, 12, 3, 13, 2
DB 14, 1, 15
ORG 0xD201
EXTRA_BITS
DB 1, 3, 7, 15, 31, 63, 127, 255 ; 2^n-1
BL_CNT
DS 70,0
; ----------------------------------------------------
; Return A number of bits in HL from block
; ----------------------------------------------------
HL_GET_A_BITS
CP 0x9
JR C,HL_LESS_8B
SUB 0x8
LD H,A
LD A,0x8
CALL READ_A_BITS
LD L,A
LD A,H
CALL READ_A_BITS
LD H,A
RET
HL_LESS_8B
CALL READ_A_BITS
LD H,0x0
LD L,A
RET
; ----------------------------------------------------
; Return A number of bits
; ----------------------------------------------------
READ_A_BITS
LD (XTRA_BITS_OFFS),A
EX AF,AF'
XTRA_BITS_OFFS+* LD A,(EXTRA_BITS) ; = 3
AND E
PUSH AF
EX AF,AF'
CALL GET_RIGHT_A_BITS
POP AF
RET
; ----------------------------------------------------
; DE/2, B--
; ----------------------------------------------------
DE_DIV_2_Bm1
SRL D
RR E ; E[0] -> CY
DEC B
RET NZ
; ----------------------------------------------------
; Get next 8 bits from buffer
; Out: D - next 8 bit from block
; B = 8
; ----------------------------------------------------
GET_NEXT_8B
PUSH AF
PUSH HL
PUSH BC
LD HL,(TMP_BUFFER_ADDR)
LD BC,0x4001
ADD HL,BC
POP BC
CALL C,LOAD_NXT_BLOCK
LD HL,(TMP_BUFFER_ADDR)
LD D,(HL)
INC HL
LD (TMP_BUFFER_ADDR),HL
LD B,0x8
POP HL
POP AF
RET
; ----------------------------------------------------
; Get number of bits (rigth shift)
; Inp: A - bits to get, B - bits remains
; Out: DE
; ----------------------------------------------------
GET_RIGHT_A_BITS
CP B
JR C,SHF_RT_DE2
SHF_RT_DE1
SRL D
RR E
DEC A
DJNZ SHF_RT_DE1
CALL GET_NEXT_8B
SHF_RT_DE2
OR A
RET Z
SRL D
RR E
DEC A
DJNZ SHF_RT_DE2 ; TODO: No RET?
MODE_ST_HUFF
PUSH BC
PUSH DE
; Init literal/length table
LD HL,LEN_LD
LD BC,0x9008 ;144 8 bit, from 00110000 to 101
INI_LEN1
LD (HL),C
INC HL
DJNZ INI_LEN1
LD BC,0x7009 ;122 9 bit, from 110010000 to 11
INI_LEN2
LD (HL),C
INC HL
DJNZ INI_LEN2
LD BC,0x1807 ;24 7 bit, from 0000000 to 0010111
INI_LEN3
LD (HL),C
INC HL
DJNZ INI_LEN3
LD BC,0x808 ;8 8 bit, from 11000000 to 11000
INI_LEN4
LD (HL),C
INC HL
DJNZ INI_LEN4
LD HL,DISTANCES
LD BC,0x2005 ; 32
LD A,B
INI_DISTANCES
LD (HL),C
INC HL
DJNZ INI_DISTANCES
LD (HDIST),A
LD (HLIT),A
JP LOAD_LIT_DIST
;
READ_HUFF_BLOCK
LD A,0x2
CALL READ_A_BITS ; Get block compression mode
DEC A
JP M,MODE_STORED
JR Z,MODE_ST_HUFF
DEC A
JP NZ,F_HAS_BAD_TAB ; MODE 11 - reserved
LD A,0x5 ; Get HLIT
CALL READ_A_BITS
INC A ; +1
LD (HLIT),A ; +0x0100
LD A,0x5 ; Get HDIST
CALL READ_A_BITS
INC A
LD (HDIST),A
LD HL,LIT_TR
LD A,NR_CL
CLR_LIT_TR
LD (HL),0x0 ; HL => LIT_TR
INC HL
DEC A
JR NZ,CLR_LIT_TR
; Read HCLEN (4bit)
LD A,0x4
CALL READ_A_BITS
ADD A,0x4 ; number of Code Length codes (4 - 19)
LD C,A
LD HL,CL_ORDER
; (HCLEN + 4) x 3 bits: code lengths for the code length
; alphabet given just above, in the order: 16, 17, 18 ...
GET_NXT_CL
LD A,0x3
CALL READ_A_BITS
PUSH DE
LD E,(HL) ; HL => CL_ORDER
LD D,0x0
PUSH HL
LD HL,LIT_TR
ADD HL,DE
LD (HL),A ; => ram_db8a
POP HL
POP DE
INC HL
DEC C
JR NZ,GET_NXT_CL
PUSH BC
PUSH DE
LD HL,CL_TR
LD DE,LIT_TR
LD BC,NR_CL
CALL BUILD_CODE
LD HL,(HLIT)
LD DE,(HDIST)
ADD HL,DE
DEC HL
POP DE
POP BC
LD IX,LEN_LD
MN_CN2
PUSH HL
PUSH DE
LD D,0x0
LD HL,CL_TR
ADD HL,DE
ADD HL,DE
LD E,(HL)
LD HL,LIT_TR
ADD HL,DE
LD A,(HL) ; HL => LIT_TR
LD C,E
POP DE
CALL GET_RIGHT_A_BITS
LD A,C
POP HL
CP 0x10 ;
JR NC,CL_16 ; >= Next bytes - length
LD C,A ; len 1
LD A,0x1
JR CL_CMPL
CL_16
JR NZ,CL_17
; 16: Copy the previous code length 3 - 6 times. (2 bits length 0 = 3, ... , 3 = 6)
LD A,0x2
CALL READ_A_BITS
ADD A,3
LD C,(IX-0x1) ; => BYTE_ram_d619
JR CL_CMPL
CL_17
CP 0x11
JR NZ,CL_18
; Repeat a code length of 0 for 3 - 10 times. (3 bits of length)
LD A,3
CALL READ_A_BITS
ADD A,3
JR CL_END
CL_18
; Repeat a code length of 0 for 11 - 138 times (7 bits of length)
LD A,7
CALL READ_A_BITS
ADD A,11
CL_END
LD C,0x0
CL_CMPL
LD (IX+0x0),C ; => LEN_LD
INC IX
DEC A ; A = rpt cnt - 1
DEC HL
JR Z,CL_HL_0
BIT 0x7,H
JP NZ,F_HAS_BAD_TAB
JR CL_CMPL
CL_HL_0
BIT 0x7,H
JR Z,MN_CN2
PUSH BC
PUSH DE
LD HL,LEN_LD
LD DE,(HLIT)
ADD HL,DE
LD DE,DISTANCES
LD BC,(HDIST)
LDIR
; ------------------------------------------------------
; Load literal/length and distance alphabets
; ------------------------------------------------------
LOAD_LIT_DIST
; Load HLIT + 257 code lengths for the literal/length alphabet
HLIT+* LD BC,0x0100 ; Count of literals and lengths (+257)
LD DE,LEN_LD
LD HL,CL_TR
LD IX,LIT_TR
CALL BUILD_CODE
; Load HDIST + 1 code lengths for the distance alphabet,
HDIST+* LD BC,0x0
LD DE,DISTANCES
LD HL,N_CODE
LD IX,DIST_TR
CALL BUILD_CODE
POP DE
POP BC
RET
; ------------------------------------------------------
BUILD_CODE
LD A,B
OR C
RET Z ; ret if no literals
LD (NR_SYM),BC
LD (LEN_PTR),HL ; HL -> CL_TR
LD HL,BL_CNT
PUSH HL
PUSH BC
LD BC,0x2000
; BL_CNT[32]=0
BL_CNT_0
LD (HL),C
INC HL
DJNZ BL_CNT_0
POP BC
POP HL ; HL -> BL_CNT
PUSH DE
BC_LP_1
LD A,(DE) ; DE -> LIT_TR
INC DE
ADD A,A
ADD A,9 ; distance*2 + 9
LD L,A
INC (HL)
JR NZ,BC_NO_L
INC HL
INC (HL)
BC_NO_L
DEC BC
LD A,B
OR C
JR NZ,BC_LP_1
LD L,45
LD (HL),C
INC HL
LD (HL),C
PUSH BC
LD BC,0x0f02
INIT_BUFF4
LD A,C
ADD A,0x9
LD L,A
LD E,(HL)
INC HL
LD D,(HL)
EX (SP),HL
ADD HL,DE
ADD HL,HL
LD E,L
LD D,H
EX (SP),HL
INC C
INC C
LD A,C
ADD A,43
LD L,A
LD (HL),E
INC HL
LD (HL),D
DJNZ INIT_BUFF4
POP DE
LD A,D
OR E
JR Z,CHAR_L_NE0
LD D,B
LD E,B
LD A,15
LD L,11
INIT_BUFF5
LD C,(HL)
INC HL
LD B,(HL)
INC HL
EX DE,HL
ADD HL,BC
EX DE,HL
DEC A
JR NZ,INIT_BUFF5
LD HL,0xfffe ; END_OF_CODE?
ADD HL,DE
JP C,F_HAS_BAD_TAB
CHAR_L_NE0
POP DE
PUSH DE
NR_SYM+* LD BC,0x0
LD HL,NODES
INIT_BUFF6
LD A,(DE) ; Char lengths?
INC DE
PUSH DE
ADD A,A
LD E,A
LD D,A
JR Z,CHAR_L_E0
PUSH HL
LD H,high BL_CNT ; 0xD2
ADD A,(low BL_CNT) + 34 ; +43
LD L,A
LD E,(HL)
INC HL
LD D,(HL)
INC DE
LD (HL),D
DEC HL
LD (HL),E
DEC DE
POP HL
CHAR_L_E0
LD (HL),E ; => NODES
INC HL
LD (HL),D ; => NODES+1
INC HL
POP DE
DEC BC
LD A,C
OR B
JR NZ,INIT_BUFF6
POP DE
PUSH DE
LD HL,NODES
LD BC,(NR_SYM)
INIT_BUFF7
LD A,(DE)
INC DE
DEC A
JP M,INIT_BUFF11
JR Z,INIT_BUFF11
PUSH DE
LD E,(HL)
INC HL
LD D,(HL)
PUSH HL
LD HL,0x0
INIT_BUFF8
SRL D
RR E
ADC HL,HL
EX AF,AF'
LD A,D
OR E
JR Z,INIT_BUFF9
EX AF,AF'
DEC A
JR NZ,INIT_BUFF8
INC A
EX AF,AF'
INIT_BUFF9
EX AF,AF'
RR E
INIT_BUFF10
ADC HL,HL
DEC A
JR NZ,INIT_BUFF10
EX DE,HL
POP HL
LD (HL),D ; => NODES_1
DEC HL
LD (HL),E ; => NODES
POP DE
INIT_BUFF11
INC HL
INC HL
DEC BC
LD A,C
OR B
JR NZ,INIT_BUFF7
LEN_PTR+* LD HL,0x0000
LD E,L
LD D,H
INC DE
LD BC,511
LD (HL),A
LDIR ; Shift LEN_TR right 1 byte
POP HL
LD BC,(NR_SYM)
DEC BC
ADD HL,BC
EX DE,HL
//;+++
LD (TR_PTR),IX ; LIT_TR or DIST_TR addr
LD HL,NODES+1
ADD HL,BC
ADD HL,BC
INIT_BUFF12
LD A,(DE)
DEC DE
OR A
JR Z,INIT_BUFF16
CP 0x9
PUSH DE
LD D,(HL)
DEC HL
LD E,(HL)
INC HL
PUSH HL
JR NC,INIT_BUFF17
LD HL,0x1
INC A
INIT_BUFF13
ADD HL,HL
DEC A
JR NZ,INIT_BUFF13
EX DE,HL
ADD HL,HL
LD A,(LEN_PTR)
ADD A,L
LD L,A
LD (IB14_L2+1),A
LD A,(LEN_PTR+1)
ADC A,H
LD H,A
INC A
INC A
LD (IB14_L1+1),A
DEC DE
INIT_BUFF14
LD (HL),C
INC HL
LD (HL),B
ADD HL,DE
LD A,H
IB14_L1
CP 0x0
JR C,INIT_BUFF14
JR NZ,INIT_BUFF15
LD A,L
IB14_L2
CP 0x0
JR C,INIT_BUFF14
INIT_BUFF15
POP HL
POP DE
INIT_BUFF16
DEC HL
DEC HL
DEC BC
BIT 0x7,B
JR Z,INIT_BUFF12
RET
INIT_BUFF17
SUB 0x8
PUSH BC
LD B,A
LD A,D
LD D,0x0
LD HL,(LEN_PTR)
ADD HL,DE
ADD HL,DE
LD C,0x1
EX AF,AF'
INIT_BUFF18
LD E,(HL)
INC HL
LD D,(HL)
DEC HL
LD A,D
OR E
JR NZ,INIT_BUFF19 ; (word)(HL) != 0?
TR_PTR+* LD DE,0x0
LD (HL),E
INC HL
LD (HL),D
LD H,D
LD L,E
LD (HL),A
INC HL
LD (HL),A
INC HL
LD (HL),A
INC HL
LD (HL),A
INC HL
LD (TR_PTR),HL
INIT_BUFF19
EX DE,HL
EX AF,AF'
LD E,A
AND C
LD A,E
JR Z,INIT_BUFF20
INC HL
INC HL
INIT_BUFF20
EX AF,AF'
SLA C
DJNZ INIT_BUFF18
POP BC
LD (HL),C
INC HL
LD (HL),B
JR INIT_BUFF15
; --- Unparsed -------------
; ----------------------------------------------------
NEXT_SYM
PUSH DE
XOR A
LD D,A
LD HL,CL_TR+1 ; Code length
ADD HL,DE
ADD HL,DE ; HL = HL + 2*E
OR (HL)
DEC HL
LD L,(HL)
LD H,A ; HL = (HL)
JP M,LB_A_B7_1 ; A<0? bit 7 = 1
PUSH HL
LD DE,LEN_LD
ADD HL,DE
LD A,(HL) ; A - next bit count
POP HL
POP DE
DO_NXT_BITS
CALL GET_RIGHT_A_BITS
LD A,H
OR A
RET Z
LD A,L
CP 0x9
RET C
CP 29 ; 0x1D
LD HL,0x200
RET Z
DEC A
LD C,A
SRL C
SRL C
DEC C
AND 0x3
ADD A,0x4
LD H,L
LD L,A
LD A,C
DO_DBL_HL_C
ADD HL,HL
DEC C
JR NZ,DO_DBL_HL_C
INC H
CALL READ_A_BITS
INC A
ADD A,L
LD L,A
RET NC
INC H
RET
LB_A_B7_1
POP DE
CALL SUB_ram_d5cb
JR DO_NXT_BITS
; ----------------------------------------------------
SUB_UNCOMP_6
PUSH DE
XOR A
LD D,A
LD HL,N_CODE+1
ADD HL,DE
ADD HL,DE
OR (HL)
DEC HL
LD L,(HL)
LD H,A
JP M,L_HLM
PUSH HL
LD DE,DISTANCES
ADD HL,DE
LD A,(HL) ; HL => DISTANCES
POP HL
POP DE
LAB_ram_d5a9
CALL GET_RIGHT_A_BITS
LD A,L
CP 0x4
RET C
RRA
DEC A
LD C,A
LD L,H
RL L
INC L
INC L
HL_SL_C
ADD HL,HL ; HL << C
DEC C
JR NZ,HL_SL_C
PUSH HL
CALL HL_GET_A_BITS
EX DE,HL
EX (SP),HL
ADD HL,DE
POP DE
RET
L_HLM
POP DE
CALL SUB_ram_d5cb
JR LAB_ram_d5a9
; ----------------------------------------------------
SUB_ram_d5cb
LD A,0x8
CALL GET_RIGHT_A_BITS
LD C,E
XOR A
HI_W_BIT1
INC A
RR C
JR NC,LD_NXT_A
INC HL
INC HL
LD_NXT_A
LD (LD_NXT_W),HL
LD_NXT_W+* LD HL,(0x0000)
BIT 0x7,H
JR NZ,HI_W_BIT1
RET
; ----------------------------------------------------
FILL_2
DS 53, 0
BYTE_ram_d619
DB 0
LEN_LD
DS NR_LIT + NR_DIST, 0
DISTANCES
DS 32,0
CL_TR
DS 512,0
N_CODE
DS 512,0
LIT_TR
DS 4 * NR_LIT, 0
DIST_TR
DS 4 * NR_DIST,0
NODES
DS 2 * MAX_CL + 2
DS 7012,0
CRC32_TAB
DB 0x00, 0x00, 0x00, 0x00, 0x96, 0x30, 0x07, 0x77, 0x2C, 0x61, 0x0E, 0xEE, 0xBA, 0x51, 0x09, 0x99
DB 0x19, 0xC4, 0x6D, 0x07, 0x8F, 0xF4, 0x6A, 0x70, 0x35, 0xA5, 0x63, 0xE9, 0xA3, 0x95, 0x64, 0x9E
DB 0x32, 0x88, 0xDB, 0x0E, 0xA4, 0xB8, 0xDC, 0x79, 0x1E, 0xE9, 0xD5, 0xE0, 0x88, 0xD9, 0xD2, 0x97
DB 0x2B, 0x4C, 0xB6, 0x09, 0xBD, 0x7C, 0xB1, 0x7E, 0x07, 0x2D, 0xB8, 0xE7, 0x91, 0x1D, 0xBF, 0x90
DB 0x64, 0x10, 0xB7, 0x1D, 0xF2, 0x20, 0xB0, 0x6A, 0x48, 0x71, 0xB9, 0xF3, 0xDE, 0x41, 0xBE, 0x84
DB 0x7D, 0xD4, 0xDA, 0x1A, 0xEB, 0xE4, 0xDD, 0x6D, 0x51, 0xB5, 0xD4, 0xF4, 0xC7, 0x85, 0xD3, 0x83
DB 0x56, 0x98, 0x6C, 0x13, 0xC0, 0xA8, 0x6B, 0x64, 0x7A, 0xF9, 0x62, 0xFD, 0xEC, 0xC9, 0x65, 0x8A
DB 0x4F, 0x5C, 0x01, 0x14, 0xD9, 0x6C, 0x06, 0x63, 0x63, 0x3D, 0x0F, 0xFA, 0xF5, 0x0D, 0x08, 0x8D
DB 0xC8, 0x20, 0x6E, 0x3B, 0x5E, 0x10, 0x69, 0x4C, 0xE4, 0x41, 0x60, 0xD5, 0x72, 0x71, 0x67, 0xA2
DB 0xD1, 0xE4, 0x03, 0x3C, 0x47, 0xD4, 0x04, 0x4B, 0xFD, 0x85, 0x0D, 0xD2, 0x6B, 0xB5, 0x0A, 0xA5
DB 0xFA, 0xA8, 0xB5, 0x35, 0x6C, 0x98, 0xB2, 0x42, 0xD6, 0xC9, 0xBB, 0xDB, 0x40, 0xF9, 0xBC, 0xAC
DB 0xE3, 0x6C, 0xD8, 0x32, 0x75, 0x5C, 0xDF, 0x45, 0xCF, 0x0D, 0xD6, 0xDC, 0x59, 0x3D, 0xD1, 0xAB
DB 0xAC, 0x30, 0xD9, 0x26, 0x3A, 0x00, 0xDE, 0x51, 0x80, 0x51, 0xD7, 0xC8, 0x16, 0x61, 0xD0, 0xBF
DB 0xB5, 0xF4, 0xB4, 0x21, 0x23, 0xC4, 0xB3, 0x56, 0x99, 0x95, 0xBA, 0xCF, 0x0F, 0xA5, 0xBD, 0xB8
DB 0x9E, 0xB8, 0x02, 0x28, 0x08, 0x88, 0x05, 0x5F, 0xB2, 0xD9, 0x0C, 0xC6, 0x24, 0xE9, 0x0B, 0xB1
DB 0x87, 0x7C, 0x6F, 0x2F, 0x11, 0x4C, 0x68, 0x58, 0xAB, 0x1D, 0x61, 0xC1, 0x3D, 0x2D, 0x66, 0xB6
DB 0x90, 0x41, 0xDC, 0x76, 0x06, 0x71, 0xDB, 0x01, 0xBC, 0x20, 0xD2, 0x98, 0x2A, 0x10, 0xD5, 0xEF
DB 0x89, 0x85, 0xB1, 0x71, 0x1F, 0xB5, 0xB6, 0x06, 0xA5, 0xE4, 0xBF, 0x9F, 0x33, 0xD4, 0xB8, 0xE8
DB 0xA2, 0xC9, 0x07, 0x78, 0x34, 0xF9, 0x00, 0x0F, 0x8E, 0xA8, 0x09, 0x96, 0x18, 0x98, 0x0E, 0xE1
DB 0xBB, 0x0D, 0x6A, 0x7F, 0x2D, 0x3D, 0x6D, 0x08, 0x97, 0x6C, 0x64, 0x91, 0x01, 0x5C, 0x63, 0xE6
DB 0xF4, 0x51, 0x6B, 0x6B, 0x62, 0x61, 0x6C, 0x1C, 0xD8, 0x30, 0x65, 0x85, 0x4E, 0x00, 0x62, 0xF2
DB 0xED, 0x95, 0x06, 0x6C, 0x7B, 0xA5, 0x01, 0x1B, 0xC1, 0xF4, 0x08, 0x82, 0x57, 0xC4, 0x0F, 0xF5
DB 0xC6, 0xD9, 0xB0, 0x65, 0x50, 0xE9, 0xB7, 0x12, 0xEA, 0xB8, 0xBE, 0x8B, 0x7C, 0x88, 0xB9, 0xFC
DB 0xDF, 0x1D, 0xDD, 0x62, 0x49, 0x2D, 0xDA, 0x15, 0xF3, 0x7C, 0xD3, 0x8C, 0x65, 0x4C, 0xD4, 0xFB
DB 0x58, 0x61, 0xB2, 0x4D, 0xCE, 0x51, 0xB5, 0x3A, 0x74, 0x00, 0xBC, 0xA3, 0xE2, 0x30, 0xBB, 0xD4
DB 0x41, 0xA5, 0xDF, 0x4A, 0xD7, 0x95, 0xD8, 0x3D, 0x6D, 0xC4, 0xD1, 0xA4, 0xFB, 0xF4, 0xD6, 0xD3
DB 0x6A, 0xE9, 0x69, 0x43, 0xFC, 0xD9, 0x6E, 0x34, 0x46, 0x88, 0x67, 0xAD, 0xD0, 0xB8, 0x60, 0xDA
DB 0x73, 0x2D, 0x04, 0x44, 0xE5, 0x1D, 0x03, 0x33, 0x5F, 0x4C, 0x0A, 0xAA, 0xC9, 0x7C, 0x0D, 0xDD
DB 0x3C, 0x71, 0x05, 0x50, 0xAA, 0x41, 0x02, 0x27, 0x10, 0x10, 0x0B, 0xBE, 0x86, 0x20, 0x0C, 0xC9
DB 0x25, 0xB5, 0x68, 0x57, 0xB3, 0x85, 0x6F, 0x20, 0x09, 0xD4, 0x66, 0xB9, 0x9F, 0xE4, 0x61, 0xCE
DB 0x0E, 0xF9, 0xDE, 0x5E, 0x98, 0xC9, 0xD9, 0x29, 0x22, 0x98, 0xD0, 0xB0, 0xB4, 0xA8, 0xD7, 0xC7
DB 0x17, 0x3D, 0xB3, 0x59, 0x81, 0x0D, 0xB4, 0x2E, 0x3B, 0x5C, 0xBD, 0xB7, 0xAD, 0x6C, 0xBA, 0xC0
DB 0x20, 0x83, 0xB8, 0xED, 0xB6, 0xB3, 0xBF, 0x9A, 0x0C, 0xE2, 0xB6, 0x03, 0x9A, 0xD2, 0xB1, 0x74
DB 0x39, 0x47, 0xD5, 0xEA, 0xAF, 0x77, 0xD2, 0x9D, 0x15, 0x26, 0xDB, 0x04, 0x83, 0x16, 0xDC, 0x73
DB 0x12, 0x0B, 0x63, 0xE3, 0x84, 0x3B, 0x64, 0x94, 0x3E, 0x6A, 0x6D, 0x0D, 0xA8, 0x5A, 0x6A, 0x7A
DB 0x0B, 0xCF, 0x0E, 0xE4, 0x9D, 0xFF, 0x09, 0x93, 0x27, 0xAE, 0x00, 0x0A, 0xB1, 0x9E, 0x07, 0x7D
DB 0x44, 0x93, 0x0F, 0xF0, 0xD2, 0xA3, 0x08, 0x87, 0x68, 0xF2, 0x01, 0x1E, 0xFE, 0xC2, 0x06, 0x69
DB 0x5D, 0x57, 0x62, 0xF7, 0xCB, 0x67, 0x65, 0x80, 0x71, 0x36, 0x6C, 0x19, 0xE7, 0x06, 0x6B, 0x6E
DB 0x76, 0x1B, 0xD4, 0xFE, 0xE0, 0x2B, 0xD3, 0x89, 0x5A, 0x7A, 0xDA, 0x10, 0xCC, 0x4A, 0xDD, 0x67
DB 0x6F, 0xDF, 0xB9, 0xF9, 0xF9, 0xEF, 0xBE, 0x8E, 0x43, 0xBE, 0xB7, 0x17, 0xD5, 0x8E, 0xB0, 0x60
DB 0xE8, 0xA3, 0xD6, 0xD6, 0x7E, 0x93, 0xD1, 0xA1, 0xC4, 0xC2, 0xD8, 0x38, 0x52, 0xF2, 0xDF, 0x4F
DB 0xF1, 0x67, 0xBB, 0xD1, 0x67, 0x57, 0xBC, 0xA6, 0xDD, 0x06, 0xB5, 0x3F, 0x4B, 0x36, 0xB2, 0x48
DB 0xDA, 0x2B, 0x0D, 0xD8, 0x4C, 0x1B, 0x0A, 0xAF, 0xF6, 0x4A, 0x03, 0x36, 0x60, 0x7A, 0x04, 0x41
DB 0xC3, 0xEF, 0x60, 0xDF, 0x55, 0xDF, 0x67, 0xA8, 0xEF, 0x8E, 0x6E, 0x31, 0x79, 0xBE, 0x69, 0x46
DB 0x8C, 0xB3, 0x61, 0xCB, 0x1A, 0x83, 0x66, 0xBC, 0xA0, 0xD2, 0x6F, 0x25, 0x36, 0xE2, 0x68, 0x52
DB 0x95, 0x77, 0x0C, 0xCC, 0x03, 0x47, 0x0B, 0xBB, 0xB9, 0x16, 0x02, 0x22, 0x2F, 0x26, 0x05, 0x55
DB 0xBE, 0x3B, 0xBA, 0xC5, 0x28, 0x0B, 0xBD, 0xB2, 0x92, 0x5A, 0xB4, 0x2B, 0x04, 0x6A, 0xB3, 0x5C
DB 0xA7, 0xFF, 0xD7, 0xC2, 0x31, 0xCF, 0xD0, 0xB5, 0x8B, 0x9E, 0xD9, 0x2C, 0x1D, 0xAE, 0xDE, 0x5B
DB 0xB0, 0xC2, 0x64, 0x9B, 0x26, 0xF2, 0x63, 0xEC, 0x9C, 0xA3, 0x6A, 0x75, 0x0A, 0x93, 0x6D, 0x02
DB 0xA9, 0x06, 0x09, 0x9C, 0x3F, 0x36, 0x0E, 0xEB, 0x85, 0x67, 0x07, 0x72, 0x13, 0x57, 0x00, 0x05
DB 0x82, 0x4A, 0xBF, 0x95, 0x14, 0x7A, 0xB8, 0xE2, 0xAE, 0x2B, 0xB1, 0x7B, 0x38, 0x1B, 0xB6, 0x0C
DB 0x9B, 0x8E, 0xD2, 0x92, 0x0D, 0xBE, 0xD5, 0xE5, 0xB7, 0xEF, 0xDC, 0x7C, 0x21, 0xDF, 0xDB, 0x0B
DB 0xD4, 0xD2, 0xD3, 0x86, 0x42, 0xE2, 0xD4, 0xF1, 0xF8, 0xB3, 0xDD, 0x68, 0x6E, 0x83, 0xDA, 0x1F
DB 0xCD, 0x16, 0xBE, 0x81, 0x5B, 0x26, 0xB9, 0xF6, 0xE1, 0x77, 0xB0, 0x6F, 0x77, 0x47, 0xB7, 0x18
DB 0xE6, 0x5A, 0x08, 0x88, 0x70, 0x6A, 0x0F, 0xFF, 0xCA, 0x3B, 0x06, 0x66, 0x5C, 0x0B, 0x01, 0x11
DB 0xFF, 0x9E, 0x65, 0x8F, 0x69, 0xAE, 0x62, 0xF8, 0xD3, 0xFF, 0x6B, 0x61, 0x45, 0xCF, 0x6C, 0x16
DB 0x78, 0xE2, 0x0A, 0xA0, 0xEE, 0xD2, 0x0D, 0xD7, 0x54, 0x83, 0x04, 0x4E, 0xC2, 0xB3, 0x03, 0x39
DB 0x61, 0x26, 0x67, 0xA7, 0xF7, 0x16, 0x60, 0xD0, 0x4D, 0x47, 0x69, 0x49, 0xDB, 0x77, 0x6E, 0x3E
DB 0x4A, 0x6A, 0xD1, 0xAE, 0xDC, 0x5A, 0xD6, 0xD9, 0x66, 0x0B, 0xDF, 0x40, 0xF0, 0x3B, 0xD8, 0x37
DB 0x53, 0xAE, 0xBC, 0xA9, 0xC5, 0x9E, 0xBB, 0xDE, 0x7F, 0xCF, 0xB2, 0x47, 0xE9, 0xFF, 0xB5, 0x30
DB 0x1C, 0xF2, 0xBD, 0xBD, 0x8A, 0xC2, 0xBA, 0xCA, 0x30, 0x93, 0xB3, 0x53, 0xA6, 0xA3, 0xB4, 0x24
DB 0x05, 0x36, 0xD0, 0xBA, 0x93, 0x06, 0xD7, 0xCD, 0x29, 0x57, 0xDE, 0x54, 0xBF, 0x67, 0xD9, 0x23
DB 0x2E, 0x7A, 0x66, 0xB3, 0xB8, 0x4A, 0x61, 0xC4, 0x02, 0x1B, 0x68, 0x5D, 0x94, 0x2B, 0x6F, 0x2A
DB 0x37, 0xBE, 0x0B, 0xB4, 0xA1, 0x8E, 0x0C, 0xC3, 0x1B, 0xDF, 0x05, 0x5A, 0x8D, 0xEF, 0x02, 0x2D
END_OF_CODE
; IF DEBUG == 1
; SAVESNA "unzip.sna", START
; ENDIF
END