home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / arc_lbr / mdcd10.arc / MDCD1213.ASM < prev    next >
Assembly Source File  |  1988-10-26  |  61KB  |  1,221 lines

  1. ;---- 10/26/1988  00:26:45 ----}
  2.           name      mdcd1213
  3.           page      82,132
  4.           title     'MDCD1213.OBJ 12/13 bit LZW file compress/decompress
  5. ;-----------------------------------------------------------------------------
  6. ;                                                                            -
  7. ;                                   `MDCD1213'                               -
  8. ;                                                                            -
  9. ; This is a modified version of LZ.ARC, obtained from the EXEC PC BBS        -
  10. ; in Milwaukee WI. on 8/20/88.  It has been changed to work as an external   -
  11. ; modlule and has been tested with Turbo Pascal 5.0.                         -
  12. ;                                                                            -
  13. ; It was assembled with Turbo Assembler 1.0 but will assemble with MASM.     -
  14. ; but will assemble with MASM.  The following modifications have been made:  -
  15. ;                                                                            -
  16. ;   1. Removed the malloc memory allocation for the hash table out to        -
  17. ;       the caller so that it can be allocated from the heap.                -
  18. ;   2. Added the CompressFile & DecompressFile function interface.           -
  19. ;   3. Minor cleanup and use of equ values for easy buffer size changes.     -
  20. ;   4. Initialized DS variables normally done by MASM/LINK, but not by some  -
  21. ;       other HLL's (e.g. Turbo Pascal).                                     -
  22. ;   5. Input file & output file allocated and opened externally by caller.   -
  23. ;       Only the file handles are passed to this module.                     -
  24. ;   6. Super fast CRC 16 (communications type) routine added to accumulate   -
  25. ;       the compressed & decompressed file's CRC for reliability.            -
  26. ;   7. Original program used a macro file.  The few that were used were      -
  27. ;       removed and coded inline for single module simplicity.               -
  28. ;   8. Increased disk input and output buffers to 8192 bytes each            -
  29. ;       (from 1024). This seems to be a good trade-off for speed/memory.     -
  30. ;   9. Moved the disk input and output buffers to CS to preserve precious    -
  31. ;       Turbo Pascal DS space.                                               -
  32. ;  10. Combined LZCOMP.ASM & LZDCMP.ASM into 1 module                        -
  33. ;  11. Allowed the beginning file offset to write to and read from to be     -
  34. ;       specified to provide for (n) files in a compressed file.             -
  35. ;  12. Replaced DIVide instructions with shifts, ands and moves.             -
  36. ;  13. Added 13 bit LZW compression based on passed parameter.               -
  37. ;                                                                            -
  38. ;                       Modified by..                                        -
  39. ;                         Mike Davenport                                     -
  40. ;                         Mike Davenport & Associates                        -
  41. ;                         6751 N. Blackstone Ave. Suite 252                  -
  42. ;                         Fresno CA  93710                                   -
  43. ;                         Voice: (209) 298-8846                              -
  44. ;                         CIS:   76676,1362                                  -
  45. ;                         PLINK: MIKE D                                      -
  46. ;                         GENIE: MDAVENPORT                                  -
  47. ;                         Amiga Techniques + PC Tech BBS - (GT POWER)        -
  48. ;                         (209) 298-8453 - 1200-9600 HST (24 hours)          -
  49. ;                                                                            -
  50. ;                       Original Author..                                    -
  51. ;                         Tom Pfau                                           -
  52. ;                         Digital Equipment Corporation                      -
  53. ;                         Parsippany, NJ                                     -
  54. ;                                                                            -
  55. ;-----------------------------------------------------------------------------
  56. ;                                                                            -
  57. ;                          ---------------------                             -
  58. ;                          MODULE CHANGE HISTORY                             -
  59. ;                          ---------------------                             -
  60. ;                                                                            -
  61. ; change#  ..date..  by  .................. change ........................  -
  62. ;                                                                            -
  63. ;   000    09-06-88  md  Original module creation                            -
  64. ;   001    10-19-88  md  added 13 bit LZW compression                        -
  65. ;   001    10-26-88  md  Original module finished                            -
  66. ;                                                                            -
  67. ;-----------------------------------------------------------------------------
  68.  
  69.  
  70. ;----------
  71. ; constants
  72. ;----------
  73. clear            equ     256            ;Clear code
  74. eof              equ     257            ;End of file marker
  75. fhdr_len         equ     128            ;size of file header for file type 1
  76. first_free       equ     258            ;First free code
  77.  
  78.  
  79. ;NOTE: this module will not handle buffers larger than 8k due to the design
  80. ;      of the original code.  It carries the total bits in the buffer waiting
  81. ;      to be written to disk in a word then divides by 8 to compare bytes.
  82. ;      Buffers > 8192 will cause the WORD that holds the total bits to
  83. ;      overflow.  I decided not to mess with this because buffers > 4096
  84. ;      didn't seem to have a worthwhile memory vs. speed tradeoff that
  85. ;      justified the non-trivial changes.   In other words, I'm lazy!
  86.  
  87. input_data_size  equ     8192           ;input data buffer size
  88. input_data_chk   equ     8187           ;size to check end of input coming up
  89. output_data_size equ     8192           ;output data buffer size
  90. output_data_chk  equ     8188           ;size to check output buffer write
  91.  
  92.  
  93. ;--------------------------
  94. ; compress hash table entry
  95. ;--------------------------
  96. hash_rec        struc
  97. first   dw      ?                       ; First entry with this value
  98. next    dw      ?                       ; Next entry along chain
  99. char    db      ?                       ; Suffix char
  100. hash_rec        ends
  101.  
  102. ;----------------------------
  103. ; decompress hash table entry
  104. ;----------------------------
  105. dhash_rec       struc
  106. dnext   dw      ?                       ; prefix code
  107. dchar   db      ?                       ; suffix char
  108. dhash_rec       ends
  109.  
  110. ;------------------------------ DATA SEGMENT ---------------------------------
  111.  
  112. data    segment word
  113.  
  114. ; data will be initialized upon entry into CompressFile or DecompressFile
  115. ; because some HLL's do not do this as does MASM/LINK.
  116.  
  117.  
  118. ; original LZCOMP.ASM data
  119.  
  120. bit_offset      dw      ?               ;
  121. free_code       dw      ?               ;
  122. hash_seg        dw      ?               ;segment of hash table from caller
  123. input_handle    dw      ?               ;input file handle from caller
  124. input_offset    dw      0               ;offset of next byte to read for input
  125. input_size      dw      0               ;number of input bytes read
  126. k               db      ?               ;
  127. max_code        dw      ?               ;
  128. nbits           dw      ?               ;number of bits for current code size
  129. output_handle   dw      ?               ;output file handle from caller
  130. prefix_code     dw      ?               ;
  131.  
  132. ; original data unique to LZDCMP.ASM
  133.  
  134. dhash_seg       dw      ?
  135. cur_code        dw      ?
  136. old_code        dw      ?
  137. in_code         dw      ?
  138. stack_count     dw      0
  139. dmax_code       dw      512             ;hash table bytes for 9 bit codes
  140. fin_char        db      ?
  141. masks           dw      1ffh,3ffh,7ffh,0fffh,0ffffh  ;9-13 bit masks
  142. dbit_offset     dw      0
  143. output_offset   dw      0
  144.  
  145. ; miscellaneous variables
  146.  
  147. maxmax          dw      ?               ;max hash table bytes (12/13 bit)
  148. maxbits         dw      ?               ;max bits for lzw (12 or 13)
  149. crc             dw      ?               ;file crc
  150. byte_hi         dw      ?               ;hi order byte of double word lseek
  151. byte_lo         dw      ?               ;lo order byte of double word lseek
  152. rtn_seg         dw      ?               ;return address segment
  153. rtn_ofs         dw      ?               ;return address offset
  154. totalbytes1     dw      ?               ;total file bytes written low
  155. totalbytes2     dw      ?               ;total file bytes written high
  156. rc              dw      ?               ;return code for caller
  157.  
  158. data    ends
  159.  
  160.  
  161. ;------------------------------ CODE SEGMENT ---------------------------------
  162.  
  163. code    segment word
  164.         assume  cs:code, ds:data, es:data, ss:nothing
  165.  
  166.         PUBLIC  CompressFile
  167.         PUBLIC  DeCompressFile
  168.  
  169. ; disk i/o buffers & CRC table are in CS to preserve DS space
  170.  
  171. input_data      db      8192 dup (?)    ;disk input buffer
  172. output_data     db      8192 dup (?)    ;disk output buffer
  173.  
  174.  
  175. ; Machine Code with CRC Table 256 - CRC Polynomial Divisor = $11021
  176.  
  177. crctab  dw      00000h, 01021h, 02042h, 03063h, 04084h, 050A5h, 060C6h, 070E7h
  178.         dw      08108h, 09129h, 0A14Ah, 0B16Bh, 0C18Ch, 0D1ADh, 0E1CEh, 0F1EFh
  179.         dw      01231h, 00210h, 03273h, 02252h, 052B5h, 04294h, 072F7h, 062D6h
  180.         dw      09339h, 08318h, 0B37Bh, 0A35Ah, 0D3BDh, 0C39Ch, 0F3FFh, 0E3DEh
  181.         dw      02462h, 03443h, 00420h, 01401h, 064E6h, 074C7h, 044A4h, 05485h
  182.         dw      0A56Ah, 0B54Bh, 08528h, 09509h, 0E5EEh, 0F5CFh, 0C5ACh, 0D58Dh
  183.         dw      03653h, 02672h, 01611h, 00630h, 076D7h, 066F6h, 05695h, 046B4h
  184.         dw      0B75Bh, 0A77Ah, 09719h, 08738h, 0F7DFh, 0E7FEh, 0D79Dh, 0C7BCh
  185.         dw      048C4h, 058E5h, 06886h, 078A7h, 00840h, 01861h, 02802h, 03823h
  186.         dw      0C9CCh, 0D9EDh, 0E98Eh, 0F9AFh, 08948h, 09969h, 0A90Ah, 0B92Bh
  187.         dw      05AF5h, 04AD4h, 07AB7h, 06A96h, 01A71h, 00A50h, 03A33h, 02A12h
  188.         dw      0DBFDh, 0CBDCh, 0FBBFh, 0EB9Eh, 09B79h, 08B58h, 0BB3Bh, 0AB1Ah
  189.         dw      06CA6h, 07C87h, 04CE4h, 05CC5h, 02C22h, 03C03h, 00C60h, 01C41h
  190.         dw      0EDAEh, 0FD8Fh, 0CDECh, 0DDCDh, 0AD2Ah, 0BD0Bh, 08D68h, 09D49h
  191.         dw      07E97h, 06EB6h, 05ED5h, 04EF4h, 03E13h, 02E32h, 01E51h, 00E70h
  192.         dw      0FF9Fh, 0EFBEh, 0DFDDh, 0CFFCh, 0BF1Bh, 0AF3Ah, 09F59h, 08F78h
  193.         dw      09188h, 081A9h, 0B1CAh, 0A1EBh, 0D10Ch, 0C12Dh, 0F14Eh, 0E16Fh
  194.         dw      01080h, 000A1h, 030C2h, 020E3h, 05004h, 04025h, 07046h, 06067h
  195.         dw      083B9h, 09398h, 0A3FBh, 0B3DAh, 0C33Dh, 0D31Ch, 0E37Fh, 0F35Eh
  196.         dw      002B1h, 01290h, 022F3h, 032D2h, 04235h, 05214h, 06277h, 07256h
  197.         dw      0B5EAh, 0A5CBh, 095A8h, 08589h, 0F56Eh, 0E54Fh, 0D52Ch, 0C50Dh
  198.         dw      034E2h, 024C3h, 014A0h, 00481h, 07466h, 06447h, 05424h, 04405h
  199.         dw      0A7DBh, 0B7FAh, 08799h, 097B8h, 0E75Fh, 0F77Eh, 0C71Dh, 0D73Ch
  200.         dw      026D3h, 036F2h, 00691h, 016B0h, 06657h, 07676h, 04615h, 05634h
  201.         dw      0D94Ch, 0C96Dh, 0F90Eh, 0E92Fh, 099C8h, 089E9h, 0B98Ah, 0A9ABh
  202.         dw      05844h, 04865h, 07806h, 06827h, 018C0h, 008E1h, 03882h, 028A3h
  203.         dw      0CB7Dh, 0DB5Ch, 0EB3Fh, 0FB1Eh, 08BF9h, 09BD8h, 0ABBBh, 0BB9Ah
  204.         dw      04A75h, 05A54h, 06A37h, 07A16h, 00AF1h, 01AD0h, 02AB3h, 03A92h
  205.         dw      0FD2Eh, 0ED0Fh, 0DD6Ch, 0CD4Dh, 0BDAAh, 0AD8Bh, 09DE8h, 08DC9h
  206.         dw      07C26h, 06C07h, 05C64h, 04C45h, 03CA2h, 02C83h, 01CE0h, 00CC1h
  207.         dw      0EF1Fh, 0FF3Eh, 0CF5Dh, 0DF7Ch, 0AF9Bh, 0BFBAh, 08FD9h, 09FF8h
  208.         dw      06E17h, 07E36h, 04E55h, 05E74h, 02E93h, 03EB2h, 00ED1h, 01EF0h
  209.  
  210.  
  211. ; save area for critical registers so we can unwind and return to caller
  212. ;  in the event of a severe error
  213.  
  214. savebp     dw   ?                       ;save bp
  215. savesp     dw   ?                       ;save sp
  216. savess     dw   ?                       ;save ss
  217. saveds     dw   ?                       ;save ds
  218. saveparms  dw   ?                       ;number of stack bytes for parms
  219.  
  220. ;---------------------------------------------------------------------------;
  221. ;                                                                           ;
  222. ;                        COMPRESSION ROUTINES                               ;
  223. ;                                                                           ;
  224. ;                             'Compress'                                    ;
  225. ;                                                                           ;
  226. ;---------------------------------------------------------------------------;
  227.  
  228. compress        proc    near
  229.  
  230. l1:     call    cinit_table             ;Initialize the table and some vars
  231.         mov     ax,clear                ;Write a clear code
  232.         call    write_code
  233.         call    read_char               ;Read first char
  234. l4:     xor     ah,ah                   ;Turn char into code
  235. l4a:    mov     prefix_code,ax          ;Set prefix code
  236.         call    read_char               ;Read next char
  237.         jc      l17                     ;Carry means eof
  238.         mov     k,al                    ;Save char in k
  239.         mov     bx,prefix_code          ;Get prefix code
  240.         call    lookup_code             ;See if this pair in table
  241.         jnc     l4a                     ;nc means yes, new code in ax
  242.         call    add_code                ;Add pair to table
  243.         push    bx                      ;Save new code
  244.         mov     ax,prefix_code          ;Write old prefix code
  245.         call    write_code
  246.         pop     bx
  247.         mov     al,k                    ;Get last char
  248.         cmp     bx,max_code             ;Exceed code size?
  249.         jl      l4                      ;less means no
  250.         mov     cx,maxbits              ;get maxbits for compare
  251.         cmp     nbits,cx                ;Currently less than (12 or 13) bits?
  252.         jl      l14                     ;yes
  253.         mov     ax,clear                ;Write a clear code
  254.         call    write_code
  255.         call    cinit_table             ;Reinit table
  256.         mov     al,k                    ;get last char
  257.         jmp     l4                      ;Start over
  258. l14:    inc     nbits                   ;Increase number of bits
  259.         shl     max_code,1              ;Double max code size
  260.         jmp     l4                      ;Get next char
  261. l17:    mov     ax,prefix_code          ;Write last code
  262.         call    write_code
  263.         mov     ax,eof                  ;Write eof code
  264.         call    write_code
  265.         mov     ax,bit_offset           ;Make sure buffer is flushed to file
  266.         cmp     ax,0
  267.         je      l18
  268.  
  269. ; convert bits to bytes
  270.  
  271.         mov     dx,ax                   ;get all of ax
  272.         and     dx,07h                  ;simulate remainder modulo 8
  273.         shr     ax,1                    ;divide ax by 8 (2)
  274.         shr     ax,1                    ;  "       "    (4)
  275.         shr     ax,1                    ;  "       "    (8)
  276.  
  277.         or      dx,dx                   ;If extra bits, make sure they get
  278.         je      l17a                    ;written
  279.         inc     ax
  280. l17a:   call    flush
  281. l18:    ret
  282.  
  283. compress        endp
  284.  
  285.  
  286. ;---------------------------------------------------------------------------;
  287. ;                                                                           ;
  288. ;                             'cinit_table'                                 ;
  289. ;                                                                           ;
  290. ;---------------------------------------------------------------------------;
  291.  
  292. cinit_table     proc    near
  293.  
  294.         mov     nbits,9                 ;Set code size to start at 9 bits
  295.         mov     max_code,512            ;Set max code to 512
  296.         push    es                      ;Save seg reg
  297.         mov     es,hash_seg             ;Address hash table
  298.         mov     ax,-1                   ;Unused flag
  299.         mov     cx,640                  ;Clear first 256 entries (256*5/2 words)
  300.         mov     di,0                    ;Point to begin of hash table
  301. rep     stosw                           ;Clear it out
  302.         pop     es                      ;Restore seg reg
  303.         mov     free_code,first_free    ;Set next code to use
  304.         ret                             ;done
  305.  
  306. cinit_table     endp
  307.  
  308.  
  309. ;---------------------------------------------------------------------------;
  310. ;                                                                           ;
  311. ;                             'write_code'                                  ;
  312. ;                                                                           ;
  313. ;---------------------------------------------------------------------------;
  314.  
  315. write_code      proc    near
  316.  
  317.         push    ax                      ;Save code
  318.         mov     ax,bit_offset           ;Get bit offset
  319.         mov     cx,nbits                ;Adjust bit offset by code size
  320.         add     bit_offset,cx
  321.  
  322. ;
  323. ; the five following instructions are the same as:
  324. ;
  325. ;;;;    mov     cx,8                    ;Convert bit offset to byte offset
  326. ;;;;    xor     dx,dx
  327. ;;;;    div     cx
  328. ;
  329. ; the above instructions take approximately 170 cycles, the 5 instructions
  330. ; below take 12 cycles.  These instructions divide the contents of ax by 8
  331. ; and store the remainder in dx.  This is done for speeeeeed ! For anyone
  332. ; interested, I ran some timings on some LARGE files and it did not make
  333. ; a measurable difference in time.  Oh well.. I just hate seeing DIV
  334. ; instructions in often repeated routines.
  335. ;
  336.         mov     dx,ax                   ;get all of ax
  337.         and     dx,07h                  ;simulate remainder modulo 8
  338.         shr     ax,1                    ;divide ax by 8 (2)
  339.         shr     ax,1                    ;  "       "    (4)
  340.         shr     ax,1                    ;  "       "    (8)
  341.  
  342.         cmp     ax,output_data_chk      ;Approaching end of buffer?
  343.         jl      wc1                     ;less means no
  344.         call    flush                   ;Write the buffer
  345.         push    dx                      ;dx contains offset within byte
  346.         add     dx,nbits                ;adjust by code size
  347.         mov     bit_offset,dx           ;new bit offset
  348.         pop     dx                      ;restore dx
  349.         add     ax,offset output_data   ;Point to last byte
  350.         mov     si,ax                   ;put in si
  351.         mov     al,cs:byte ptr [si]     ;move byte to first position
  352.         mov     cs:output_data,al
  353.         xor     ax,ax                   ;Byte offset of zero
  354. wc1:    add     ax,offset output_data   ;Point into buffer
  355.         mov     di,ax                   ;Destination
  356.         pop     ax                      ;Restore code
  357.         push    es                      ;save es
  358.         mov     cx,cs                   ;mov es,cs to reference disk output
  359.         mov     es,cx                   ;... buffer in cs for stosw/stosb
  360.         mov     cx,dx                   ;offset within byte
  361.         xor     dx,dx                   ;dx will catch bits rotated out
  362.         jcxz    wc3                     ;If offset in byte is zero, skip shift
  363. wc2:    shl     ax,1                    ;Rotate code
  364.         rcl     dx,1
  365.         loop    wc2
  366.         or      al,cs:byte ptr [di]     ;Grab bits currently in buffer
  367. wc3:    stosw                           ;Save data
  368.         mov     al,dl                   ;Grab extra bits
  369.         stosb                           ;and save
  370.         pop     es                      ;restore es
  371.         ret
  372.  
  373. write_code      endp
  374.  
  375.  
  376. ;---------------------------------------------------------------------------;
  377. ;                                                                           ;
  378. ;                             'flush'                                       ;
  379. ;                                                                           ;
  380. ;---------------------------------------------------------------------------;
  381.  
  382. flush   proc    near
  383.  
  384.         push    ax                      ;Save all registers
  385.         push    bx                      ;AX contains number of bytes to write
  386.         push    cx
  387.         push    dx
  388.  
  389. ; write data to disk
  390.  
  391.         add     totalbytes1,ax          ;accumulate total bytes written
  392.         jnc     noof3                   ;if no carry, skip
  393.         inc     totalbytes2             ;else increment for long add
  394. noof3:                                  ;
  395.         mov     bx,output_handle        ;setup output file handle
  396.         push    ds                      ;save ds
  397.         mov     cx,cs                   ;mov ds,cs to reference disk output
  398.         mov     ds,cx                   ;... buffer in cs when calling dos
  399.         lea     dx,output_data          ;address of output buffer
  400.         mov     cx,ax                   ;number of bytes to write
  401.         mov     ah,40h                  ;dos function - write to file/device
  402.         int     21h                     ;call dos
  403.         jnc     i21ok1                  ;if no disk error, continue
  404.         jmp     diskerror               ;else report disk error and exit
  405. i21ok1:
  406.         pop     ds                      ;restore ds
  407.  
  408.         pop     dx                      ;restore saved registers
  409.         pop     cx
  410.         pop     bx
  411.         pop     ax
  412.         ret
  413.  
  414. flush           endp
  415.  
  416.  
  417. ;---------------------------------------------------------------------------;
  418. ;                                                                           ;
  419. ;                             'read_char'                                   ;
  420. ;                                                                           ;
  421. ;---------------------------------------------------------------------------;
  422.  
  423. read_char       proc    near
  424.  
  425.         mov     di,input_offset         ;Anything left in buffer?
  426.         cmp     di,input_size
  427.         jl      rd1                     ;less means yes
  428.  
  429. ; read data from disk
  430.  
  431.         mov     bx,input_handle         ;setup input file handle
  432.         push    ds                      ;save ds
  433.         mov     dx,cs                   ;mov ds,cs to reference disk input
  434.         mov     ds,dx                   ;... buffer in cs when calling dos
  435.         lea     dx,input_data           ;offset of input buffer
  436.         mov     cx,input_data_size      ;max bytes to read
  437.         mov     ah,3fh                  ;dos function - read from file/device
  438.         int     21h                     ;call dos
  439.         jnc     i21ok2                  ;if no disk error, continue
  440.         jmp     diskerror               ;else report disk error and exit
  441. i21ok2:
  442.         pop     ds                      ;restore ds
  443.         cmp     ax,0                    ;Anything left?
  444.         je      rd2                     ;equal means no, finished
  445.         mov     input_size,ax           ;Save bytes read
  446.         mov     input_offset,0          ;Point to beginning of buffer
  447.         mov     di,0
  448. rd1:
  449.         lea     bx,input_data[di]       ;Point at character
  450.         mov     al,cs:[bx]              ;get next file character into al
  451.  
  452. ; the following CRC16 (ala Xmodem crc) code is inline for max speeeeeeed...!
  453.  
  454.         mov     dx,crc                  ;get old crc
  455.         xchg    dl,dh                   ;swap crc bytes
  456.         xor     ah,ah                   ;make sure ah is zero (al has the data)
  457.         xor     dx,ax                   ;xor low crc with new data byte
  458.         xor     bx,bx                   ;clear bx
  459.         xchg    dl,bl                   ;swap low crc to bl
  460.         shl     bx,1                    ;bx = bx * 2
  461.         xor     dx,cs:[crctab+bx]       ;xor crc with table value
  462.         mov     crc,dx                  ;store updated crc
  463.  
  464.         inc     input_offset            ;Adjust pointer
  465.         clc                             ;Success
  466.         ret
  467. rd2:    stc                             ;Nothing left
  468.         ret
  469.  
  470. read_char       endp
  471.  
  472.  
  473. ;---------------------------------------------------------------------------;
  474. ;                                                                           ;
  475. ;                             'lookup_code'                                 ;
  476. ;                                                                           ;
  477. ;---------------------------------------------------------------------------;
  478.  
  479. lookup_code     proc    near
  480.  
  481.         push    ds                      ;Save seg reg
  482.         mov     ds,hash_seg             ;point to hash table
  483.         call    index                   ;convert code to address
  484.         mov     di,0                    ;flag
  485.         cmp     [si].first,-1           ;Has this code been used?
  486.         je      gc4                     ;equal means no
  487.         inc     di                      ;set flag
  488.         mov     bx,[si].first           ;Get first entry
  489. gc2:    call    index                   ;convert code to address
  490.         cmp     [si].char,al            ;is char the same?
  491.         jne     gc3                     ;ne means no
  492.         clc                             ;success
  493.         mov     ax,bx                   ;put found code in ax
  494.         pop     ds                      ;restore seg reg
  495.         ret                             ;done
  496. gc3:    cmp     [si].next,-1            ;More left with this prefix?
  497.         je      gc4                     ;equal means no
  498.         mov     bx,[si].next            ;get next code
  499.         jmp     gc2                     ;try again
  500. gc4:    stc                             ;not found
  501.         pop     ds                      ;restore seg reg
  502.         ret                             ;done
  503.  
  504. lookup_code     endp
  505.  
  506.  
  507. ;---------------------------------------------------------------------------;
  508. ;                                                                           ;
  509. ;                             'index'                                       ;
  510. ;                                                                           ;
  511. ;---------------------------------------------------------------------------;
  512.  
  513. index           proc    near
  514.  
  515.         mov     si,bx                   ;si = bx * 5 (5 byte hash entries)
  516.         shl     si,1                    ;si = bx * 2 * 2 + bx
  517.         shl     si,1
  518.         add     si,bx
  519.         ret
  520.  
  521. index           endp
  522.  
  523.  
  524. ;---------------------------------------------------------------------------;
  525. ;                                                                           ;
  526. ;                             'add_code'                                    ;
  527. ;                                                                           ;
  528. ;---------------------------------------------------------------------------;
  529.  
  530. add_code        proc    near
  531.  
  532.         mov     bx,free_code            ;Get code to use
  533.         push    ds                      ;point to hash table
  534.         mov     ds,hash_seg             ;get segment of heap hash table
  535.         cmp     di,0                    ;First use of this prefix?
  536.         je      ac1                     ;equal means yes
  537.         mov     [si].next,bx            ;point last use to new entry
  538.         jmp     short ac2
  539. ac1:    mov     [si].first,bx           ;Point first use to new entry
  540. ac2:    cmp     bx,maxmax               ;Have we reached code limit?
  541.         je      ac3                     ;equal means yes, just return
  542.         call    index                   ;get address of new entry
  543.         mov     [si].first,-1           ;initialize pointers
  544.         mov     [si].next,-1
  545.         mov     [si].char,al            ;save suffix char
  546.         inc     es:free_code            ;adjust next code
  547. ac3:    pop     ds                      ;restore seg reg
  548.         ret
  549.  
  550. add_code        endp
  551.  
  552.  
  553. ;---------------------------------------------------------------------------;
  554. ;                                                                           ;
  555. ;                 function   'CompressFile'                                 ;
  556. ;                                                                           ;
  557. ; Function interface to other languages for file compression                ;
  558. ;                                                                           ;
  559. ;   See TESTC.PAS for an example                                            ;
  560. ;                                                                           ;
  561. ;  inhandle & outhandle must be DOS handles of already opened files         ;
  562. ;                                                                           ;
  563. ;  bytehi & bytelo is a long integer specifying the starting byte offset    ;
  564. ;                  of where to start reading the input file                 ;
  565. ;                                                                           ;
  566. ;  rtnseg & rtnofs is a pointer to a return area where this module will     ;
  567. ;                  pass back the CRC and the compressed file size           ;
  568. ;                                                                           ;
  569. ;  hashsegment is the segment:0 address of memory allocated by the caller.  ;
  570. ;                  if you are requesting 12 bit compression, this must point;
  571. ;                  to 20480 bytes of available memory. If you are requesting;
  572. ;                  13 bit, it must point to 40960 bytes of available memory ;
  573. ;                                                                           ;
  574. ;  lzwbits must be a word value of 12 for 12 bit compression or 13 for 13   ;
  575. ;                  bit compression                                          ;
  576. ;                                                                           ;
  577. ;---------------------------------------------------------------------------;
  578.  
  579.  
  580. inhandle        equ     word ptr  [bp+20] ;input handle on stack
  581. outhandle       equ     word ptr  [bp+18] ;output handle on stack
  582. bytehi          equ     word ptr  [bp+16] ;byte offset (hi order)
  583. bytelo          equ     word ptr  [bp+14] ;byte offset (low order)
  584. rtnseg          equ     word ptr  [bp+12] ;segment of return record
  585. rtnofs          equ     word ptr  [bp+10] ;offset of return record
  586. hashsegment     equ     word ptr  [bp+8]  ;segment of hash table
  587. lzwbits         equ     word ptr  [bp+6]  ;number of bits (lzw) 12 or 13
  588.  
  589. cstack          equ     16                ;number of bytes passed on stack
  590.  
  591. ;---------------------------------------------------------------------------;
  592. ;                                                                           ;
  593. ;                 (FAR)       'CompressFile'                                ;
  594. ;                                                                           ;
  595. ;---------------------------------------------------------------------------;
  596.  
  597. CompressFile  proc far
  598.  
  599. ; save bp, sp, ss, ds, and stack parameter count so we can exit this module
  600. ; in the event of an error (e.g. disk i/o)
  601.  
  602.         mov     cs:savebp,bp            ;save bp
  603.         mov     cs:savesp,sp            ;save sp
  604.         mov     cs:savess,ss            ;save ss
  605.         mov     cs:saveds,ds            ;save ds
  606.         mov     cs:saveparms,cstack     ;number of stack bytes for parms
  607.  
  608. ; set up reference to callers parameters and save anything required
  609.  
  610.         push    bp                      ;save bp
  611.         mov     bp,sp                   ;set stack frame to reference my parms
  612.         push    ds                      ;save ds
  613.  
  614. ; set up ds & es addressability
  615.  
  616.         mov     bx,data                 ;Set up data segment addressability
  617.         mov     es,bx                   ;
  618.         mov     ds,bx                   ;
  619.  
  620. ; get parameters from caller
  621.  
  622.         mov     ax,inhandle             ;store input file handle
  623.         mov     input_handle,ax         ;
  624.         mov     ax,outhandle            ;store output file handle
  625.         mov     output_handle,ax        ;
  626.         mov     ax,bytehi               ;store hi order byte offset
  627.         mov     byte_hi,ax              ;
  628.         mov     ax,bytelo               ;store lo order byte offset
  629.         mov     byte_lo,ax              ;
  630.         mov     ax,rtnseg               ;store return address segment
  631.         mov     rtn_seg,ax              ;
  632.         mov     ax,rtnofs               ;store return address offset
  633.         mov     rtn_ofs,ax              ;
  634.         mov     ax,hashsegment          ;store seg pointer to heap hash table
  635.         mov     hash_seg,ax             ;
  636.         mov     cx,lzwbits              ;store lzw type (12 or 13)
  637.         mov     maxbits, cx             ;
  638.         mov     maxmax,1                ;calc max entries for lzw type
  639.         shl     maxmax,cl               ; (12 bit = 4096,  13 bit = 8192)
  640.  
  641.  
  642. ; initialize anything required
  643.  
  644.         mov     input_offset,0          ;clear input_offset
  645.         mov     input_size,0            ;clear input_size
  646.         mov     bit_offset,0            ;clear bit_offset
  647.         mov     crc,0                   ;clear crc for new file
  648.         mov     totalbytes1,0           ;clear bytes written count
  649.         mov     totalbytes2,0           ;
  650.         cld                             ;clear direction flag for di & si
  651.  
  652.  
  653. ; move file pointer so that writes start at the requested byte
  654.  
  655.         mov     bx,output_handle        ;setup output file handle
  656.         mov     cx,byte_hi              ;hi-order byte offset to start write
  657.         mov     dx,byte_lo              ;lo-order byte offset to start write
  658.         mov     ah,42h                  ;dos function - move file pointer
  659.         mov     al,00h                  ;  method = absolute from beginning
  660.         int     21h                     ;call dos
  661.         jnc     i21ok3                  ;if no disk error, continue
  662.         jmp     diskerror               ;else report disk error and exit
  663. i21ok3:
  664.  
  665. ; compress the file
  666.  
  667.         call    compress                ;Compress file
  668.  
  669. ; wrap it up
  670.  
  671.         mov     bx,rtn_ofs              ;setup offset of callers return area
  672.         mov     ds,rtn_seg              ;setup segment of callers return area
  673.         mov     ax,crc                  ;send back crc
  674.         mov     [bx],ax                 ;
  675.         mov     ax,totalbytes1          ;send back low order total bytes
  676.         mov     [bx]+2,ax               ;
  677.         mov     ax,totalbytes2          ;send back high order total bytes
  678.         mov     [bx]+4,ax               ;
  679.         mov     rc,-1                   ;good return code
  680.         mov     ax,rc                   ;function return = return code
  681.         pop     ds                      ;restore ds
  682.         pop     bp                      ;restore bp
  683.         ret     cstack                  ;clean parms from stack-back to caller
  684.  
  685. CompressFile  endp
  686.  
  687. ;---------------------------------------------------------------------------;
  688. ;                                                                           ;
  689. ;                        DECOMPRESSION ROUTINES                             ;
  690. ;                                                                           ;
  691. ;                             'DeCompress'                                  ;
  692. ;                                                                           ;
  693. ;---------------------------------------------------------------------------;
  694.  
  695. decompress      proc    near
  696.  
  697.         mov     bx,input_handle         ;setup input file handle
  698.         push    ds                      ;save ds
  699.         mov     dx,cs                   ;mov ds,cs to reference disk input
  700.         mov     ds,dx                   ;... buffer in cs when calling dos
  701.         lea     dx,input_data           ;offset of input buffer
  702.         mov     cx,input_data_size      ;max bytes to read
  703.         mov     ah,3fh                  ;dos function - read from file/device
  704.         int     21h                     ;call dos
  705.         jnc     i21ok4                  ;if no disk error, continue
  706.         jmp     diskerror               ;else report disk error and exit
  707. i21ok4:
  708.         pop     ds                      ;restore ds
  709.  
  710. z1:     call    read_code               ;Get a code
  711.         cmp     ax,eof                  ;End of file?
  712.         jne     z2                      ;no
  713.         cmp     output_offset,0         ;Data in output buffer?
  714.         je      z1a                     ;no
  715.  
  716.  
  717. ;write data to disk
  718.  
  719.         mov     bx,output_handle        ;setup output file handle
  720.         mov     cx,output_offset        ;number of bytes to write
  721.         add     totalbytes1,cx          ;accumulate total bytes written
  722.         jnc     noof1                   ;if no carry, skip
  723.         inc     totalbytes2             ;else increment for long add
  724. noof1:                                  ;
  725.         push    ds                      ;save ds
  726.         mov     dx,cs                   ;mov ds,cs to reference disk output
  727.         mov     ds,dx                   ;... buffer in cs when calling dos
  728.         lea     dx,output_data          ;address of output buffer
  729.         mov     ah,40h                  ;dos function - write to file/device
  730.         int     21h                     ;call dos
  731.         jnc     i21ok5                  ;if no disk error, continue
  732.         jmp     diskerror               ;else report disk error and exit
  733. i21ok5:
  734.         pop     ds                      ;restore ds
  735.  
  736. z1a:    ret                             ;done
  737. z2:     cmp     ax,clear                ;Clear code?
  738.         jne     z7                      ;no
  739.         call    init_tab                ;Initialize table
  740.         call    read_code               ;Read next code
  741.         mov     cur_code,ax             ;Initialize variables
  742.         mov     old_code,ax
  743.         mov     k,al
  744.         mov     fin_char,al
  745.         mov     al,k
  746.         call    write_char              ;Write character
  747.         jmp     z1                      ;Get next code
  748. z7:     mov     cur_code,ax             ;Save new code
  749.         mov     in_code,ax
  750.         mov     es,dhash_seg             ;Point to hash table
  751.         cmp     ax,free_code            ;Code in table? (k<w>k<w>k)
  752.         jl      z11                     ;yes
  753.         mov     ax,old_code             ;get previous code
  754.         mov     cur_code,ax             ;make current
  755.         mov     al,fin_char             ;get old last char
  756.         push    ax                      ;push it
  757.         inc     stack_count
  758. z11:    cmp     cur_code,255            ;Code or character?
  759.         jle     z15                     ;Char
  760.         mov     bx,cur_code             ;Convert code to address
  761.         call    dindex
  762.         mov     al,es:2[bx]             ;Get suffix char
  763.         push    ax                      ;push it
  764.         inc     stack_count
  765.         mov     ax,es:[bx]              ;Get prefix code
  766.         mov     cur_code,ax             ;Save it
  767.         jmp     z11                     ;Translate again
  768. z15:    mov     ax,ds                   ;Restore seg reg
  769.         mov     es,ax
  770.         mov     ax,cur_code             ;Get code
  771.         mov     fin_char,al             ;Save as final, k
  772.         mov     k,al
  773.         push    ax                      ;Push it
  774.         inc     stack_count
  775.         mov     cx,stack_count          ;Pop stack
  776.         jcxz    z18                     ;If anything there
  777. z17:    pop     ax
  778.         call    write_char
  779.         loop    z17
  780. z18:    mov     stack_count,cx          ;Clear count on stack
  781.         call    dadd_code                ;Add new code to table
  782.         mov     ax,in_code              ;Save input code
  783.         mov     old_code,ax
  784.         mov     bx,free_code            ;Hit table limit?
  785.         cmp     bx,dmax_code
  786.         jl      z23                     ;Less means no
  787.         mov     cx,maxbits              ;get maxbits for compare
  788.         cmp     nbits,cx                ;Currently less than (12 or 13) bits?
  789.         je      z23                     ;no (next code should be clear)
  790.         inc     nbits                   ;Increase code size
  791.         shl     dmax_code,1              ;Double max code
  792. z23:    jmp     z1                      ;Get next code
  793.  
  794. decompress      endp
  795.  
  796.  
  797. ;---------------------------------------------------------------------------;
  798. ;                                                                           ;
  799. ;                             'read_code'                                   ;
  800. ;                                                                           ;
  801. ;---------------------------------------------------------------------------;
  802.  
  803. read_code   proc    near
  804.  
  805.         mov     ax,dbit_offset           ;Get bit offset
  806.         add     ax,nbits                ;Adjust by code size
  807.         xchg    dbit_offset,ax           ;Swap
  808.  
  809. ; convert bits to bytes
  810.  
  811.         mov     dx,ax                   ;get all of ax
  812.         and     dx,07h                  ;simulate remainder modulo 8
  813.         shr     ax,1                    ;divide ax by 8 (2)
  814.         shr     ax,1                    ;  "       "    (4)
  815.         shr     ax,1                    ;  "       "    (8)
  816.  
  817.         cmp     ax,input_data_chk       ;Approaching end of buffer?
  818.         jl      xd0                     ;no
  819.         push    dx                      ;Save offset in byte
  820.         add     dx,nbits                ;Calculate new bit offset
  821.         mov     dbit_offset,dx
  822.         mov     cx,input_data_size      ;buffer size
  823.         mov     bp,ax                   ;save byte offset
  824.         sub     cx,ax                   ;Calculate bytes left
  825.  
  826. ; make the following buffer shuffle, and read code, segment relative
  827.  
  828.         mov     bx,input_handle         ;setup input handle while ds still ok
  829.         push    ds                      ;Save ds
  830.         push    es                      ;Save es
  831.         mov     dx,cs                   ;Set ds & es to cs
  832.         mov     ds,dx                   ;    "
  833.         mov     es,dx                   ;    "
  834.  
  835. ; move unprocessed input buffer down to the beginning of the buffer
  836.  
  837.         add     ax,offset input_data    ;Point to char
  838.         mov     si,ax
  839.         lea     di,input_data           ;Point to beginning of buffer
  840. rep     movsb                           ;Move last chars down
  841.  
  842. ; fill up the rest of the input buffer
  843.  
  844.         lea     dx,[di]                 ;offset of input buffer
  845.         mov     cx,bp                   ;bytes to read
  846.         mov     ah,3fh                  ;dos function - read from file/device
  847.         int     21h                     ;call dos
  848.         jnc     i21ok6                  ;if no disk error, continue
  849.         jmp     diskerror               ;else report disk error and exit
  850. i21ok6:
  851.         pop     es                      ;restore es
  852.         pop     ds                      ;restore ds
  853.  
  854.         xor     ax,ax                   ;Clear ax
  855.         pop     dx                      ;Restore offset in byte
  856.  
  857.  
  858. xd0:
  859.         push    ds                      ;save ds
  860.         mov     bx,cs                   ;ds = cs (to reference buffer in cs)
  861.         mov     ds,bx                   ;   "                   "
  862.         add     ax,offset input_data    ;Point to char
  863.         mov     si,ax
  864.         lodsw                           ;Get word
  865.         mov     bx,ax                   ;Save in AX
  866.         lodsb                           ;Next byte
  867.         pop     ds                      ;restore ds
  868.         mov     cx,dx                   ;Offset in byte
  869.         jcxz    xd2                     ;If zero, skip shifts
  870. xd1:    shr     al,1                    ;Put code in low (code size) bits of BX
  871.         rcr     bx,1
  872.         loop    xd1
  873. xd2:    mov     ax,bx                   ;put code in ax
  874.         mov     bx,nbits                ;mask off unwanted bits
  875.         sub     bx,9                    ;9 bits = masks[0]  10 bits = masks[2]
  876.         shl     bx,1                    ;  etc. etc.
  877.         and     ax,masks[bx]            ;
  878.         ret
  879.  
  880. read_code       endp
  881.  
  882.  
  883. ;---------------------------------------------------------------------------;
  884. ;                                                                           ;
  885. ;                             'init_tab'                                    ;
  886. ;                                                                           ;
  887. ;---------------------------------------------------------------------------;
  888.  
  889. init_tab        proc    near
  890.  
  891.         mov     nbits,9                 ;Initialize variables
  892.         mov     dmax_code,512
  893.         mov     free_code,first_free
  894.         ret
  895.  
  896. init_tab        endp
  897.  
  898.  
  899. ;---------------------------------------------------------------------------;
  900. ;                                                                           ;
  901. ;                             'write_char'                                  ;
  902. ;                                                                           ;
  903. ;---------------------------------------------------------------------------;
  904.  
  905. write_char      proc    near
  906.  
  907.         mov     di,output_offset        ;Get offset in buffer
  908.         cmp     di,output_data_size     ;Full?
  909.         jl      wch1                    ;no
  910.         push    ax                      ;Save registers
  911.         push    cx
  912.  
  913.         mov     bx,output_handle        ;setup output file handle
  914.         add     totalbytes1,di          ;accumulate total bytes written
  915.         jnc     noof2                   ;if no carry, skip
  916.         inc     totalbytes2             ;else increment for long add
  917. noof2:                                  ;
  918.         push    ds                      ;save ds
  919.         mov     cx,cs                   ;mov ds,cs to reference disk output
  920.         mov     ds,cx                   ;... buffer in cs when calling dos
  921.         lea     dx,output_data          ;address of output buffer
  922.         mov     cx,di                   ;number of bytes to write
  923.         mov     ah,40h                  ;dos function - write to file/device
  924.         int     21h                     ;call dos
  925.         jnc     i21ok7                  ;if no disk error, continue
  926.         jmp     diskerror               ;else report disk error and exit
  927. i21ok7:
  928.         pop     ds                      ;restore ds
  929.  
  930.         pop     cx                      ;restore cx
  931.         pop     ax                      ;restore ax
  932.         mov     di,0                    ;Point to beginning of buffer
  933.         mov     output_offset,di        ;reset buffer offset to 0
  934. wch1:
  935.         push    es                      ;save es
  936.         mov     dx,cs                   ;es=cs so es:di points to buffer in cs
  937.         mov     es,dx
  938.         lea     di,output_data[di]      ;Point into buffer
  939.         stosb                           ;Store char
  940.         pop     es
  941.  
  942. ; the following CRC16 (ala Xmodem crc) code is inline for max speeeeeeed...!
  943.  
  944.         push    cx                      ;save cx (loop counter in decompress)
  945.  
  946.         mov     dx,crc                  ;get old crc
  947.         xchg    dl,dh                   ;swap crc bytes
  948.         xor     ah,ah                   ;make sure ah is zero (al has the data)
  949.         xor     dx,ax                   ;xor low crc with new data byte
  950.         xor     bx,bx                   ;clear bx
  951.         xchg    dl,bl                   ;swap low crc to bl
  952.         shl     bx,1                    ;bx = bx * 2
  953.         xor     dx,cs:[crctab+bx]       ;xor crc with table value
  954.         mov     crc,dx                  ;store updated crc
  955.  
  956.         pop     cx                      ;restore cx
  957.  
  958.         inc     output_offset           ;Increment number of chars in buffer
  959.         ret
  960.  
  961. write_char      endp
  962.  
  963.  
  964. ;---------------------------------------------------------------------------;
  965. ;                                                                           ;
  966. ;                             'dindex'                                      ;
  967. ;                                                                           ;
  968. ;---------------------------------------------------------------------------;
  969.  
  970. dindex           proc    near
  971.  
  972.         mov     bp,bx                   ;bx = bx * 3 (3 byte entries)
  973.         shl     bx,1                    ;bp = bx
  974.         add     bx,bp                   ;bx = bx * 2 + bp
  975.         ret
  976.  
  977. dindex           endp
  978.  
  979.  
  980. ;---------------------------------------------------------------------------;
  981. ;                                                                           ;
  982. ;                             'dadd_code'                                   ;
  983. ;                                                                           ;
  984. ;---------------------------------------------------------------------------;
  985.  
  986. dadd_code        proc    near
  987.  
  988.         mov     bx,free_code            ;Get new code
  989.         call    dindex                  ;convert to address
  990.         push    es                      ;point to hash table
  991.         mov     es,dhash_seg
  992.         mov     al,k                    ;get suffix char
  993.         mov     es:[bx].dchar,al        ;save it
  994.         mov     ax,old_code             ;get prefix code
  995.         mov     es:[bx].dnext,ax        ;save it
  996.         pop     es
  997.         inc     free_code               ;set next code
  998.         ret
  999.  
  1000. dadd_code        endp
  1001.  
  1002.  
  1003. ;---------------------------------------------------------------------------;
  1004. ;                                                                           ;
  1005. ;                 function   'DeCompressFile'                               ;
  1006. ;                                                                           ;
  1007. ; Function interface to other languages for file decompression              ;
  1008. ;                                                                           ;
  1009. ;   See TESTD.PAS for an example                                            ;
  1010. ;                                                                           ;
  1011. ;  dinhandle & douthandle must be DOS handles of already opened files       ;
  1012. ;                                                                           ;
  1013. ;  dbytehi & dbytelo is a long integer specifying the starting byte offset  ;
  1014. ;                  of where to start reading the input file                 ;
  1015. ;                                                                           ;
  1016. ;  drtnseg & drtnofs is a pointer to a return area where this module will   ;
  1017. ;                  pass back the CRC and the compressed file size           ;
  1018. ;                                                                           ;
  1019. ;  dhashsegment is the segment:0 address of memory allocated by the caller. ;
  1020. ;                if you are requesting 12 bit decompression, this must point;
  1021. ;                to 12288 bytes of available memory. If you are requesting  ;
  1022. ;                13 bit, it must point to 24576 bytes of available memory   ;
  1023. ;                                                                           ;
  1024. ;  dlzwbits must be a word value of 12 for 12 bit decompression or 13 for   ;
  1025. ;                  13 bit decompression                                     ;
  1026. ;                                                                           ;
  1027. ;---------------------------------------------------------------------------;
  1028.  
  1029. dinhandle       equ     word ptr  [bp+20] ;input handle on stack
  1030. douthandle      equ     word ptr  [bp+18] ;output handle on stack
  1031. dbytehi         equ     word ptr  [bp+16] ;byte offset (hi order)
  1032. dbytelo         equ     word ptr  [bp+14] ;byte offset (low order)
  1033. drtnseg         equ     word ptr  [bp+12] ;segment of return record
  1034. drtnofs         equ     word ptr  [bp+10] ;offset of return record
  1035. dhashsegment    equ     word ptr  [bp+8]  ;segment of hash table on stack
  1036. dlzwbits        equ     word ptr  [bp+6]  ;number of bits (lzw) 12 or 13
  1037.  
  1038. dstack          equ     16                ;number of bytes passed on stack
  1039.  
  1040.  
  1041. ;---------------------------------------------------------------------------;
  1042. ;                                                                           ;
  1043. ;               (FAR)         'DeCompressFile'                              ;
  1044. ;                                                                           ;
  1045. ;---------------------------------------------------------------------------;
  1046.  
  1047. DeCompressFile  proc far
  1048.  
  1049. ; save bp, sp, ss, ds, and stack parameter count so we can exit this module
  1050. ; in the event of an error (e.g. disk i/o)
  1051.  
  1052.         mov     cs:savebp,bp            ;save bp
  1053.         mov     cs:savesp,sp            ;save sp
  1054.         mov     cs:savess,ss            ;save ss
  1055.         mov     cs:saveds,ds            ;save ds
  1056.         mov     cs:saveparms,dstack     ;number of stack bytes for parms
  1057.  
  1058. ; set up reference to callers parameters and save anything required
  1059.  
  1060.         push    bp                      ;save bp
  1061.         mov     bp,sp                   ;set stack frame to reference my parms
  1062.         push    ds                      ;save ds
  1063.  
  1064. ; set up ds & es addressability
  1065.  
  1066.         mov     bx,data                 ;Set up data segment addressability
  1067.         mov     es,bx                   ;
  1068.         mov     ds,bx                   ;
  1069.  
  1070. ; get parameters from caller
  1071.  
  1072.         mov     ax,dinhandle            ;store input file handle
  1073.         mov     input_handle,ax         ;
  1074.         mov     ax,douthandle           ;store output file handle
  1075.         mov     output_handle,ax        ;
  1076.         mov     ax,dbytehi              ;store hi order byte offset
  1077.         mov     byte_hi,ax              ;
  1078.         mov     ax,dbytelo              ;store lo order byte offset
  1079.         mov     byte_lo,ax              ;
  1080.         mov     ax,drtnseg              ;store return address segment
  1081.         mov     rtn_seg,ax              ;
  1082.         mov     ax,drtnofs              ;store return address offset
  1083.         mov     rtn_ofs,ax              ;
  1084.         mov     ax,dhashsegment         ;store seg pointer to heap hash table
  1085.         mov     dhash_seg,ax            ;
  1086.         mov     cx,dlzwbits             ;store lzw type (12 or 13)
  1087.         mov     maxbits, cx             ;
  1088.         mov     maxmax,1                ;calc max entries for lzw type
  1089.         shl     maxmax,cl               ; (12 bit = 4096,  13 bit = 8192)
  1090.  
  1091. ; initialize anything required
  1092.  
  1093.         mov     input_offset,0          ;clear input_offset
  1094.         mov     output_offset,0         ;clear output_offset
  1095.         mov     input_size,0            ;clear input_size
  1096.         mov     dbit_offset,0           ;clear input_size
  1097.         mov     stack_count,0           ;clear stack_count
  1098.         mov     totalbytes1,0           ;clear bytes written read count
  1099.         mov     totalbytes2,0           ;
  1100.         mov     crc,0                   ;clear crc for new file
  1101.         mov     nbits,9                 ;set number of starting bits
  1102.         mov     free_code,first_free    ;set first free code
  1103.         mov     dmax_code,512           ;set first free code
  1104.         mov     masks+0,1ffh            ;set up mask for  9 bit codes
  1105.         mov     masks+2,3ffh            ;set up mask for 10 bit codes
  1106.         mov     masks+4,7ffh            ;set up mask for 11 bit codes
  1107.         mov     masks+6,0fffh           ;set up mask for 12 bit codes
  1108.         mov     masks+8,1fffh           ;set up mask for 13 bit codes
  1109.         cld                             ;clear direction flag for di & si
  1110.  
  1111. ; move file pointer so that reads start at the requested byte
  1112.  
  1113.         mov     bx,input_handle         ;setup intput file handle
  1114.         mov     cx,byte_hi              ;hi-order byte offset to start write
  1115.         mov     dx,byte_lo              ;lo-order byte offset to start write
  1116.         mov     ah,42h                  ;dos function - move file pointer
  1117.         mov     al,00h                  ;  method = absolute from beginning
  1118.         int     21h                     ;call dos
  1119.         jnc     i21ok8                  ;if no disk error, continue
  1120.         jmp     diskerror               ;else report disk error and exit
  1121. i21ok8:
  1122.  
  1123. ; decompress the file
  1124.  
  1125.         call    decompress              ;DeCompress file
  1126.  
  1127. ; wrap it up
  1128.  
  1129.         mov     bx,rtn_ofs              ;setup offset of callers return area
  1130.         mov     ds,rtn_seg              ;setup segment of callers return area
  1131.         mov     ax,crc                  ;send back crc
  1132.         mov     [bx],ax                 ;
  1133.         mov     ax,totalbytes1          ;send back low order total bytes
  1134.         mov     [bx]+2,ax               ;
  1135.         mov     ax,totalbytes2          ;send back high order total bytes
  1136.         mov     [bx]+4,ax               ;
  1137.         mov     rc,-1                   ;good return code
  1138.         mov     ax,rc                   ;function return = return code
  1139.         pop     ds                      ;restore ds
  1140.         pop     bp                      ;restore bp
  1141.         ret     dstack                  ;clean parms from stack-back to caller
  1142.  
  1143. DeCompressFile  endp
  1144.  
  1145.  
  1146. ;---------------------------------------------------------------------------;
  1147. ;                                                                           ;
  1148. ;                             'diskerror'                                   ;
  1149. ;                                                                           ;
  1150. ; clear screen, display an error message, restore the routine entry state   ;
  1151. ; and exit gracefully back to caller with a function return code of (0)     ;
  1152. ; (error).                                                                  ;
  1153. ;                                                                           ;
  1154. ; This routine is entered via a jump, not a call.                           ;
  1155. ;                                                                           ;
  1156. ;---------------------------------------------------------------------------;
  1157.  
  1158. diskerror   proc near
  1159.  
  1160.         jmp     skipdt                  ;bypass data
  1161.  
  1162. ; don't change the order or position of the following jmp.... definitions
  1163.  
  1164. jmpofst dw      0                       ;offset for far jump return to TP
  1165. jmpseg  dw      0                       ;segment for far jump return to TP
  1166.  
  1167. ; error message to display if this routine is called
  1168.  
  1169. errmsg  db      0dh, 0ah, 0ah, 07h
  1170.         db      'SEVERE DISK I/O ERROR IN MODULE: '
  1171.         db      'MDCD1213.OBJ COMPRESS/DECOMPRESS'
  1172.         db      0dH, 0aH, 0ah
  1173.         db      'CLEANING UP AND RETURNING TO CALLING ROUTINE'
  1174.         db      0dh, 0ah, 0ah, 07h, '$'
  1175.         db      '$'
  1176. skipdt:
  1177.  
  1178. ; get the screen attribute currently at cursor and clear screen
  1179.  
  1180.         xor     bh,bh                   ;video page 0
  1181.         mov     ah,08h                  ;bios video function = read attr/char
  1182.         int     10h                     ;call bios video
  1183.         mov     bh,ah                   ;save attribute for function 6 call
  1184.         mov     ah,06h                  ;video function = scroll page up
  1185.         xor     al,al                   ;blank screen
  1186.         xor     cx,cx                   ;clear screen (scroll) from 0,0 to..
  1187.         mov     dx,184fh                ; ... to 24,79
  1188.         int     10h                     ;call bios video
  1189.  
  1190. ; display error message
  1191.  
  1192.         mov     ah,09h                  ;dos function = display string
  1193.         lea     dx,errmsg               ;address of data to display
  1194.         push    cs                      ;make ds point to code segment
  1195.         pop     ds                      ; "                     "
  1196.         int     21h                     ;call dos
  1197.  
  1198. ; reset all of callers stuff so we can get back gracefully
  1199.  
  1200.         mov     bp,cs:savebp            ;restore tp's bp
  1201.         mov     ds,cs:saveds            ;restore tp's ds
  1202.         cli                             ;interrupts off for old 8088 chips
  1203.         mov     sp,cs:savesp            ;restore entry sp
  1204.         mov     ss,cs:savess            ;restore entry ss (shud be the same)
  1205.         sti                             ;interrupts back on
  1206.  
  1207. ; the following code pulls the callers return address (segment:offset) off
  1208. ; from the stack, adjusts the stack, and returns to the caller
  1209.  
  1210.         pop     cs:jmpofst              ;pull return address off of stack
  1211.         pop     cs:jmpseg               ;pull return segment off of stack
  1212.         add     sp,cs:saveparms         ;get rid of locals from stack
  1213.         xor     ax,ax                   ;error return code for caller
  1214.         jmp     dword ptr cs:jmpofst    ;return far to caller
  1215.  
  1216. diskerror   endp
  1217.  
  1218. code    ends
  1219.  
  1220.         end
  1221.