home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1995 July / IMM0795.ISO / share / os2 / zoo21_32 / source / lzd.asm < prev    next >
Assembly Source File  |  1993-12-17  |  10KB  |  482 lines

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