home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c019 / 5.ddi / LZSS.ZIP / LZSS.PAS next >
Encoding:
Pascal/Delphi Source File  |  1993-05-19  |  20.3 KB  |  659 lines

  1. Program LZss;
  2.  
  3. {
  4. ;
  5. ;  LZSS.ASM     Compress and uncompress program using LZ77 algorithm
  6. ;
  7. ;  Assembler Programmer : Andy Tam
  8. ;  Pascal Conversion : Douglas Webb
  9. }
  10.  
  11. CONST
  12.   N           = 4096;  { Bigger N -> Better compression on big files only. }
  13.   F           = 18;
  14.   THRESHOLD   = 2;
  15.   NUL         = N * 2;
  16.   DBLARROW    = $AF;
  17.  
  18.   BUFSIZE = 1024;    { 4k File Buffers }
  19.   InBufPtr  : WORD = BUFSIZE;
  20.   InBufSize : WORD = BUFSIZE;
  21.   OutBufPtr : WORD = 0;
  22.  
  23.  
  24. VAR
  25.   infile,  outfile : File;
  26.   printcount, height, matchPos, matchLen, lastLen, printPeriod : WORD;
  27.   opt : BYTE;
  28.  
  29.   TextBuf : Array[0.. N + F - 2] OF BYTE;     { Start full of spaces ?! }
  30.   Left,Mom:  Array [0..N] OF WORD;
  31.   Right: Array [0..N + 256] OF WORD;
  32.   codeBuf: Array [0..16] of BYTE;
  33.  
  34.   Inbuf,OutBuf : Array[0..PRED(BUFSIZE)] of BYTE;      { File buffers. }
  35.  
  36.  
  37. FUNCTION ReadChunk: WORD;    { Returns #Bytes read. }
  38.  
  39. VAR
  40.   Actual : WORD;
  41.  
  42. BEGIN
  43.   BlockRead(InFile,InBuf,BUFSIZE,Actual);
  44.   ReadChunk := Actual;
  45. END;
  46.  
  47.  
  48.   Procedure Getc; Assembler;
  49.   ASM
  50.   {
  51.   ; getc : retrun a character from the buffer
  52.   ;
  53.   ;           RETURN : AL = input char
  54.   ;                    Carry set when EOF
  55.   }
  56.               push    bx
  57.               mov     bx, inBufPtr
  58.               cmp     bx, inBufSize
  59.               jb      @getc1
  60.               push    cx
  61.               push    dx
  62.               push    di
  63.               push    si
  64.               call    readchunk
  65.               pop     si
  66.               pop     di
  67.               pop     dx
  68.               pop     cx
  69.               mov     inBufSize, ax
  70.               or      ax, ax
  71.               jz      @getc2               { ; EOF }
  72.               xor     bx, bx
  73.   @getc1:     mov     al, [Offset InBuf + bx]
  74.               inc     bx
  75.               mov     inBufPtr, bx
  76.               pop     bx
  77.               clc                         { ; clear the carry flag }
  78.               jmp     @end
  79.   @getc2:     pop     bx
  80.               stc                         { ; set carry to indicate EOF }
  81.   @end:
  82.  END;
  83.  
  84.  
  85.  
  86. {
  87.   ; writeOut : flush the output buffer to disk
  88.   ;
  89.   ;           Entry : BX = number of byte to write from outBuf
  90. }
  91.  
  92. Procedure Writeout;
  93. VAR
  94.   Actual : WORD;
  95.  
  96. BEGIN
  97.   BlockWrite(OutFile,OutBuf,OutBufPtr,Actual);
  98. END;
  99.  
  100.  
  101.  
  102.  
  103.  
  104. {
  105.   ; putc : put a character into the output buffer
  106.   ;
  107.   ;           Entry : AL = output char
  108. }
  109.  
  110. PROCEDURE Putc; Assembler;
  111. ASM
  112.               push    bx
  113.               mov     bx, outBufPtr
  114.               mov     [OFFSet OutBuf + bx], al
  115.               inc     bx
  116.               cmp     bx, BUFSIZE
  117.               jb      @putc1
  118.               mov     OutBufPtr,BUFSIZE   { Just so the flush will work. }
  119.               push    cx
  120.               push    dx
  121.               push    di
  122.               push    si
  123.               call    writeOut
  124.               pop     si
  125.               pop     di
  126.               pop     dx
  127.               pop     cx
  128.               xor     bx, bx
  129.   @putc1:     mov     outBufPtr, bx
  130.               pop     bx
  131. END;
  132.  
  133.  
  134.  
  135. {
  136.   ; initTree : initialize all binary search trees.  There are 256 BST's, one
  137.   ;            for all strings started with a particular character.  The
  138.   ;            parent is tree K is the node N + K + 1 and it has only a
  139.   ;            right child.
  140.   ;
  141. }
  142. PROCEDURE InitTree; Assembler;
  143. ASM
  144.       cld
  145.       push    ds
  146.       pop     es
  147.       mov     di, offset right
  148.       add     di, (N + 1) * 2
  149.       mov     cx, 256
  150.       mov     ax, NUL
  151.       rep     stosw
  152.       mov     di, offset mom
  153.       mov     cx, N
  154.       rep     stosw
  155. END;
  156.  
  157.  
  158. {
  159.   ; splay : use splay tree operations to move the node to the 'top' of
  160.   ;         tree.  Note that it will not actual become the root of the tree
  161.   ;         because the root of each tree is a special node.  Instead, it
  162.   ;         will become the right child of this special node.
  163.   ;
  164.   ;           ENTRY : di = the node to be rotated
  165. }
  166. PROCEDURE Splay; Assembler;
  167. ASM
  168.   @Splay1:    mov     si, [Offset Mom + di]
  169.               cmp     si, NUL           { ; exit if its parent is a special node }
  170.               ja      @Splay4
  171.               mov     bx, [Offset Mom + si]
  172.               cmp     bx, NUL           { ; check if its grandparent is special }
  173.               jbe     @Splay5           { ; if not then skip }
  174.               cmp     di, [Offset Left + si] { ; is the current node is a left child ? }
  175.               jne     @Splay2
  176.               mov     dx, [Offset Right + di]    { ; perform a left zig operation }
  177.               mov     [Offset Left + si], dx
  178.               mov     [Offset Right + di], si
  179.               jmp     @Splay3
  180.   @Splay2:    mov     dx, [Offset Left + di]     { ; perform a right zig }
  181.               mov     [Offset Right + si], dx
  182.               mov     [Offset Left + di], si
  183.   @Splay3:    mov     [Offset Right + bx], di
  184.               xchg    bx, dx
  185.               mov     [Offset Mom + bx], si
  186.               mov     [Offset Mom + si], di
  187.               mov     [Offset Mom + di], dx
  188.   @Splay4:    jmp     @end
  189.   @Splay5:    mov     cx, [Offset Mom + bx]
  190.               cmp     di, [Offset Left + si]
  191.               jne     @Splay7
  192.               cmp     si, [Offset Left + bx]
  193.               jne     @Splay6
  194.               mov     dx, [Offset Right + si]    { ; perform a left zig-zig operation }
  195.               mov     [Offset Left + bx], dx
  196.               xchg    bx, dx
  197.               mov     [Offset Mom + bx], dx
  198.               mov     bx, [Offset Right + di]
  199.               mov     [Offset Left +si], bx
  200.               mov     [Offset Mom + bx], si
  201.               mov     bx, dx
  202.               mov     [Offset Right + si], bx
  203.               mov     [Offset Right + di], si
  204.               mov     [Offset Mom + bx], si
  205.               mov     [Offset Mom + si], di
  206.               jmp     @Splay9
  207.   @Splay6:    mov     dx, [Offset Left + di]     { ; perform a left zig-zag operation }
  208.               mov     [Offset Right + bx], dx
  209.               xchg    bx, dx
  210.               mov     [Offset Mom + bx], dx
  211.               mov     bx, [Offset Right + di]
  212.               mov     [Offset Left + si], bx
  213.               mov     [Offset Mom + bx], si
  214.               mov     bx, dx
  215.               mov     [Offset Left + di], bx
  216.               mov     [Offset Right + di], si
  217.               mov     [Offset Mom + si], di
  218.               mov     [Offset Mom + bx], di
  219.               jmp     @Splay9
  220.   @Splay7:    cmp     si, [Offset Right + bx]
  221.               jne     @Splay8
  222.               mov     dx, [Offset Left + si]     { ; perform a right zig-zig }
  223.               mov     [Offset Right + bx], dx
  224.               xchg    bx, dx
  225.               mov     [Offset Mom + bx], dx
  226.               mov     bx, [Offset Left + di]
  227.               mov     [Offset Right + si], bx
  228.               mov     [Offset Mom + bx], si
  229.               mov     bx, dx
  230.               mov     [Offset Left + si], bx
  231.               mov     [Offset Left + di], si
  232.               mov     [Offset Mom + bx], si
  233.               mov     [Offset Mom + si], di
  234.               jmp     @Splay9
  235.   @Splay8:    mov     dx, [Offset Right + di]    { ; perform a right zig-zag }
  236.               mov     [Offset Left + bx], dx
  237.               xchg    bx, dx
  238.               mov     [Offset Mom + bx], dx
  239.               mov     bx, [Offset Left + di]
  240.               mov     [Offset Right + si], bx
  241.               mov     [Offset Mom + bx], si
  242.               mov     bx, dx
  243.               mov     [Offset Right + di], bx
  244.               mov     [Offset Left + di], si
  245.               mov     [Offset Mom + si], di
  246.               mov     [Offset Mom + bx], di
  247.   @Splay9:    mov     si, cx
  248.               cmp     si, NUL
  249.               ja      @Splay10
  250.               cmp     bx, [Offset Left + si]
  251.               jne     @Splay10
  252.               mov     [Offset Left + si], di
  253.               jmp     @Splay11
  254.   @Splay10:   mov     [Offset Right + si], di
  255.   @Splay11:   mov     [Offset Mom + di], si
  256.               jmp     @Splay1
  257.   @end:
  258. END;
  259.  
  260.  
  261. {
  262.   ; insertNode : insert the new node to the corresponding tree.  Note that the
  263.   ;              position of a string in the buffer also served as the node
  264.   ;              number.
  265.   ;
  266.   ;           ENTRY : di = position in the buffer
  267. }
  268.  
  269. PROCEDURE InsertNode; Assembler;
  270. ASM
  271.               push    si
  272.               push    dx
  273.               push    cx
  274.               push    bx
  275.               mov     dx, 1
  276.               xor     ax, ax
  277.               mov     matchLen, ax
  278.               mov     height, ax
  279.               mov     al, byte ptr [Offset TextBuf + di]
  280.               shl     di, 1
  281.               add     ax, N + 1
  282.               shl     ax, 1
  283.               mov     si, ax
  284.               mov     ax, NUL
  285.               mov     word ptr [Offset Right + di], ax
  286.               mov     word ptr [Offset Left + di], ax
  287.   @Ins1:      inc     height
  288.               cmp     dx, 0
  289.               jl      @Ins3
  290.               mov     ax, word ptr [Offset Right + si]
  291.               cmp     ax, NUL
  292.               je      @Ins2
  293.               mov     si, ax
  294.               jmp     @Ins5
  295.   @Ins2:      mov     word ptr [Offset Right + si], di
  296.               mov     word ptr [Offset Mom + di], si
  297.               jmp     @Ins11
  298.   @Ins3:      mov     ax, word ptr [Offset Left + si]
  299.               cmp     ax, NUL
  300.               je      @Ins4
  301.               mov     si, ax
  302.               jmp     @Ins5
  303.   @Ins4:      mov     word ptr [Offset Left + si], di
  304.               mov     word ptr [Offset Mom + di], si
  305.               jmp     @Ins11
  306.   @Ins5:      mov     bx, 1
  307.               shr     si, 1
  308.               shr     di, 1
  309.               xor     ch, ch
  310.               xor     dh, dh
  311.   @Ins6:      mov     dl, byte ptr [Offset Textbuf + di + bx]
  312.               mov     cl, byte ptr [Offset TextBuf + si + bx]
  313.               sub     dx, cx
  314.               jnz     @Ins7
  315.               inc     bx
  316.               cmp     bx, F
  317.               jb      @Ins6
  318.   @Ins7:      shl     si, 1
  319.               shl     di, 1
  320.               cmp     bx, matchLen
  321.               jbe     @Ins1
  322.               mov     ax, si
  323.               shr     ax, 1
  324.               mov     matchPos, ax
  325.               mov     matchLen, bx
  326.               cmp     bx, F
  327.               jb      @Ins1
  328.   @Ins8:      mov     ax, word ptr [Offset Mom + si]
  329.               mov     word ptr [Offset Mom + di], ax
  330.               mov     bx, word ptr [Offset Left + si]
  331.               mov     word ptr [Offset Left + di], bx
  332.               mov     word ptr [Offset Mom + bx], di
  333.               mov     bx, word ptr [Offset Right + si]
  334.               mov     word ptr [Offset Right + di], bx
  335.               mov     word ptr [Offset Mom + bx], di
  336.               mov     bx, word ptr [Offset Mom + si]
  337.               cmp     si, word ptr [Offset Right + bx]
  338.               jne     @Ins9
  339.               mov     word ptr [Offset Right + bx], di
  340.               jmp     @Ins10
  341.   @Ins9:      mov     word ptr [Offset Left + bx], di
  342.   @Ins10:     mov     word ptr [Offset Mom + si], NUL
  343.   @Ins11:     cmp     height, 30
  344.               jb      @Ins12
  345.               call    Splay
  346.   @Ins12:     pop     bx
  347.               pop     cx
  348.               pop     dx
  349.               pop     si
  350.               shr     di, 1
  351. END;
  352.  
  353.  
  354. {
  355.   ; deleteNode : delete the node from the tree
  356.   ;
  357.   ;           ENTRY : SI = position in the buffer
  358. }
  359. PROCEDURE DeleteNode; Assembler;
  360.   ASM
  361.               push    di
  362.               push    bx
  363.               shl     si, 1
  364.               cmp     word ptr [Offset Mom + si], NUL   { ; if it has no parent then exit }
  365.               je      @del7
  366.               cmp     word ptr [Offset Right + si], NUL { ; does it have right child ? }
  367.               je      @del8
  368.               mov     di, word ptr [Offset Left + si]   { ; does it have left child ? }
  369.               cmp     di, NUL
  370.               je      @del9
  371.               mov     ax, word ptr [Offset Right + di]  { ; does it have right grandchild ? }
  372.               cmp     ax, NUL
  373.               je      @del2                             { ; if no then skip }
  374.   @del1:      mov     di, ax                            { ; find the rightmost node in }
  375.               mov     ax, word ptr [Offset Right + di]  { ;   the right subtree }
  376.               cmp     ax, NUL
  377.               jne     @del1
  378.               mov     bx, word ptr [Offset Mom + di]    { ; move this node as the root of }
  379.               mov     ax, word ptr [Offset Left + di]   { ;   the subtree }
  380.               mov     word ptr [Offset Right + bx], ax
  381.               xchg    ax, bx
  382.               mov     word ptr [Offset Mom + bx], ax
  383.               mov     bx, word ptr [Offset Left + si]
  384.               mov     word ptr [Offset Left + di], bx
  385.               mov     word ptr [Offset Mom + bx], di
  386.   @del2:      mov     bx, word ptr [Offset Right + si]
  387.               mov     word ptr [Offset Right + di], bx
  388.               mov     word ptr [Offset Mom + bx], di
  389.   @del3:      mov     bx, word ptr [Offset Mom + si]
  390.               mov     word ptr [Offset Mom + di], bx
  391.               cmp     si, word ptr [Offset Right + bx]
  392.               jne     @del4
  393.               mov     word ptr [Offset Right + bx], di
  394.               jmp     @del5
  395.   @del4:      mov     word ptr [Offset Left + bx], di
  396.   @del5:      mov     word ptr [Offset Mom + si], NUL
  397.   @del7:      pop     bx
  398.               pop     di
  399.               shr     si, 1
  400.               jmp     @end;
  401.   @del8:      mov     di, word ptr [Offset Left + si]
  402.               jmp     @del3
  403.   @del9:      mov     di, word ptr [Offset Right + si]
  404.               jmp     @del3
  405.   @end:
  406.   END;
  407.  
  408.  
  409. PROCEDURE Encode; Assembler;
  410.   ASM
  411.               call    initTree
  412.               xor     bx, bx
  413.               mov     [Offset CodeBuf + bx], bl
  414.               mov     dx, 1
  415.               mov     ch, dl
  416.               xor     si, si
  417.               mov     di, N - F
  418.   @Encode2:   call    getc
  419.               jc      @Encode3
  420.               mov     byte ptr [Offset TextBuf +di + bx], al
  421.               inc     bx
  422.               cmp     bx, F
  423.               jb      @Encode2
  424.   @Encode3:   or      bx, bx
  425.               jne     @Encode4
  426.               jmp     @Encode19
  427.   @Encode4:   mov     cl, bl
  428.               mov     bx, 1
  429.               push    di
  430.               sub     di, 1
  431.   @Encode5:   call    InsertNode
  432.               inc     bx
  433.               dec     di
  434.               cmp     bx, F
  435.               jbe     @Encode5
  436.               pop     di
  437.               call    insertNode
  438.   @Encode6:   mov     ax, matchLen
  439.               cmp     al, cl
  440.               jbe     @Encode7
  441.               mov     al, cl
  442.               mov     matchLen, ax
  443.   @Encode7:   cmp     al, THRESHOLD
  444.               ja      @Encode8
  445.               mov     matchLen, 1
  446.               or      byte ptr codeBuf, ch
  447.               mov     bx, dx
  448.               mov     al, byte ptr [Offset TextBuf + di]
  449.               mov     byte ptr [Offset CodeBuf + bx], al
  450.               inc     dx
  451.               jmp     @Encode9
  452.   @Encode8:   mov     bx, dx
  453.               mov     al, byte ptr matchPos
  454.               mov     byte ptr [Offset Codebuf + bx], al
  455.               inc     bx
  456.               mov     al, byte ptr (matchPos + 1)
  457.               push    cx
  458.               mov     cl, 4
  459.               shl     al, cl
  460.               pop     cx
  461.               mov     ah, byte ptr matchLen
  462.               sub     ah, THRESHOLD + 1
  463.               add     al, ah
  464.               mov     byte ptr [Offset Codebuf + bx], al
  465.               inc     bx
  466.               mov     dx, bx
  467.   @Encode9:   shl     ch, 1
  468.               jnz     @Encode11
  469.               xor     bx, bx
  470.   @Encode10:  mov     al, byte ptr [Offset CodeBuf + bx]
  471.               call    putc
  472.               inc     bx
  473.               cmp     bx, dx
  474.               jb      @Encode10
  475.               mov     dx, 1
  476.               mov     ch, dl
  477.               mov     byte ptr codeBuf, dh
  478.   @Encode11:  mov     bx, matchLen
  479.               mov     lastLen, bx
  480.               xor     bx, bx
  481.   @Encode12:  call    getc
  482.               jc      @Encode14
  483.               push    ax
  484.               call    deleteNode
  485.               pop     ax
  486.               mov     byte ptr [Offset TextBuf + si], al
  487.               cmp     si, F - 1
  488.               jae     @Encode13
  489.               mov     byte ptr [Offset TextBuf + si + N], al
  490.   @Encode13:  inc     si
  491.               and     si, N - 1
  492.               inc     di
  493.               and     di, N - 1
  494.               call    insertNode
  495.               inc     bx
  496.               cmp     bx, lastLen
  497.               jb      @Encode12
  498.   @Encode14:  sub     printCount, bx
  499.               jnc     @Encode15
  500.               mov     ax, printPeriod
  501.               mov     printCount, ax
  502. (*              push    dx                 { Print out a period as a sign. }
  503.               mov     dl, DBLARROW
  504.               mov     ah, 2
  505.               int     21h
  506.               pop     dx *)
  507.   @Encode15:  cmp     bx, lastLen
  508.               jae     @Encode16
  509.               inc     bx
  510.               call    deleteNode
  511.               inc     si
  512.               and     si, N - 1
  513.               inc     di
  514.               and     di, N - 1
  515.               dec     cl
  516.               jz      @Encode15
  517.               call    insertNode
  518.               jmp     @Encode15
  519.   @Encode16:  cmp     cl, 0
  520.               jbe     @Encode17
  521.               jmp     @Encode6
  522.   @Encode17:  cmp     dx, 1
  523.               jb      @Encode19
  524.               xor     bx, bx
  525.   @Encode18:  mov     al, byte ptr [Offset Codebuf + bx]
  526.               call    putc
  527.               inc     bx
  528.               cmp     bx, dx
  529.               jb      @Encode18
  530.   @Encode19:
  531. END;
  532.  
  533.  
  534.  
  535. PROCEDURE Decode; Assembler;
  536.   ASM
  537.               xor     dx, dx
  538.               mov     di, N - F
  539.   @Decode2:   shr     dx, 1
  540.               or      dh, dh
  541.               jnz     @Decode3
  542.               call    getc
  543.               jc      @Decode9
  544.               mov     dh, 0ffh
  545.               mov     dl, al
  546.   @Decode3:   test    dx, 1
  547.               jz      @Decode4
  548.               call    getc
  549.               jc      @Decode9
  550.               mov     byte ptr [Offset TextBuf + di], al
  551.               inc     di
  552.               and     di, N - 1
  553.               call    putc
  554.               jmp     @Decode2
  555.   @Decode4:   call    getc
  556.               jc      @Decode9
  557.               mov     ch, al
  558.               call    getc
  559.               jc      @Decode9
  560.               mov     bh, al
  561.               mov     cl, 4
  562.               shr     bh, cl
  563.               mov     bl, ch
  564.               mov     cl, al
  565.               and     cl, 0fh
  566.               add     cl, THRESHOLD
  567.               inc     cl
  568.   @Decode5:   and     bx, N - 1
  569.               mov     al, byte ptr [Offset TextBuf + bx]
  570.               mov     byte ptr [Offset TextBuf + di], al
  571.               inc     di
  572.               and     di, N - 1
  573.               call    putc
  574.               inc     bx
  575.               dec     cl
  576.               jnz     @Decode5
  577.               jmp     @Decode2
  578.   @Decode9:
  579.   END;
  580.  
  581.  
  582.  
  583. PROCEDURE LZSSquash;
  584. BEGIN
  585.   InBufPtr    := BUFSIZE;
  586.   InBufSize   := BUFSIZE;
  587.   OutBufPtr   := 0;
  588.   printcount  := 0;
  589.   height      := 0;
  590.   matchPos    := 0;
  591.   matchLen    := 0;
  592.   lastLen     := 0;
  593.   printPeriod := 0;
  594.   opt         := 0;
  595.  
  596.   FillChar(TextBuf,Sizeof(TextBuf),0);
  597.   FillChar(Left,Sizeof(Left),0);
  598.   FillChar(Mom,Sizeof(Mom),0);
  599.   FillChar(Right,Sizeof(Right),0);
  600.   FillChar(codeBuf,Sizeof(codebuf),0);
  601.  
  602.   encode;
  603.   writeout;
  604. END;
  605.  
  606. PROCEDURE LZSSUnSquash;
  607. BEGIN
  608.   InBufPtr  := BUFSIZE;
  609.   InBufSize := BUFSIZE;
  610.   OutBufPtr := 0;
  611.   FillChar(TextBuf,Sizeof(TextBuf),0);
  612.  
  613.   decode;
  614.   writeout;
  615. END;
  616.  
  617.  
  618.  
  619. BEGIN
  620.   IF (ParamCount < 2) OR (ParamCount > 4) THEN
  621.     BEGIN
  622.       Writeln('Usage: ',ParamStr(0),' inputfile outputfile [decompress]');
  623.       HALT;
  624.     END;
  625.   IF (ParamStr(1) = ParamStr(2)) THEN
  626.     BEGIN
  627.       Writeln('File names must be different');
  628.       HALT;
  629.     END;
  630.  
  631.   Assign(Infile,ParamStr(1));
  632. {$I-}
  633.   Reset(infile,1);
  634.   IF IOResult <> 0 THEN
  635.     BEGIN
  636.       Writeln('Error opening input file ',ParamStr(1));
  637.       HALT;
  638.     END;
  639.  
  640.   Assign(OutFile,ParamStr(2));
  641.   ReWrite(outFile,1);
  642. {$I+}
  643.   IF IOResult <> 0 THEN
  644.     BEGIN
  645.       Writeln('Error opening output file ',ParamStr(2));
  646.       HALT;
  647.     END;
  648.  
  649.    IF (ParamCount <> 3) THEN
  650.      BEGIN
  651.         LZSSquash;
  652.      END
  653.    ELSE
  654.      BEGIN
  655.        LZSSUnSquash;
  656.     END;
  657.   Close(outfile);
  658.   Close(infile);
  659. END.