; ------------------------------------------------------------ ; UNSQ.ASM 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.ASM 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. ; It reads a squeezed file, recovering the original unsqueezed ; file as its output. ; ; UNSQ.ASM Copyright (C) 1984 ; Universidad Autonoma de Puebla ; July 16, 1984 ; ; [Harold V. McIntosh, 16 July 1984] ; ------------------------------------------------------------ BDOS equ 0005H 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: lxi h,0000 dad sp shld stak ;save sp lxi sp,stak ;stackend lda qfcb+1 ;squeezed FCB cpi ' ' jnz notu lxi d,tuto ferm: call mssg exit: jmp 0000 notu: lxi h,ubuf ;unsqueezed buffer shld uptr ;pointer to .UNS buffer lxi h,qbuf ;squeezed buffer shld qptr ;squeezed file index lxi b,0021H ;33 00's lxi h,ufcb ;unsqueezed FCB call fiuc ;block fill lxi b,200BH ;11 blanks lxi h,ufcb+1 ;unsqueezed FCB call fiuc ;block fill call opef ;open squeezed file lxi h,0000 shld qctr lxi h,uctr ;occupancy of .UNS buffer mvi m,usiz+1 ;size of .UNS buffer lxi h,roco mvi m,1 cota: call rbyt ;fetch one byte from input stream cpi 076H jnz cote ;'not squeezed file' call rbyt ;fetch one byte from input stream cpi 0FFH jz rchk ;read checksum cote: lxi d,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 shld cksm ;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. mvi b,8 lxi h,ufcb+1 ;unsqueezed FCB luup: call rbyt ;fetch one byte from input stream ora a jz luuw ;load code dictionary cpi '.' jz luuw call ucfo mov m,a inx h call cona dcr b jnz luup luuz: call rbyt ora a jz ldic cpi '.' jnz luuz luuw: call cona mvi b,3 lxi h,ufcb+9 ;unsqueezed FCB luur: call rbyt ora a jz ldic call ucfo mov m,a inx h call cona dcr b jnz luur luus: call rbyt ora a 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 lxi b,csiz mov a,c sub l mov a,b sbb h jnc ldii lxi d,ntab ;'insufficient dictionary space' jmp ferm ;final (error) message ldii: dad h dad h mov c,l mov b,h lxi d,code ;decoding table luuq: call rbyt ;fetch one byte from input stream stax d inx d dcx b mov a,c ora b jnz luuq call crlf ;type CR,LF mvi c,26 ;(1A) set DMA address lxi d,ubuf ;unsqueezed buffer call BDOS lxi d,ufcb ;unsqueezed FCB mvi c,17 ;(11) search for file call BDOS inr a jz nexi lxi d,yexi ;'file already exists' jmp ferm ;final (error) message nexi: lxi d,ufcb ;unsqueezed FCB mvi c,22 ;(16) create file call BDOS lxi d,ufcb ;unsqueezed FCB mvi c,15 ;(0F) open file call BDOS cpi 0FFH lxi d,nodi ;'no more directory' jz ferm ;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 jc chek ;verify the checksum cpi 090H ;repeat last character jnz tusu ;normal character call dnch ;decode next character ora a jnz tusr mvi a,090H call type jmp tusq tusr: dcr a ;get count, adjust it mov b,a ;set count aside tust: lda lach ;last character typed call type ;type char & add to checksum dcr b ;update count jnz tust ;repeat until exhausted jmp tusq ;type unsqueezed code tusu: sta lach ;last character typed call type ;type char & add to checksum jmp tusq ;type unsqueezed code ; Decode next character. dnch: lxi h,code ;decoding table dncr: call rbit ;read next bit jnc dncs ;skip for 1, stay for 0 inx h inx h dncs: mov e,m ;get next offset inx h mov d,m mov a,d cpi 0FEH ;FEFF means [end] jz dnct ora a jp dncu ;p means new offset mov a,e ;m means complemented char cma stc cmc ret dnct: stc ;flag [end] with carry bit ret ; Calculate +4*. dncu: lxi h,code ;decoding table dad d dad d dad d dad d jmp dncr ; Type CR, LF. crlf: mvi a,CR call cona ;type character at console mvi a,LF jmp cona ;type character at console ; Type unsqueezed text and accumulate checksum. type: push h push d push b push psw lxi h,cksm ;checksum mov b,a mov a,m sub b mov m,a inx h mov a,m sbi 0 mov m,a mov a,b call wbyt ;send character to .COM file pop psw pop b pop d pop h ret ; Upper case fold. ucfo: cpi 'a' rc cpi '{' rnc ani 5FH ret ; Send character in accumulator to console. cona: push h push d push b mvi c,2 ;(02) char to console mov e,a call BDOS pop b pop d pop h ret ; Send message to the console. mssg: mvi c,9 ;(09) print buffer jmp BDOS ; Verify the checksum. chek: lhld cksm ;checksum mov a,h ora l jz clof ;close the file mvi c,19 ;(13) delete file lxi d,ufcb ;unsqueezed FCB call BDOS lxi d,chno ;'Checksum failure.' call ferm ;final (error) message ; Open squeezed file. opef: xra a sta qfcb+32 ;squeezed FCB lxi d,qfcb ;squeezed FCB mvi c,15 ;(0F) open file call BDOS inr a rnz lxi d,nfil ;'requested file not found' jmp ferm ;final (error) message ; Close unsqueezed file. clof: lda uctr ;occupancy of .UNS buffer cpi usiz ;size of .UNS buffer cnz wrdi mvi c,16 ;(10) close file lxi d,ufcb ;unsqueezed FCB call BDOS cpi 0FFH lxi d,nclo ;'cannot close file' jz ferm ;final (error) message jmp exit ; Read one bit at a time. rbit: push h lxi h,roco ;bit rotation counter dcr m jnz rbiu mvi m,8 call rbyt ;fetch one byte from input stream sta roby ;rotating byte rbiu: lda roby ;rotating byte rar sta roby ;rotating byte pop h ret ; Read one word. rwor: call rbyt ;fetch one byte from input stream push psw call rbyt ;fetch one byte from input stream pop h mov l,h mov h,a ret ; Read one byte, refill buffer as needed. rbyt: push h lhld qctr ;byte counter - input buffer mov a,l ora h jnz rbyu call rdsk lxi h,qbuf ;squeezed buffer shld qptr ;byte pointer - input buffer lxi h,qsiz ;size of squeezed file buffer rbyu: dcx h shld qctr ;byte counter - input buffer lhld qptr ;byte pointer - input buffer mov a,m inx h shld qptr ;byte pointer - input buffer pop h ret ; Insert byte in .UNS buffer. wbyt: push h lxi h,uctr ;occupancy of .UNS buffer dcr m jnz wbyy mvi m,usiz ;size of .UNS buffer push psw lxi h,ubuf ;unsqueezed buffer shld uptr ;pointer to .UNS buffer call wrdi call cbuz ;clear output buffer to zeroes pop psw wbyy: lhld uptr ;pointer to .UNS buffer mov m,a inx h shld uptr ;pointer to .UNS buffer pop h ret ; Send ubuf to disk. wrdi: mvi c,26 ;(1A) set DMA address lxi d,ubuf ;unsqueezed buffer call BDOS mvi c,21 ;(15) write one record lxi d,ufcb ;unsqueezed DCB call BDOS cpi 00H lxi d,werr ;'disk write' jnz ferm ;final (error) message ret rdsk: push h push d push b mvi c,26 ;(1A) set DMA address lxi d,qbuf ;squeezed buffer call BDOS mvi c,20 ;(14) read one record lxi d,qfcb ;squeezed FCB call BDOS pop b pop d pop h ret ; Fill ubuf with zeroes. cbuz: xra a mvi b,1 ;one sector in buffer lxi h,ubuf ;unsqueezed buffer cbuy: mvi c,tsiz ;record size cbux: mov m,a inx h dcr c jnz cbux dcr b jnz cbuy ret ; Block fill with C B's starting at (HL). fiuc: mov m,b inx h dcr c jnz fiuc ;block fill ret logo: db ' UNSQ/ICUAP',CR,LF db 'Universidad Autonoma de Puebla',CR,LF db ' July 16, 1983',CR,LF,'$' tuto: db 'UNSQ.ASM 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: ds 21H ;unsqueezed FCB uctr: ds 1 ;occupancy of .UNS buffer uptr: ds 2 ;pointer to .UNS buffer ubuf: ds usiz ;unsqueezed buffer reco: ds 1 ;record counter rbrk: ds 2 ;record breakpoint lach: ds 1 ;last character typed roco: ds 1 ;rotating bit counter roby: ds 1 ;rotating byte qctr: ds 2 ;byte counter - input buffer qptr: ds 2 ;byte pointer - input buffer cksm: ds 2 ;checksum code: ds 4*csiz ;decoding table ds 100 stak: ds 2 ;stackend end