From f88fc0e5ff7a980443ac0c5e75b11acfa4dff5a1 Mon Sep 17 00:00:00 2001 From: boykovra Date: Fri, 14 Jun 2024 13:41:17 +0300 Subject: [PATCH] Initial commit --- .gitignore | 10 + .vscode/extensions.json | 10 + .vscode/launch.json | 94 ++ .vscode/tasks.json | 41 + README.md | 4 + bios.asm | 189 ++++ sim/ports.js | 44 + test_data.asm | 37 + unzip.asm | 2249 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 2678 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 README.md create mode 100644 bios.asm create mode 100644 sim/ports.js create mode 100644 test_data.asm create mode 100644 unzip.asm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b21a0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.dos +*.sna +*.lst +*.sld +*.obj +*.labels +*.tmp +*.EXE +*.exe +*.bin diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..48fb1d6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "maziac.asm-code-lens", + "maziac.dezog", + "maziac.hex-hover-converter", + "maziac.z80-instruction-set", + "maziac.sna-fileviewer", + "maziac.nex-fileviewer", + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f61c718 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,94 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "dezog", + "request": "launch", + "name": "Internal Simulator", + "remoteType": "zsim", + "zsim": { + "visualMemory": true, + "memoryModel": "CUSTOM", + "customMemory": { + "slots": [ + { + "name": "PAGE0", + "range": ["0x0000","0x3FFF"], + "banks": [{"index": [0, 255]}], + "initialBank": 0 + }, + { + "name": "PAGE1", + "range": ["0x4000","0x7FFF"], + "banks": [{"index": [0, 255]}], + "initialBank": 1 + }, + { + "name": "PAGE2", + "range": ["0x8000","0xBFFF"], + "banks": [{"index": [0, 255]}], + "initialBank": 2 + }, + { + "name": "PAGE3", + "range": ["0xC000","0xFFFF"], + "banks": [{"index": [0, 255]}], + "initialBank": 3 + } + ], + "ioMmu": [ + "if (portAddress == 0x82) {", + " bank = portValue;", + " PAGE0 = bank;", + "}", + "if (portAddress == 0xA2) {", + " bank = portValue;", + " PAGE1 = bank;", + "}", + "if (portAddress == 0xC2) {", + " bank = portValue;", + " PAGE2 = bank;", + "}", + "if (portAddress == 0xE2) {", + " bank = portValue;", + " PAGE3 = bank;", + "}" + ] + }, + "customCode": { + "debug": false, + "jsPath": "sim/ports.js" + //"uiPath": "simulation/ui.html" + }, + //"ulaScreen": true, + //"zxBorderWidth": 20, + //"vsyncInterrupt": true, + //"zxKeyboard": true, + //"zxBeeper": true + }, + "sjasmplus": [ + { + "path": "unzip.sld" + } + ], + "history": { + "reverseDebugInstructionCount": 1000000, + "spotCount": 10, + "codeCoverageEnabled": true + }, + "startAutomatically": false, + "commandsAfterLaunch": [], + "rootFolder": "${workspaceFolder}", + "topOfStack": "STACK_TOP", + "loadObjs": [ + { + "path": "unzip.obj", + "start": "0x0000" + } + ], + "execAddress": "0x8100", + "smallValuesMaximum": 513, + "tmpDir": ".tmp" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3735c0d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "make (sjasmplus)", + "type": "shell", + "command": "sjasmplus", + "args": [ + "--sld=unzip.sld", + "--sym=unzip.labels", + "--raw=unzip.obj", + "--fullpath", + "unzip.asm" + ], + "problemMatcher": { + "owner": "sjasmplus", + "fileLocation": "autoDetect", + "pattern": { + "regexp": "^(.*)\\((\\d+)\\):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "message": 4 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "start mame", + "type": "shell", + "command": "while true; do ./mame spectrum -window -debugger gdbstub -debug -debugger_port 12000 -verbose -resolution 512x384 ; sleep 2 ; done", + "options": { + "cwd": "${config:mame_dir}" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..046d7c5 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +UNZIP for Sprinter +================== + +Dizassembled code from UNZIP.EXE v0.7 for Sprinter computer. diff --git a/bios.asm b/bios.asm new file mode 100644 index 0000000..4ff7407 --- /dev/null +++ b/bios.asm @@ -0,0 +1,189 @@ + ORG 0x0000 + +RESET: + JP NOT_IMPL + DS 5, 0xFF + +RST08: + JP NOT_IMPL + DS 5, 0xFF + + ORG 0x0010 +RST10: + JP DSS_HANDLER + DS 5, 0xFF + +RST18: + JP NOT_IMPL + DS 5, 0xFF + +RST20: + JP NOT_IMPL + DS 5, 0xFF + +RST28: + JP NOT_IMPL + DS 5, 0xFF + +RST30: + JP NOT_IMPL + DS 5, 0xFF + +RST38: + JP NOT_IMPL + DS 5, 0xFF + +DSS_HANDLER + + PUSH HL + PUSH BC + LD A, C + CP 0x0B + JP Z, _CREATE_FILE + CP 0x11 + JP Z, _OPEN_FILE + CP 0x12 + JP Z, _CLOSE_FILE + CP 0x13 + JP Z, _READ_FILE + CP 0x14 + JP Z, _WRITE_FILE + CP 0x5C + JP Z, _PCHARS + CP 0x41 + JP Z, _EXIT + + POP BC + POP HL + + +NOT_IMPL + LD A,0x01 + SCF + RET + +_PCHARS + LD BC, 0x9000 + +NXT_PCHAR + LD A, (HL) + OUT (C),A + INC HL + OR A + JR NZ, NXT_PCHAR + +NORM_EXIT + CCF + POP BC + POP HL + RET + +BAD_EXIT + SCF + POP BC + POP HL + RET + + +; Входные значения: +; HL - указатель на файловую спецификацию +; A - атрибут файла +; Выходные значения: +; A — код ошибки, если CF=1 +; A - файловый манипулятор, если CF=0 +_CREATE_FILE + JP DSS_OPEN_FILE + +; Входные значения: +; HL - указатель на файловую спецификацию +; A - режим доступа +; A=0 чтение/запись +; A=1 чтение +; A=2 запись +; Выходные значения: +; A - код ошибки, если CF=1 +; A - файловый манипулятор, если CF=0 +CUR_FILE_MAN + DB 0x4F + +_OPEN_FILE + LD HL, CUR_FILE_MAN + INC (HL) + LD A, (HL) + JP NORM_EXIT + +_CLOSE_FILE + JP NORM_EXIT + +CUR_F_PTR + DW ZIP_FILE + +REMAINS_IN_ZIP + DW 0 + +; Входные значения: +; A - файловый манипулятор +; HL - адрес в памяти +; DE - количество читаемых байт +; Выходные значения: +; A - код ошибки, если CF=1 +; DE - реальное количество прочитанных байт +; если CF=0: +; A = 0 прочитаны все байты +; A = 0FFh прочитано меньшее число байт +_READ_FILE + OR A + JP Z, BAD_EXIT + PUSH DE + POP BC ; BC - bytes to read + PUSH HL + + LD HL, (CUR_F_PTR) ; HL -> IN ZIP_FILE + LD DE, ZIP_FILE_END + EX HL, DE + SUB HL, DE ; HL = remain bytes + LD (REMAINS_IN_ZIP), HL + SBC HL, BC + LD A, 0 + JR NC, NO_OUT_OF_ZIP + DEC A + LD HL,(REMAINS_IN_ZIP) + LD BC, HL + +NO_OUT_OF_ZIP + LD HL, (CUR_F_PTR) + POP DE ; DE - Buffer to write + PUSH BC + LDIR + POP DE ; DE = bytes read, A = 0 or 0xFF + LD (CUR_F_PTR), HL + + JP NORM_EXIT + + +; Входные значения: +; A - файловый манипулятор +; HL - адрес в памяти +; DE - количество записываемых байт +; Выходные значения: +; A - код ошибки, если CF=1 +; DE - реальное количество записанных байт +_WRITE_FILE + + PUSH DE + POP BC + LD DE,UNZIP_FILE + + PUSH BC + LDIR + POP DE + JP NORM_EXIT + + +_EXIT +; LOGPOINT STOPPED! + + HALT + JP _EXIT + + ALIGN 16384, 0 \ No newline at end of file diff --git a/sim/ports.js b/sim/ports.js new file mode 100644 index 0000000..9287bb0 --- /dev/null +++ b/sim/ports.js @@ -0,0 +1,44 @@ +port_p0 = 0; +port_p1 = 1; +port_p2 = 2; +port_p3 = 3; +message = ""; + +// This function is called when time (t-states) advances. +API.tick = () => { +} + +// This function is called when an 'out' is executed in Z80. +API.writePort = (port, value) => { + // Go through all ports + if (port == 0x9000) { + if (value != 0) { + message += String.fromCharCode(value); + } else { + API.log("> " + message); + message = ""; + } + } else if (port == 0x82) { + port_p0 = value; + } else if (port == 0xA2) { + port_p1 = value; + } else if (port == 0xC2) { + port_p2 = value; + } else if (port == 0xE2) { + port_p3 = value; + } +} + + +API.readPort = (port) => { + if (port == 0x82) { + return port_p0; + } else if (port == 0xA2) { + return port_p1; + } else if (port == 0xC2) { + return port_p2; + } else if (port == 0xE2) { + return port_p3; + } +} + diff --git a/test_data.asm b/test_data.asm new file mode 100644 index 0000000..96cedf9 --- /dev/null +++ b/test_data.asm @@ -0,0 +1,37 @@ + + ORG 0x4000 + +ZIP_FILE + DB 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0xC9, 0xA3, 0xBA, 0x58, 0xA0, 0xE8, 0xCD, 0xD3, 0xEA, 0x00 + DB 0x00, 0x00, 0x7B, 0x02, 0x00, 0x00, 0x05, 0x00, 0x1C, 0x00, 0x31, 0x2E, 0x61, 0x73, 0x6D, 0x55, 0x54, 0x09, 0x00, 0x03 + DB 0xA9, 0x71, 0x53, 0x66, 0xE6, 0x58, 0x68, 0x66, 0x75, 0x78, 0x0B, 0x00, 0x01, 0x04, 0xE8, 0x03, 0x00, 0x00, 0x04, 0xE8 + DB 0x03, 0x00, 0x00, 0xB5, 0x91, 0xC1, 0x8E, 0xC2, 0x30, 0x0C, 0x44, 0xCF, 0xE3, 0xAF, 0x40, 0xE2, 0x52, 0xA4, 0x1C, 0x58 + DB 0x90, 0xB8, 0xA7, 0x49, 0x2A, 0x8A, 0xD2, 0x50, 0x25, 0x01, 0x01, 0x17, 0xFE, 0xFF, 0x2F, 0xD6, 0x71, 0x4B, 0xD9, 0x20 + DB 0x71, 0xDC, 0x53, 0xD3, 0xD8, 0xF3, 0xE2, 0x19, 0xE7, 0x94, 0x9F, 0xDB, 0x1F, 0x42, 0x1F, 0xA0, 0x55, 0x63, 0x86, 0xF3 + DB 0x25, 0xB9, 0x0D, 0x21, 0x46, 0xA3, 0x57, 0x84, 0xD3, 0x88, 0x60, 0x54, 0xAE, 0x7A, 0xEC, 0xAB, 0xC7, 0x5B, 0x38, 0xA5 + DB 0x09, 0x6D, 0x9F, 0x71, 0x28, 0x07, 0x63, 0x3A, 0xD6, 0x44, 0x97, 0x11, 0x1E, 0x44, 0xA2, 0xDA, 0x7D, 0x25, 0xC7, 0x85 + DB 0xBC, 0xF4, 0xFC, 0x25, 0xDB, 0xEF, 0x64, 0xF0, 0xC3, 0x5A, 0x39, 0x82, 0x0E, 0x16, 0xEB, 0x7D, 0x47, 0xE5, 0x42, 0x26 + DB 0x91, 0x82, 0x9F, 0x0B, 0xDB, 0xFD, 0x62, 0x63, 0x76, 0x73, 0x8E, 0x60, 0x55, 0xD5, 0x6C, 0x6B, 0x8A, 0xBC, 0x5A, 0x53 + DB 0xCC, 0x27, 0x65, 0x86, 0xBD, 0x99, 0xCC, 0x60, 0x49, 0x25, 0x8D, 0x5E, 0xE2, 0xFB, 0xF8, 0xB8, 0x34, 0xE5, 0x74, 0x12 + DB 0xEF, 0x29, 0xB7, 0x17, 0x42, 0xE2, 0xB4, 0x4A, 0x78, 0xE5, 0x0F, 0x75, 0xBF, 0xD8, 0x2B, 0x2E, 0x98, 0xDE, 0x0C, 0xED + DB 0x46, 0x22, 0xD6, 0xDE, 0xB3, 0x26, 0xA4, 0xC9, 0x88, 0xC4, 0x20, 0xE5, 0x9B, 0x94, 0x65, 0xF4, 0x69, 0x9E, 0x66, 0xB8 + DB 0xCB, 0x55, 0x7A, 0x2D, 0x85, 0x57, 0x43, 0xB8, 0xBB, 0xF1, 0x69, 0xE3, 0xB5, 0x20, 0xB5, 0x5A, 0x77, 0x9C, 0x5D, 0x1F + DB 0x0C, 0x8E, 0x9C, 0x99, 0x19, 0xD1, 0x1C, 0x7D, 0x59, 0xFD, 0xB4, 0xBF, 0xFF, 0x2E, 0xAC, 0xE8, 0x17, 0x50, 0x4B, 0x01 + DB 0x02, 0x1E, 0x03, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0xC9, 0xA3, 0xBA, 0x58, 0xA0, 0xE8, 0xCD, 0xD3, 0xEA, 0x00, 0x00 + DB 0x00, 0x7B, 0x02, 0x00, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB4, 0x81, 0x00 + DB 0x00, 0x00, 0x00, 0x31, 0x2E, 0x61, 0x73, 0x6D, 0x55, 0x54, 0x05, 0x00, 0x03, 0xA9, 0x71, 0x53, 0x66, 0x75, 0x78, 0x0B + DB 0x00, 0x01, 0x04, 0xE8, 0x03, 0x00, 0x00, 0x04, 0xE8, 0x03, 0x00, 0x00, 0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00 + DB 0x01, 0x00, 0x01, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00 +ZIP_FILE_END + +CMD_LINE1 + DB 20, " C:\\FOLDER\\ FILE.ZIP", 0 + +CMD_LINE2 + DB 19, " C:\\FOLDER\\FILE.ZIP", 0 + + +UNZIP_FILE + DS 1024, 0 + + ALIGN 16384, 0 \ No newline at end of file diff --git a/unzip.asm b/unzip.asm new file mode 100644 index 0000000..d1831f0 --- /dev/null +++ b/unzip.asm @@ -0,0 +1,2249 @@ +DEBUG EQU 1 +; ============================================== +; PKUNZIP utility for Sprinter version 0.7 +; Created by Aleksey Gavrilenko 09.02.2002 +; Procedure deflate by Michail Kondratyev +; ============================================== + 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_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? + + ORG 0x8080 + +EXE_HEADER + DB "EXE" + DB 0x00 ; 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,INPUT_PATH + CALL READ_CMD_PAR + JR C,INVALID_CMDLINE + LD DE,OUTPUT_PATH + CALL READ_CMD_PAR + JR NC,IS_SEC_PAR + LD HL,INPUT_PATH ; In and out is same + LD DE,OUTPUT_PATH + LD BC,256 + LDIR +IS_SEC_PAR + LD HL,OUTPUT_PATH + CALL FIND_FILE_NAME + 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,(INPUT_PATH) + AND A + JR Z,INVALID_CMDLINE + LD HL,START_MESSAGE ; "PKUNZIP utility for Sprinter + LD C,DSS_PCHARS + RST DSS + LD HL,INPUT_PATH + CALL FIND_FILE_NAME + JP C,ERR_FILE_OP + LD HL,MSG_INP_PATH ; "Input path:" + LD C,DSS_PCHARS + RST DSS + LD HL,INPUT_PATH + 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,OUTPUT_PATH + LD C,DSS_PCHARS + RST DSS + LD HL,MSG_EOL ; '\r' + LD C,DSS_PCHARS + RST DSS + IN A,(PAGE0) + LD (SAVE_P0),A + LD HL,INPUT_PATH + LD C,DSS_CHDIR + RST DSS + JP C,ERR_FILE_OP + 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 + JR GOT_INP_FILE +GET_NEXT_FILE + LD DE,FF_WORK_BUF + LD BC,DSS_FIND_NEXT ; FIND_NEXT + RST DSS + JR NC,GOT_INP_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 +GOT_INP_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_LOCL_HDR + + CALL READ_HEADERS + JR C,ERR_IN_ZIP + AND A + JP Z,GOT_LFH + +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 GET_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 +GOT_LFH + LD HL,OUTPUT_PATH + 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 +FND_PATH_CPY_END + CP (HL) ; HL => TEMP_BUFFR + JR Z,END_PATH_CPY + INC HL + JR FND_PATH_CPY_END +END_PATH_CPY + DEC HL + LD A,(HL) ; HL => TEMP_0 + CP "\\" + JR Z,IS_DIR_SEP + INC HL + LD (HL),"\\" ; HL => TEMP_BUFFR +IS_DIR_SEP + INC HL + LD (HL),0x0 ; mark end of string + LD DE,ENTRY_FILE_NAME +MV_PATH_0 + LD A,(DE) ; =>ENTRY_FILE_NAME + LD (HL),A ; =>TEMP_BUFFR + 1 + INC HL + INC DE +CHK_MV_END + AND A + JR NZ,MV_PATH_0 + LD HL,TEMP_BUFFR +CHK_SLASH + LD A,(HL) ; HL => TEMP_BUFFR + CP '/' + JR NZ,OUT_COMP_METHOD + LD (HL),"\\" +OUT_COMP_METHOD + INC HL + AND A + JR NZ,CHK_SLASH + 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_FP_REL + 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_LOCL_HDR + +COMP_PARAMS_EMP + LD HL,MSG_UNKNOWN ; "Unknown: " + LD C,DSS_PCHARS + RST DSS + JR MOVE_FP_REL + +DIR_OR_EMPTY + LD HL,TEMP_BUFFR + CALL MAKE_FILE_PATH + OUT (BRD_SND),A + JP C,ERR_FILE_OP + JP RD_LOCL_HDR + +; Supported compression method. Stored of Deflate +C_SUPPORTED + LD HL,(LH_COMP_SIZE_L) + LD (FILEPOS_L),HL + LD DE,(LH_COMP_SIZE_H) + LD (FILEPOS_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 + 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 + 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 + LD HL,TEMP_BUFFR + CALL FIND_FILE_NAME + JP C,ERR_FILE_OP + LD HL,TEMP_BUFFR + CALL MAKE_FILE_PATH + JP C,ERR_FILE_OP + LD HL,TEMP_BUFFR + LD C,DSS_CHDIR + RST DSS + JP C,ERR_FILE_OP + 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 + +ERR_FILE_EXIST + LD HL,MSG_FILE_EXISTS ; " File exists!" + LD C,DSS_PCHARS + RST DSS + JP MOVE_FP_REL + +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 + +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 + 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_LOCL_HDR + +CRC_CHK_ERR + 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_LOCL_HDR + +; 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 +; ret A=0 - for LocalHileHeader +; A=ff - for CentralDirectory +; --------------------------- +; 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 +; ---------------------------- +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 cmd line parameter +; Inp: HL - pointer to cmd line position +; DE - pointer to buffer to place parameter +; --------------------------------- +READ_CMD_PAR + PUSH DE + +FIRST_SPACE + LD A,(HL) + INC HL + AND A + JR Z,PARAM_EOL + CP ' ' + JR Z,FIRST_SPACE + DEC HL + +PARAM_MOV + 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 + XOR A + LD (DE),A + POP DE + LD A,(DE) + AND A + RET NZ + SCF + RET + +; --------------------------------- +; File name from filepath +; HL - Buffer to seaarch +; ret: CF=1 - error +; else FILE_SPEC = file name +; --------------------------------- +FIND_FILE_NAME + PUSH HL + LD BC,0x80 + LD A,B + CPIR + LD A,C + AND A + JR NZ,NOT_EOS + POP HL + LD A,0x10 + SCF + RET +NOT_EOS + LD C,0x80 + LD A,"\\" + CPDR + LD A,C + AND A + JR NZ,NOT_BKSL + POP HL + LD BC,13 + LD DE,FILE_SPEC + LDIR + AND A + RET +NOT_BKSL + INC HL + LD DE,FILE_SPEC + LD C,13 + INC HL + PUSH HL + LDIR + POP HL + LD (HL),0x0 + POP HL + AND A + 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 needs +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 +INPUT_PATH + DS 256, 0 + +; Second parameter: Path to .zip file +OUTPUT_PATH + DS 256, 0 + +; Work buffer for FindFist/FindNext op (256bytes) +FF_WORK_BUF + DS 33,0 + +FF_FILE_NAME + DS 223, 0 + +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 +FILEPOS_H EQU $+2 + LD IX,0x0 +FILEPOS_L EQU $+1 + 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 (FILEPOS_H),IX + LD (FILEPOS_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 Page0 state + 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 + CALL UC_READ + LD A,D + 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 + PUSH HL + LD IX,(FILEPOS_H) + LD HL,(FILEPOS_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 (FILEPOS_H),IX + LD (FILEPOS_L),HL + LD A,D + OR E + POP HL + RET Z + 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 EQU $+1 + LD SP,0x0 + LD HL,(LD_NXT_WRD+1) + 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 + +; ------------------------------------------------------ +SUB_UNCOMP_7 + LD A,C + OR B + RET Z +LD_NXT_WRD + LD DE,0x0 +HAZ_BYTEZ + LD A,(HL) + LD (DE),A + INC DE + PUSH DE + PUSH HL + LD (LD_NXT_WRD+1),DE + LD HL,0x8000 + OR A + SBC HL,DE + JR Z,NO_BYTEZ + POP HL + POP DE +CONT_BYTEZ + CPI + JP PE,HAZ_BYTEZ + LD (LD_NXT_WRD+1),DE + RET +NO_BYTEZ + CALL BUFF_IS_FULL + POP HL + POP DE + LD DE,(LD_NXT_WRD+1) + JR CONT_BYTEZ + +; ------------------------------------------------------ +PUT_A_TO_BUFF + PUSH HL + LD HL,(LD_NXT_WRD+1) + LD (HL),A + INC HL + LD (LD_NXT_WRD+1),HL + LD A,H + CP 80h ; < 0x8000 ? + POP HL + RET C + +; ------------------------------------------------------ +BUFF_IS_FULL + PUSH HL + PUSH DE + PUSH BC + PUSH AF + LD HL,(LD_NXT_WRD+1) + LD (SU_L4+1),HL + CALL FLUSH_BUFF + LD (LD_NXT_WRD+1),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_NXT_BLOCK + PUSH HL + PUSH DE + PUSH BC + PUSH IX + LD HL,TEMP_BUFFR + LD (TMP_BUFFER_ADDR+1),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 + +FILL0 + DS 8843, 0 + +TEMP_0 + DB 0 + +; 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 D_NEXT_8BIT_B8 ; Get LEN_L + LD E,D + CALL D_NEXT_8BIT_B8 ; 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 D_NEXT_8BIT_B8 ; Get NLEN? + EX DE,HL + ; Move next DE bytes from input to output +TMP_BUFFER_ADDR + LD HL,0x0 + 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+1),HL + POP DE + JR DO_NEXT_BLOCK + +; ---------------------------------------------------------- +INFLATE + XOR A + LD (LAST_BLK+1),A + CALL LOAD_NXT_BLOCK + LD HL,0x0 + LD (LD_NXT_WRD+1),HL + +DO_NEXT_BLOCK + LD HL,(TMP_BUFFER_ADDR+1) + LD E,(HL) + INC HL + LD (TMP_BUFFER_ADDR+1),HL + CALL D_NEXT_8BIT_B8 ; DE = next 16 bit from inp; b=8 +LAST_BLK + LD A,0x0 + OR A + JR NZ,SU_L7 ; non zero last blk + CALL DE_DIV_2_Bm1 ; DE>>1; B-- + LD HL,LAST_BLK+1 + RR (HL) + CALL INFLATE_BLOCK +SU_L2 + CALL SUB_UNCOMP_5 + 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,LAST_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,(LD_NXT_WRD+1) + 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 +SU_L4 + 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,(LD_NXT_WRD+2) + CP 0x80 + CALL NC,BUFF_IS_FULL + POP DE + POP BC + JR SU_L2 +SU_L7 + LD HL,(LD_NXT_WRD+1) +; -------------------------------------- +FLUSH_BUFF + LD DE,0x0000 + JP WRITE_BUFF + +; ---------------------------- +; Data definitions block for LZ77 +; ---------------------------- +FILL_1 + DS 33, 0 + +ALPHABET_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 + +LZ77_BUFF + 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 GET_A_BITS + LD L,A + LD A,H + CALL GET_A_BITS + LD H,A + RET +HL_LESS_8B + CALL GET_A_BITS + LD H,0x0 + LD L,A + RET + +; ----------------------------------------- +; Return A number of bits +; ----------------------------------------- +GET_A_BITS + LD (XTRA_BITS_OFFS+1),A + EX AF,AF' +XTRA_BITS_OFFS + LD A,(EXTRA_BITS) ; = 1 + 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 + DEC B + RET NZ + +; ----------------------------------------- +; D - next 8 bit from block +; B = 8 +; ----------------------------------------- +D_NEXT_8BIT_B8 + PUSH AF + PUSH HL + PUSH BC + LD HL,(TMP_BUFFER_ADDR+1) + LD BC,0x4001 + ADD HL,BC + POP BC + CALL C,LOAD_NXT_BLOCK + LD HL,(TMP_BUFFER_ADDR+1) + LD D,(HL) + INC HL + LD (TMP_BUFFER_ADDR+1),HL + LD B,0x8 + POP HL + POP AF + RET + +; ----------------------------------------- +; Get A number of bits (rigth shift) +; return 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 D_NEXT_8BIT_B8 +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,CHAR_LENS + 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 UN_LZ77 +; + +INFLATE_BLOCK + LD A,0x2 + CALL GET_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 GET_A_BITS + INC A + LD (HLIT),A + LD A,0x5 ; Get HDIST + CALL GET_A_BITS + INC A + LD (HDIST),A + LD HL,IX_VAL_001 + LD A,0x13 +SU4_L1 + LD (HL),0x0 ; HL => IX_VAL_001 + INC HL + DEC A + JR NZ,SU4_L1 + ; Read HCLEN (4bit) + LD A,0x4 + CALL GET_A_BITS + ADD A,0x4 + LD C,A + LD HL,ALPHABET_ORDER +SU4_L2 + LD A,0x3 + CALL GET_A_BITS + PUSH DE + LD E,(HL) ; HL => ALPHABET_ORDER + LD D,0x0 + PUSH HL + LD HL,IX_VAL_001 + ADD HL,DE + LD (HL),A ; => ram_db8a + POP HL + POP DE + INC HL + DEC C + JR NZ,SU4_L2 + PUSH BC + PUSH DE + LD HL,HL_VAL_001 + LD DE,IX_VAL_001 + LD BC,0x13 + CALL UN_LZ77_1 + LD HL,(HLIT) + LD DE,(HDIST) + ADD HL,DE + DEC HL + POP DE + POP BC + LD IX,CHAR_LENS +SU4_L3 + PUSH HL + PUSH DE + LD D,0x0 + LD HL,HL_VAL_001 + ADD HL,DE + ADD HL,DE + LD E,(HL) + LD HL,IX_VAL_001 + ADD HL,DE + LD A,(HL) ; HL => IX_VAL_001 + LD C,E + POP DE + CALL GET_RIGHT_A_BITS + LD A,C + POP HL + CP 0x10 + JR NC,SU4_L4 + LD C,A + LD A,0x1 + JR SU4_L8 +SU4_L4 + JR NZ,SU4_L5 + LD A,0x2 + CALL GET_A_BITS + ADD A,0x3 + LD C,(IX-0x1) ; =>BYTE_ram_d619 + JR SU4_L8 +SU4_L5 + CP 0x11 + JR NZ,SU4_L6 + LD A,0x3 + CALL GET_A_BITS + ADD A,0x3 + JR SU4_L7 +SU4_L6 + LD A,0x7 + CALL GET_A_BITS + ADD A,0xb +SU4_L7 + LD C,0x0 +SU4_L8 + LD (IX+0x0),C ; =>CHAR_LENS + INC IX + DEC A + DEC HL + JR Z,SU4_L9 + BIT 0x7,H + JP NZ,F_HAS_BAD_TAB + JR SU4_L8 +SU4_L9 + BIT 0x7,H + JR Z,SU4_L3 + PUSH BC + PUSH DE + LD HL,CHAR_LENS + LD DE,(HLIT) + ADD HL,DE + LD DE,DISTANCES + LD BC,(HDIST) + LDIR + +; Init other LZ77 tables +UN_LZ77 +HLIT EQU $+1 + LD BC,0x100 ; Count of literals and lengths + LD DE,CHAR_LENS + LD HL,HL_VAL_001 + LD IX,IX_VAL_001 + CALL UN_LZ77_1 +HDIST EQU $+1 +SU4_L11 + LD BC,0x0 + LD DE,DISTANCES + LD HL,HL_VAL_002 + LD IX,IX_ARR_000 + CALL UN_LZ77_1 + POP DE + POP BC + RET + + +UN_LZ77_1 + LD A,B + OR C + RET Z ; ret if no literals + LD (LIT_CNT_LEN),BC + LD (HL_VAL_000),HL + LD HL,LZ77_BUFF + PUSH HL + PUSH BC + LD BC,0x2000 + +; [32]=0 +INI_BUFF1 + LD (HL),C + INC HL + DJNZ INI_BUFF1 + POP BC + POP HL + PUSH DE ; ? DE -> Distances + +INIT_BUFF2 + LD A,(DE) + INC DE + ADD A,A + ADD A,0x9 ; distance*2 + 9 + LD L,A + INC (HL) + JR NZ,INIT_BUFF3 + INC HL + INC (HL) + +INIT_BUFF3 + DEC BC + LD A,B + OR C + JR NZ,INIT_BUFF2 + LD L,45 + LD (HL),C + INC HL + LD (HL),C + PUSH BC + LD BC,0xf02 + +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 + ADD HL,DE + JP C,F_HAS_BAD_TAB + +CHAR_L_NE0 + POP DE + PUSH DE +LIT_CNT_LEN EQU $+1 + LD BC,0x0 + LD HL,HL_ARR_000 +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,210 + ADD A,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 ; =>HL_ARR_000 + INC HL + LD (HL),D ; =>HL_ARR_000+1 + INC HL + POP DE + DEC BC + LD A,C + OR B + JR NZ,INIT_BUFF6 + POP DE + PUSH DE + LD HL,HL_ARR_000 + LD BC,(LIT_CNT_LEN) +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 ; =>HL_ARR_000_1 + DEC HL + LD (HL),E ; =>HL_ARR_000 + POP DE +INIT_BUFF11 + INC HL + INC HL + DEC BC + LD A,C + OR B + JR NZ,INIT_BUFF7 + +HL_VAL_000 EQU $+1 + LD HL,0x0 + LD E,L + LD D,H + INC DE + LD BC,511 + LD (HL),A + LDIR + POP HL + LD BC,(LIT_CNT_LEN) + DEC BC + ADD HL,BC + EX DE,HL + LD (IB18_L1+1),IX + LD HL,HL_ARR_000+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,(HL_VAL_000) + ADD A,L + LD L,A + LD (IB14_L2+1),A + LD A,(HL_VAL_000+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,(HL_VAL_000) + 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? +IB18_L1 + 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 (IB18_L1+1),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 ------------- +; ----------------------------------- +SUB_UNCOMP_5 + PUSH DE + XOR A + LD D,A + LD HL,HL_VAL_001+1 + ADD HL,DE + ADD HL,DE ; HL = HL + 2*E + OR (HL) + DEC HL + LD L,(HL) + LD H,A ; HL = (HL) + JP M,LAB_ram_d58c ; HL<0? + PUSH HL + LD DE,CHAR_LENS + ADD HL,DE + LD A,(HL) ; HL =>CHAR_LENS + POP HL + POP DE +LAB_ram_d560 + CALL GET_RIGHT_A_BITS + LD A,H + OR A + RET Z + LD A,L + CP 0x9 + RET C + CP 29 + 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 +LAB_ram_d57e + ADD HL,HL + DEC C + JR NZ,LAB_ram_d57e + INC H + CALL GET_A_BITS + INC A + ADD A,L + LD L,A + RET NC + INC H + RET +LAB_ram_d58c + POP DE + CALL SUB_ram_d5cb + JR LAB_ram_d560 + +; ----------------------------------- +SUB_UNCOMP_6 + PUSH DE + XOR A + LD D,A + LD HL,HL_VAL_002+1 + ADD HL,DE + ADD HL,DE + OR (HL) + DEC HL + LD L,(HL) + LD H,A + JP M,LAB_ram_d5c5 + 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 +LAB_ram_d5c5 + 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+1),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 + +CHAR_LENS + DS 256, 0 +CHAR_LENGTHS_256 + DS 64,0 +DISTANCES + DS 32,0 + +HL_VAL_001 + DS 512,0 + +HL_VAL_002 + DS 512,0 + +IX_VAL_001 + DS 220, 0 + +UNK001 + DS 932, 0 + +IX_ARR_000 + DS 128,0 + +HL_ARR_000 + DS 7046,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 + + +; IF DEBUG == 1 +; SAVESNA "unzip.sna", START +; ENDIF + + END \ No newline at end of file