home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mssup201.arc / LZD.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-08-25  |  9.3 KB  |  449 lines

  1.     title    Lempel-Ziv Decompressor
  2.  
  3. ;Derived from Tom Pfau's public domain assembly code.
  4. ;The contents of this file are hereby released to the public domain.
  5. ;                                   -- Rahul Dhesi 1988/08/24
  6.  
  7. UNBUF_IO    equ    1        ;use unbuffered I/O
  8.  
  9. public    _lzd,memflag,docrc
  10.  
  11.     include    asmconst.ai
  12.     include macros.ai
  13.  
  14. ;Hash table entry
  15. hash_rec    struc
  16. next    dw    ?            ; prefix code
  17. char    db    ?            ; suffix char
  18. hash_rec    ends
  19.  
  20. extrn    _addbfcrc:near            ;External C function for CRC
  21.  
  22. ifdef    UNBUF_IO
  23. extrn    _read:near
  24. extrn    _blockwrite:near
  25. else
  26. extrn    _zooread:near
  27. extrn    _zoowrite:near
  28. endif
  29.  
  30. ;Declare segments
  31. _text    segment byte public 'code'
  32. _text    ends
  33.  
  34. dgroup    group    _data
  35.     assume ds:dgroup,es:dgroup
  36. _data    segment word public 'data'
  37. extrn    _out_buf_adr:word        ;address of C output buffer
  38. extrn    _in_buf_adr:word        ;address of C input buffer
  39.  
  40. memflag        db    0        ;Memory allocated?  flag
  41. save_bp        dw    ?
  42. save_sp        dw    ?
  43.  
  44. input_handle    dw    ?
  45. output_handle    dw    ?
  46. hash_seg    dw    ?
  47. cur_code    dw    ?
  48. old_code    dw    ?
  49. in_code        dw    ?
  50. free_code    dw    first_free
  51.  
  52. ;Note:  for re-entrancy, following 3 must be re-initialized each time
  53. stack_count    dw    0
  54. nbits        dw    9
  55. max_code    dw    512
  56.  
  57. fin_char    db    ?
  58. k        db    ?
  59. masks        dw    1ffh,3ffh,7ffh,0fffh,1fffh
  60.  
  61. ;Note:  for re-entrancy, following 2 must be re-initialized each time
  62. bit_offset    dw    0
  63. output_offset    dw    0
  64. _data    ends
  65.  
  66. memory    segment para public 'memory'
  67. hash    label    hash_rec
  68. memory    ends
  69.  
  70. call_index macro
  71.     mov    bp,bx            ;bx = bx * 3 (3 byte entries)
  72.     shl    bx,1            ;bp = bx
  73.     add    bx,bp            ;bx = bx * 2 + bp
  74.     endm
  75.  
  76. call_write_char macro
  77.     local    wc$1
  78.     mov    di,output_offset    ;Get offset in buffer
  79.     cmp    di,outbufsiz        ;Full?
  80.     jb    wc$1            ;no
  81.     call    write_char_partial
  82.     sub    di,di            ;so we add zero in next statement
  83. wc$1:    add    di,[_out_buf_adr]    ;di <- buffer address + di
  84.     stosb                ;Store char
  85.     inc    output_offset        ;Increment number of chars in buffer
  86.     endm
  87.  
  88. add_code macro
  89.     mov    bx,free_code        ;Get new code
  90.     ;call    index            ;convert to address
  91.     call_index
  92.     push    es            ;point to hash table
  93.     mov    es,hash_seg
  94.     mov    al,k            ;get suffix char
  95.     mov    es:[bx].char,al        ;save it
  96.     mov    ax,old_code        ;get prefix code
  97.     mov    es:[bx].next,ax        ;save it
  98.     pop    es
  99.     inc    free_code        ;set next code
  100.     endm
  101.  
  102. ;Start coding
  103. _text    segment
  104.     assume    cs:_text,ds:dgroup,es:dgroup,ss:nothing
  105.  
  106. write_char_partial proc    near
  107.     push    cx
  108.     mov    cx,di            ;byte count
  109.     call    write_block
  110.     pop    cx
  111.     mov    output_offset,0        ;Restore buffer pointer
  112.     ret
  113. write_char_partial endp
  114.  
  115. _lzd    proc    near
  116.  
  117.     push    bp            ;Standard C entry code
  118.     mov    bp,sp
  119.     push    di
  120.     push    si
  121.     
  122.     push    ds            ;Save ds to be sure
  123.     mov    [save_bp],bp        ;And bp too!
  124.     mov    bx,ds
  125.     mov    es,bx
  126.  
  127. ;Get two parameters, both integers, that are input file handle and
  128. ;output file handle
  129.     mov    ax,[bp+4]
  130.     mov    [input_handle],ax
  131.     mov    ax,[bp+6]
  132.     mov    [output_handle],ax
  133.  
  134.     call    decompress        ;Compress file & get status in AX
  135.  
  136.     mov    bp,[save_bp]        ;Restore bp
  137.     pop    ds
  138.     pop    si            ;Standard C return code
  139.     pop    di
  140.     mov    sp,bp
  141.     pop    bp
  142.     ret
  143. _lzd    endp
  144.  
  145. ;Note:  Procedure decompress returns AX=0 for successful decompression and
  146. ;    AX=1 for I/O error and AX=2 for malloc failure.  
  147. decompress    proc    near
  148.     mov    [save_sp],sp        ;Save SP in case of error return
  149.  
  150. ;Initialize variables -- required for serial re-entrancy
  151.     mov    [nbits],9
  152.     mov    [max_code],512
  153.     mov    [free_code],first_free
  154.     mov    [stack_count],0
  155.     mov    [bit_offset],0
  156.     mov    [output_offset],0
  157.  
  158.     test    memflag,0ffH        ;Memory allocated?
  159.     jnz    gotmem            ;If allocated, continue
  160.     malloc    <((maxmax * 3) / 16 + 20)>    ;allocate it
  161.     jnc    here1
  162.     jmp    MALLOC_err
  163. here1:
  164.     mov    hash_seg,ax        ;Save segment address of mem block
  165.     mov    memflag,0ffh        ;Set flag to remind us later
  166. gotmem:
  167.  
  168.     mov    ax,inbufsiz
  169.     push    ax            ;byte count
  170.     push    _in_buf_adr        ;buffer address
  171.     push    input_handle        ;zoofile
  172. ifdef    UNBUF_IO
  173.     call    _read
  174. else
  175.     call    _zooread
  176. endif
  177.     add    sp,6
  178.  
  179.     cmp    ax,-1
  180.     jz    IO_err            ;I/O error
  181. here2:
  182.  
  183. l1:    call    read_code        ;Get a code
  184.     cmp    ax,eof            ;End of file?
  185.     jne    l2            ;no
  186.     cmp    output_offset,0        ;Data in output buffer?
  187.     je    OK_ret            ;no
  188.     mov    cx,[output_offset]    ;byte count
  189.     call    write_block        ;write block of cx bytes
  190. OK_ret:    
  191.     xor    ax,ax            ;Normal return -- decompressed
  192.     ret                ;done
  193. IO_err:
  194.     mov    ax,2            ;I/O error return 
  195.     mov    sp,[save_sp]        ;Restore stack pointer
  196.     ret    
  197.  
  198. MALLOC_err:
  199.     mov    ax,1            ;Malloc error return
  200.     mov    sp,[save_sp]        ;Restore stack pointer
  201.     ret
  202.  
  203. l2:    cmp    ax,clear        ;Clear code?
  204.     jne    l7            ;no
  205.     call    init_tab        ;Initialize table
  206.     call    read_code        ;Read next code
  207.     mov    cur_code,ax        ;Initialize variables
  208.     mov    old_code,ax
  209.     mov    k,al
  210.     mov    fin_char,al
  211.     mov    al,k
  212.     ;call    write_char        ;Write character
  213.     call_write_char
  214.     jmp    l1            ;Get next code
  215. l7:    mov    cur_code,ax        ;Save new code
  216.     mov    in_code,ax
  217.     mov    es,hash_seg        ;Point to hash table
  218.     cmp    ax,free_code        ;Code in table? (k<w>k<w>k)
  219.     jb    l11            ;yes
  220.     mov    ax,old_code        ;get previous code
  221.     mov    cur_code,ax        ;make current
  222.     mov    al,fin_char        ;get old last char
  223.     push    ax            ;push it
  224.     inc    stack_count
  225.  
  226. ;old code -- two memory references
  227. ;l11:    
  228. ;    cmp    cur_code,255        ;Code or character?
  229. ;    jbe    l15            ;Char
  230. ;    mov    bx,cur_code        ;Convert code to address
  231. ;new code -- 0 or 1 memory references
  232.     mov    ax,cur_code
  233. l11:
  234.     ;All paths in must have ax containing cur_code
  235.     cmp    ax,255
  236.     jbe    l15
  237.     mov    bx,ax
  238. ;end code
  239.     ;call    index
  240.     call_index
  241.     mov    al,es:2[bx]        ;Get suffix char
  242.     push    ax            ;push it
  243.     inc    stack_count
  244.     mov    ax,es:[bx]        ;Get prefix code
  245.     mov    cur_code,ax        ;Save it
  246.     jmp    l11            ;Translate again
  247. l15:    
  248. ;old code
  249. ;    push    ds            ;Restore seg reg
  250. ;    pop    es
  251. ;new code
  252.     mov    ax,ds            ;faster than push/pop
  253.     mov    es,ax
  254. ;end code
  255.     mov    ax,cur_code        ;Get code
  256.     mov    fin_char,al        ;Save as final, k
  257.     mov    k,al
  258.     push    ax            ;Push it
  259.  
  260. ;old code
  261. ;    inc    stack_count
  262. ;    mov    cx,stack_count        ;Pop stack
  263. ;new code -- slightly faster because INC of memory is slow
  264.     mov    cx,stack_count
  265.     inc    cx
  266.     mov    stack_count,cx
  267. ;end code
  268.     jcxz    l18            ;If anything there
  269. l17:    pop    ax
  270.     ;call    write_char
  271.     call_write_char
  272.     loop    l17
  273.  
  274. ;old code
  275. ;l18:    
  276. ;    mov    stack_count,cx        ;Clear count on stack
  277. ;new code -- because stack_count is already zero on earlier "jcxz l18"
  278.     mov    stack_count,cx
  279. l18:
  280. ;end code
  281.  
  282.     ;call    add_code        ;Add new code to table
  283.     add_code
  284.     mov    ax,in_code        ;Save input code
  285.     mov    old_code,ax
  286.     mov    bx,free_code        ;Hit table limit?
  287.     cmp    bx,max_code
  288.     jb    l23            ;Less means no
  289.     cmp    nbits,maxbits        ;Still within maxbits?
  290.     je    l23            ;no (next code should be clear)
  291.     inc    nbits            ;Increase code size
  292.     shl    max_code,1        ;Double max code
  293. l23:    jmp    l1            ;Get next code
  294. decompress    endp    
  295.  
  296. read_code    proc    near
  297.  
  298. ;old code
  299. ;    mov    ax,bit_offset        ;Get bit offset
  300. ;    add    ax,nbits        ;Adjust by code size
  301. ;    xchg    bit_offset,ax        ;Swap
  302. ;    mov    dx,ax            ;dx <- ax
  303. ;new code
  304.     mov    ax,bit_offset
  305.     mov    dx,ax            ;dx <- bit_offset
  306.     add    ax,nbits
  307.     mov    bit_offset,ax
  308.     mov    ax,dx
  309. ;end code
  310.  
  311.     shr    ax,1
  312.     shr    ax,1
  313.     shr    ax,1            ;ax <- ax div 8
  314.     and    dx,07            ;dx <- ax mod 8
  315.     cmp    ax,inbufsiz-3        ;Approaching end of buffer?
  316.     jb    rd0            ;no
  317.     push    dx            ;Save offset in byte
  318.     add    dx,nbits        ;Calculate new bit offset
  319.     mov    bit_offset,dx
  320.     mov    cx,inbufsiz
  321.     mov    bp,ax            ;save byte offset
  322.     sub    cx,ax            ;Calculate bytes left
  323.     add    ax,_in_buf_adr
  324.     mov    si,ax
  325.     mov    di,_in_buf_adr
  326. rep    movsb                ;Move last chars down
  327.  
  328.     push    bp            ;byte count
  329.     push    di            ;buffer address
  330.     push    input_handle        ;zoofile
  331. ifdef    UNBUF_IO
  332.     call _read
  333. else
  334.     call    _zooread
  335. endif
  336.     add    sp,6
  337.  
  338.     cmp    ax,-1
  339.     jnz    here4
  340.     jmp    IO_err            ;I/O error
  341.  
  342. here4:
  343.     xor    ax,ax            ;Clear ax
  344.     pop    dx            ;Restore offset in byte
  345. rd0:    
  346.     add    ax,_in_buf_adr
  347.     mov    si,ax
  348.     lodsw                ;Get word
  349.     mov    bx,ax            ;Save in AX
  350.     lodsb                ;Next byte
  351.     mov    cx,dx            ;Offset in byte
  352.     jcxz    rd2            ;If zero, skip shifts
  353. rd1:    shr    al,1            ;Put code in low (code size) bits of BX
  354.     rcr    bx,1
  355.     loop    rd1
  356. rd2:    mov    ax,bx            ;put code in ax
  357.     mov    bx,nbits        ;mask off unwanted bits
  358.     sub    bx,9
  359.     shl    bx,1
  360.     and    ax,masks[bx]
  361.     ret
  362. read_code    endp
  363.  
  364. init_tab    proc    near
  365.     mov    nbits,9            ;Initialize variables
  366.     mov    max_code,512
  367.     mov    free_code,first_free
  368.     ret
  369. init_tab    endp
  370.  
  371. comment #
  372. index        proc    near
  373.     mov    bp,bx            ;bx = bx * 3 (3 byte entries)
  374.     shl    bx,1            ;bp = bx
  375.     add    bx,bp            ;bx = bx * 2 + bp
  376.     ret
  377. index        endp
  378. #end comment
  379.  
  380. docrc    proc    near
  381. ;On entry, ax=char count, dx=buffer address.
  382. ;Do crc on character count, in buffer.
  383. ;****** Update CRC value -- call external C program
  384.     ;External program is:    addbfcrc(buffer, count)
  385.     ;            char *buffer;
  386.     ;            int count;
  387.  
  388.     push    ax        ;SAVE AX
  389.     push    bx        ;SAVE BX
  390.     push    cx
  391.     push    dx
  392.  
  393.     push    ax        ;param 2: char count
  394.     push    dx        ;param 1: buffer address
  395.     call    _addbfcrc
  396.     add    sp,4        ;Restore 2 params from stack
  397.  
  398.     pop    dx
  399.     pop    cx
  400.     pop    bx        ;RESTORE BX
  401.     pop    ax        ;RESTORE AX
  402.     ret
  403. docrc    endp
  404.  
  405. write_block proc near
  406. ;Input:  CX=byte count to write
  407.     push    ax
  408.     push    bx
  409.     push    cx
  410.     push    dx
  411.     push    si            ;may not be necessary to save si & di
  412.     push    di
  413.  
  414.     push    cx            ;save count
  415.  
  416.     push    cx            ;count
  417.     push    _out_buf_adr        ;buffer
  418.     push    output_handle        ;zoofile
  419. ifdef    UNBUF_IO
  420.     call    _blockwrite
  421. else
  422.     call    _zoowrite
  423. endif
  424.     add    sp,6
  425.  
  426.     pop    cx            ;restore count
  427.  
  428.     ;ax = actual number of bytes written
  429.     cmp    ax,cx            ;all bytes written?
  430.     je    written            ;if yes, OK
  431.     jmp    IO_err
  432. written:
  433.     mov    dx,_out_buf_adr
  434.     call    docrc            ;do crc on ax bytes in buffer dx
  435.     mov    output_offset,0        ;restore buffer ptr to zero
  436.  
  437.     pop    di
  438.     pop    si
  439.     pop    dx
  440.     pop    cx
  441.     pop    bx
  442.     pop    ax
  443.     ret
  444. write_block endp
  445.  
  446. _text    ends
  447.  
  448.     end
  449.