; ------------------------------------------------------------ ; UNSQ.A86 is similar to the program USQ.COM (SIG/M 58.27). ; The latter appears to have been compiled from BDS "C" source ; code, which is known to be from ten to twenty times more ; voluminous than code derived from assembly language source. ; UNSQ.A86 was written on the basis of information concerning ; Huffman codes found in the literature, an inspection of a ; disassembly of USQ.COM, and several experiments in which ; test files were squeezed and the squeezed files then dumped. ; UNSQ recovers the original unsqueezed file, which it places ; on the same disk as output. ; ; UNSQ.A86 Copyright (C) 1984 ; Universidad Autonoma de Puebla ; July 16, 1984 ; ; [Harold V. McIntosh, 16 July 1984] ; ------------------------------------------------------------ BDOS equ 224 ;bdos interrupt qfcb equ 005CH ;squeezed FCB tsiz equ 0080H usiz equ 0080H ;size of .UNS buffer qsiz equ 0080H ;size of squeezed file buffer qbuf equ 0080H ;squeezed buffer csiz equ 512 ;max chars in Huffman code ; Nongraphic characters. LF equ 0AH CR equ 0DH ; ------------- org 0100H ; ------------- begn: mov bx,(offset qfcb+1) ;squeezed FCB cmp (byte ptr[bx]),' ' jnz notu mov dx,(offset tuto) ferm: call mssg exit: mov dl,00 mov cl,00 int bdos notu: mov uptr,(offset ubuf) ;unsqueezed buffer mov qptr,(offset qbuf) ;squeezed buffer mov cx,0021H ;33 00's mov bx,(offset ufcb) ;unsqueezed FCB call fiuc ;block fill mov cx,200BH ;11 blanks mov bx,(offset ufcb+1) ;unsqueezed FCB call fiuc ;block fill call opef ;open squeezed file mov qctr,0000 mov uctr,usiz+1 ;size of .UNS buffer mov roco,1 cota: call rwor ;fetch one byte from input stream cmp bx,0FF76H jz rchk ;read checksum mov dx,(offset nsqz) ;'not a squeezed file' jmp ferm ;final (error) message ; The "squeezed" marker is followed by a two-byte checksum, ; which is the simple sum of all the one-byte characters in ; the source file, carried as a two byte sum modulo 2**16. rchk: call rwor ;fetch two bytes from input stream mov cksm,bx ;checksum ; Unsqueezed file name. It is an ASCII sequence, may be lower ; case if SQ.UNS received it in response to a prompt, ending ; with a zero byte. Some trash may be present if SQ.UNS wasn't ; used correctly. mov cx,8 mov bx,(offset ufcb+1) ;unsqueezed FCB luup: call rbyt ;fetch one byte from input stream or al,al jz luuw ;load code dictionary cmp al,'.' jz luuw call ucfo mov [bx],al inc bx call cona loop luup luuz: call rbyt or al,al jz ldic cmp al,'.' jnz luuz luuw: call cona mov cx,3 mov bx,(offset ufcb+9) ;unsqueezed FCB luur: call rbyt or al,al jz ldic call ucfo mov [bx],al inc bx call cona loop luur luus: call rbyt or al,al jnz luus ; Load code dictionary. It is preceded by its two-byte length, ; and consists of a series of pairs of two-byte addresses. For ; each bit in the code, select the first element (0) or the ; second (1) element of the pair. If the pair is positive, it ; is the table entry (code + 4*index) at which to continue with ; the next bit. If the pair is negative, it is the complement ; of the coded ASCII character (low order byte except for [end]). ldic: call rwor ;fetch two bytes from input stream cmp bx,(csiz+1) jc ldii mov dx,(offset ntab) ;'insufficient dictionary space' jmp ferm ;final (error) message ldii: add bx,bx add bx,bx mov cx,bx mov si,(offset code) ;decoding table luuq: call rbyt ;fetch one byte from input stream mov [si],al inc si loop luuq call crlf ;type CR,LF mov cl,26 ;(1A) set DMA address mov dx,(offset ubuf) ;unsqueezed buffer int BDOS mov dx,(offset ufcb) ;unsqueezed FCB mov cl,17 ;(11) search for file int BDOS inc al jz nexi mov dx,(offset yexi) ;'file already exists' jmp ferm ;final (error) message nexi: mov dx,(offset ufcb) ;unsqueezed FCB mov cl,22 ;(16) create file int BDOS mov dx,(offset ufcb) ;unsqueezed FCB mov cl,15 ;(0F) open file int BDOS cmp al,0FFH mov dx,(offset nodi) ;'no more directory' jnz G14 ! jmp ferm ! G14: ;final (error) message call cbuz ;clear output buffer to zeroes ; Type unsqueezed code. Beware of the [end] marker, ; and also the repeat marker 90H which occurs in the ; combination <90H>. When count is zero, ; 90H itself is intended; otherwise is to be ; repeated times, including the occurrence just ; before 90H was seen. tusq: call dnch ;decode next character jnc G15 ! jmp chek ! G15: ;verify the checksum cmp al,090H ;repeat last character jnz tusu ;normal character call dnch ;decode next character or al,al jnz tusr mov al,090H call tpye jmp tusq tusr: dec al ;get count, adjust it mov ch,al ;set count aside tust: mov al,lach ;last character typed call tpye ;type char & add to checksum dec ch ;update count jnz tust ;repeat until exhausted jmp tusq ;type unsqueezed code tusu: mov lach,al ;last character typed call tpye ;type char & add to checksum jmp tusq ;type unsqueezed code ; Decode next character. dnch: mov bx,(offset code) ;decoding table dncr: call rbit ;read next bit jnc dncs ;skip for 1, stay for 0 inc bx inc bx dncs: mov ax,[bx] ;get next offset cmp ax,0FEFFH jz dnct or ax,ax jns dncu ;p means new offset not al stc cmc ret dnct: stc ;flag [end] with carry bit ret ; Calculate +4*. dncu: mov bx,(offset code) ;decoding table add ax,ax add ax,ax add bx,ax jmp dncr ; Type CR, LF. crlf: mov al,CR call cona ;type character at console mov al,LF jmp cona ;type character at console ; Type unsqueezed text and accumulate checksum. tpye: push bx push dx push cx push ax mov bx,(offset cksm) ;checksum mov ch,al mov al,(byte ptr[bx]) sub al,ch mov [bx],al inc bx mov al,(byte ptr[bx]) sbb al,0 mov [bx],al mov al,ch call wbyt ;send character to .COM file pop ax pop cx pop dx pop bx ret ; Upper case fold. ucfo: cmp al,'a' jc ucfr cmp al,'{' jnc ucfr and al,5FH ucfr: ret ; Send character in accumulator to console. cona: push bx push dx push cx mov cl,2 ;(02) char to console mov dl,al int BDOS pop cx pop dx pop bx ret ; Send message to the console. mssg: mov cl,9 ;(09) print buffer int BDOS ret ; Verify the checksum. chek: mov bx,cksm ;checksum mov al,bh or al,bl jnz G24 ! jmp clof ! G24: ;close the file mov cl,19 ;(13) delete file mov dx,(offset ufcb) ;unsqueezed FCB int BDOS mov dx,(offset chno) ;'Checksum failure.' call ferm ;final (error) message ; Open squeezed file. opef: mov bx,(offset qfcb+32) mov (byte ptr[bx]),00 ;squeezed FCB mov dx,(offset qfcb) ;squeezed FCB mov cl,15 ;(0F) open file int BDOS inc al jz G25 ! ret ! G25: mov dx,(offset nfil) ;'requested file not found' jmp ferm ;final (error) message ; Close unsqueezed file. clof: mov al,uctr ;occupancy of .UNS buffer cmp al,usiz ;size of .UNS buffer jz G26 ! call wrdi ! G26: mov cl,16 ;(10) close file mov dx,(offset ufcb) ;unsqueezed FCB int BDOS cmp al,0FFH mov dx,(offset nclo) ;'cannot close file' jnz G27 ! jmp ferm ! G27: ;final (error) message jmp exit ; Read one bit at a time. rbit: push bx dec roco ;rotation count jnz rbiu mov roco,8 call rbyt ;fetch one byte from input stream mov roby,al ;rotating byte rbiu: rcr roby,1 ;rotating byte pop bx ret ; Read one word. rwor: call rbyt ;fetch one byte from input stream push ax call rbyt ;fetch one byte from input stream pop bx mov bh,al ret ; Read one byte, refill buffer as needed. rbyt: push bx mov bx,qctr ;byte counter - input buffer mov al,bl or al,bh jnz rbyu call rdsk mov bx,(offset qbuf) ;squeezed buffer mov qptr,bx ;byte pointer - input buffer mov bx,(offset qsiz) ;size of squeezed file buffer rbyu: dec bx mov qctr,bx ;byte counter - input buffer mov bx,qptr ;byte pointer - input buffer mov al,(byte ptr[bx]) inc bx mov qptr,bx ;byte pointer - input buffer pop bx ret ; Insert byte in .UNS buffer. wbyt: push bx mov bx,(offset uctr) ;occupancy of .UNS buffer dec (byte ptr[bx]) jnz wbyy mov (byte ptr[bx]),usiz ;size of .UNS buffer push ax mov bx,(offset ubuf) ;unsqueezed buffer mov uptr,bx ;pointer to .UNS buffer call wrdi call cbuz ;clear output buffer to zeroes pop ax wbyy: mov bx,uptr ;pointer to .UNS buffer mov [bx],al inc bx mov uptr,bx ;pointer to .UNS buffer pop bx ret ; Send ubuf to disk. wrdi: mov cl,26 ;(1A) set DMA address mov dx,(offset ubuf) ;unsqueezed buffer int BDOS mov cl,21 ;(15) write one record mov dx,(offset ufcb) ;unsqueezed DCB int BDOS cmp al,00H mov dx,(offset werr) ;'disk write' jz G31 ! jmp ferm ! G31: ;final (error) message ret rdsk: push bx push dx push cx mov cl,26 ;(1A) set DMA address mov dx,(offset qbuf) ;squeezed buffer int BDOS mov cl,20 ;(14) read one record mov dx,(offset qfcb) ;squeezed FCB int BDOS pop cx pop dx pop bx ret ; Fill ubuf with zeroes. cbuz: xor al,al mov ch,1 ;one sector in buffer mov bx,(offset ubuf) ;unsqueezed buffer cbuy: mov cl,tsiz ;record size cbux: mov [bx],al inc bx dec cl jnz cbux dec ch jnz cbuy ret ; Block fill with C B's starting at (HL). fiuc: mov (byte ptr[bx]),ch inc bx dec cl jnz fiuc ;block fill ret logo db ' UNSQ/ICUAP',CR,LF db 'Universidad Autonoma de Puebla',CR,LF db ' July 16, 1984',CR,LF,'$' tuto db 'UNSQ.A86 will restore files which have been squeezed',CR,LF db 'by SQ.COM or some similar program.',CR,LF,CR,LF db ' UNSQ [X:]FILE[.QQQ]',CR,LF db CR,LF db 'will read [X:]FILE.SQZ to produce [X:]FILE.UNS.',CR,LF db '$' werr db CR,LF,'Disk write error.$' nfil db CR,LF,'Requested file not present.$' yexi db CR,LF,'Unsqueezed file already exists.$' ntab db CR,LF,'Insufficient space for dictionary.$' nsqz db CR,LF,'Not a squeezed file.$' chno db CR,LF,'Checksum failure.$' nopn db CR,LF,'Can''t open source.$' nodi db CR,LF,'Disk or Directory full.$' nclo db CR,LF,'Cannot close file.$' ufcb rb 21H ;unsqueezed FCB uctr rb 1 ;occupancy of .UNS buffer uptr rw 1 ;pointer to .UNS buffer ubuf rb usiz ;unsqueezed buffer reco rb 1 ;record counter rbrk rw 1 ;record breakpoint lach rb 1 ;last character typed roco rb 1 ;rotating bit counter roby rb 1 ;rotating byte qctr rw 1 ;byte counter - input buffer qptr rw 1 ;byte pointer - input buffer cksm rw 1 ;checksum code rb 4*csiz ;decoding table rb 100 stak rw 1 ;stackend end