home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / kboom11.zip / KBOOM11.ASM next >
Assembly Source File  |  1993-01-08  |  55KB  |  1,372 lines

  1. .MODEL small
  2.  
  3. COMMENT #
  4.  
  5.                  "AP-SLIDER"  (LZW) DYNAMIC DICTIONARY COMPRESSION
  6.                               uses 13 bit pointers and
  7.                                     8k dictionary
  8.                                        w/update
  9.                                (oldest leaf is deleted)
  10.                                     (one-at-a-time)
  11.                                   Memory needed: 100k
  12.  
  13.                                  Written in MASM 6.0
  14.                                  Miles Pawski, 1992
  15.  
  16.                                 THIS PROGRAM IS FREE
  17.  
  18.       To assemble & link under MASM 6.0 (use ML.EXE):  ML kboom11.asm   
  19.  
  20.       Requirements:   8086+
  21.  
  22.       Please note:  Stack frames are generated automatically by                                  
  23.                     procedures called by the INVOKE directive. 
  24.                     The stack is automatically cleaned up by the
  25.                     RET instruction.  Local variables are automatically
  26.                     referenced and coded.  You can eliminate the INVOKE
  27.                     directive by passing parameters in variables or
  28.                     registers.  The USES list automatically pushes (on entry)
  29.                     and pops (on ret) the indicated registers.  You can
  30.                     eliminate this with the appropriate code within the 
  31.                     procedure.     
  32.  
  33.                     .WHILE .IF .ELSEIF .ELSE, etc. are automatic generations            
  34.                     of the cmp/jne/jmp... routines.  An .IF .ENDIF block
  35.                     is basically a cmp/jne routine.  Adding an .ELSEIF
  36.                     puts in a cmp/jump-around, etc.                        
  37.  
  38.  
  39.                     .STARTUP generates the following code (if default near-
  40.                      stack is used - this places the stack in DGROUP so ss:sp
  41.                      needs to be adjusted).  Only the first two lines are 
  42.                      required if using using FARSTACK (stack in its own 
  43.                      segment).  FARSTACK can be specified by indicating
  44.                      it in the .MODEL directive: .MODEL small,farstack       
  45.  
  46.                                     mov dx,DGROUP
  47.                                     mov ds,dx
  48.                                     mov bx,ss
  49.                                     sub bx,dx
  50.                                     shl bx,1
  51.                                     shl bx,1
  52.                                     shl bx,1
  53.                                     shl bx,1
  54.                                     cli
  55.                                     mov ss,dx
  56.                                     add sp,bx
  57.                                     sti
  58.  
  59.  
  60.                     .EXIT generates terminate program code using int 21h,
  61.                           function 04ch.
  62.    
  63.                     The ASSUME assembler directive was used to automatically
  64.                     provide various segment over-rides for various array
  65.                     variables.  For examble, ASSUME es:seg parfield generates
  66.                     this code: es:parfield.     
  67.  
  68.                     THIS PROGRAM is based on James Storer's 'squeeze' source
  69.                     code found in his book DATA COMPRESSION, METHODS AND
  70.                     THEORY, 1988 - Computer Science Press.  Modification
  71.                     and methods were based on experimentation, general
  72.                     tree theory of data structures and ideas put forth in
  73.                     Mr. Storer's book.  Mr. Storer's original source code
  74.                     is in PASCAL.  This program will hopefully provide a
  75.                     better understanding of the LZW method and complex,
  76.                     linked tree structures and there use.        
  77.  
  78.  #
  79.  
  80.  
  81.  ;---------------------------MACROS---------------------------------------  
  82.  
  83.  child macro mainptr,char
  84.    xor ax,ax                           ;;returns pointer value in ax
  85.    mov cx,char
  86.    mov bx,mainptr
  87.       shl bx,1                         ;;make mainptr word indexer
  88.       mov ax,lcfield[bx]               ;;get child from lcfield
  89.       mov bx,ax                        ;;put in bx to index
  90.       shl bx,1                         ;;make word ptr
  91.      .WHILE ax != NILPTR && cx != ctrfield[bx]
  92.          mov ax,rsibfield[bx]          ;;cx=indexed char
  93.          mov bx,ax                     ;;if first child <> NILPTR and 
  94.          shl bx,1                      ;;char <> indexed char then walk the
  95.      .ENDW                             ;;linked list of siblings of child
  96.   endm                                 ;;until we find a match
  97.                                        ;;no match returns NILPTR
  98.  
  99.    parent macro mainptr
  100.     xor ax,ax                 ;returns pointer value in ax
  101.     mov bx,mainptr
  102.     shl bx,1
  103.     mov ax,es:parfield[bx]
  104.     endm
  105.  
  106.   ctr1 macro mainptr
  107.    xor ax,ax                 ;returns pointer value in ax
  108.    mov bx,mainptr
  109.    shl bx,1
  110.    mov ax,ctrfield[bx]
  111.    endm
  112.  
  113.    print macro char
  114.      mov ah,02h
  115.      forc arg1,<char>
  116.       mov dl,"&arg1"
  117.       int 21h                     ;;print string to screen: print HELLO
  118.      endm
  119.    endm
  120.  
  121.    close macro handle
  122.    mov ah,3eh
  123.    mov bx,handle                  ;;file closure
  124.    int 21h
  125.    endm
  126.  
  127.    writestring macro string,length
  128.    mov ah,40h
  129.    mov bx,1
  130.    mov cx,length                  ;;write string to screen
  131.    lea dx,string
  132.    int 21h
  133.    endm           
  134.  
  135.    writefile macro var,handle,len
  136.    mov ah,40h
  137.    mov bx,handle                  ;;write to file handle from variable
  138.    mov cx,len
  139.    lea dx,var
  140.    int 21h
  141.    endm   
  142.  
  143.   readfile macro var,handle,len
  144.   mov ah,3fh
  145.   mov bx,handle                   ;;read from file handle into variable
  146.   mov cx,len              
  147.   lea dx,var 
  148.   int 21h                 
  149.   endm
  150.  
  151. ;------------------------------------------------------------------------  
  152. ;   ADD_LEAF macro.  Adds a leaf to the tree. 
  153. ;   Input: Parent node, node (code) to be added, character (mval)   
  154. ;   ** See James Storer's  DATA COMPRESSION, METHODS AND THEORY
  155. ;      for more explanations,theory and original PASCAL code.
  156. ;------------------------------------------------------------------------
  157.   
  158.  add_leaf macro 
  159.  .IF prevptr != NILPTR  
  160.   push dx
  161.   push si
  162.   push di
  163.   mov bx,trieptr                    ;new code
  164.   mov dx,bx                         ;save a copy of new code in dx
  165.   mov ax,mval                       ;match character
  166.   mov di,prevptr                    ;parent node in di
  167.   shl bx,1
  168.   mov ctrfield[bx],ax               ;ctrfield(mainptr)=char
  169.   mov parfield[bx],di               ;parfield(mainptr)=parptr
  170.   mov lcfield[bx],NILPTR            ;lcfield(mainptr)=NILPTR
  171.   mov lsibfield[bx],NILPTR
  172.   shl di,1                          ;make parptr word indexer
  173.   mov si,lcfield[di]                ;si=lcfield(parptr)
  174.   mov rsibfield[bx],si              ;rsibfield(mainptr)=lcfield(parptr)
  175.   .IF si != NILPTR                  ;si=lcfield(parptr)           
  176.       shl si,1
  177.       mov lsibfield[si],dx          ;lsibfield(lcfield(parptr))=mainptr
  178.   .ENDIF
  179.   mov lcfield[di],dx                ;lcfield(parptr)=ptr
  180.   pop di
  181.   pop si
  182.   pop dx  
  183. .ENDIF
  184.   endm
  185.  
  186. ;----------------------------------------------------------------------
  187. ;  DELETE_LEAF macro.  Deletes a leaf from the tree. 
  188. ;  Input: Node (code) to be deleted.  Passed in variable (trieptr)
  189. ;  If node has siblings, they will be connected to each other properly
  190. ;  after the node is deleted.        
  191. ;  ** See James Storer's  DATA COMPRESSION, METHODS AND THEORY
  192. ;     for more explanations,theory and original PASCAL code  
  193. ;----------------------------------------------------------------------
  194.  
  195.   delete_leaf macro
  196.   push si
  197.   push di
  198.   mov bx,trieptr                    ;bx=code to be deleted 
  199.   shl bx,1
  200.   mov ax,rsibfield[bx]              ;ax=rsibfield(mainptr)   
  201.   .IF lsibfield[bx] != NILPTR
  202.      mov di,lsibfield[bx]           ;connect left sibling and right sibling   
  203.      shl di,1                       ;through rsibfield of left sibling (huh?)
  204.      mov rsibfield[di],ax           ;rsibfield[lsibfield(mainptr))=
  205.   .ELSE                             ;                 rsibfield(mainptr)
  206.      mov di,parfield[bx]            ;di=parfield(mainptr)
  207.      shl di,1
  208.      mov lcfield[di],ax             ;lcfield(parfield(mainptr))= 
  209.   .ENDIF                            ;                 rsibfield(mainptr)
  210.   .IF ax != NILPTR
  211.      mov di,lsibfield[bx]           ;di=lsibfield(mainptr)
  212.      mov si,ax                      ;make left sibling of deleted leaf the
  213.      shl si,1                       ;left sibling of deleted leaf's right sib.
  214.      mov lsibfield[si],di           ;lsibfield[rsibfield(mainptr))=
  215.   .ENDIF                            ;                 lsibfield(mainptr)
  216.     pop di
  217.     pop si
  218.     endm
  219.  
  220. ;--------------------------------------------------------------------------
  221.  
  222.      ;MASM 6.0 is 1-pass assembly.  Procedures called with the INVOKE
  223.      ;directive that are physically located AFTER the call in the source
  224.      ;code must be declared with PROTO.  Far procedures must be declared
  225.      ;also although this code has none.  
  226.  
  227.  
  228.    cmdline PROTO near C,arg1:WORD,arg2:WORD,arg3:WORD  
  229.    caps PROTO near C,arg1:WORD,arg2:WORD   
  230.  
  231.  
  232. .STACK
  233.  
  234.  
  235.  
  236. .DATA
  237.  
  238.   dictsize      WORD  00h      
  239.   curptr        WORD  00h
  240.   curlen        WORD  00h
  241.   prevptr       WORD  00h 
  242.   trieptr       WORD  00h
  243.   mval          WORD  00h
  244.   mindex        WORD  00h
  245.   prevlen       WORD  00h
  246.   mstart        WORD  00h
  247.   outcount      WORD  00h
  248.   incount       WORD  00h
  249.   bytes_read    WORD   ? 
  250.   eight_count   BYTE  00h
  251.   sixteen_count BYTE  16
  252.   all_over      BYTE  00h 
  253.   bigplace      WORD  256          
  254.  
  255.   filename      BYTE  50 dup (00)
  256.   tempfile      BYTE  50 dup (00)
  257.   parabuf       BYTE  50 dup (00)
  258.   paraflag      BYTE  00h  
  259.   compflag      BYTE  00h 
  260.   decompflag    BYTE  00h    
  261.   file_handle   WORD  ?
  262.   file_handle2  WORD  ?    
  263.   inputbyte     WORD  00h
  264.   end_flag      BYTE  00h
  265.   init_size    DWORD  ?
  266.   master_size  DWORD  00h
  267.   filelen       WORD  ? 
  268.   filelen2      WORD  ?
  269.   comp_size    DWORD  ? 
  270.   dictflag      BYTE  00h
  271.   incflag       BYTE  00h           
  272.   work_code     BYTE  0,0,0,0
  273.   ascii_string  BYTE  10 dup (00h)
  274.   count         WORD  00h
  275.   xdate         WORD  ?
  276.   xtime         WORD  ?    
  277.   nologo_flag   BYTE  00h
  278.   comp_flag     BYTE  00h
  279.   decomp_flag   BYTE  00h
  280.  
  281.  
  282.  
  283.   comp          BYTE  "Compressing: "
  284.   spc           BYTE  70 dup (20h)
  285.   fsize         BYTE  "Comp. size: " 
  286.   isize         BYTE  "Orig. size: "   
  287.   ratio         BYTE  "Ratio: "
  288.   perc          BYTE  "%"
  289.   crlf          BYTE  13,10
  290.   expand        BYTE  "Expanding: "
  291.   arrow         BYTE  " --> "
  292.   fnl           BYTE  "Exp. Size: "
  293.   kboom_code    BYTE  "¿MP¿"
  294.   sorry0        BYTE  "Sorry..."
  295.   sorry1        BYTE  " was not compressed by Kboom11"
  296.  
  297.   logo    BYTE  13,10,"  Kboom11  LZW File Encoding/Decoding Utility featuring",13,10,
  298.                       "  8k Dynamic Dictionary w/discrete update",13,10,                                                        
  299.                       "  Miles Pawski   CIS: 70473,527      1992",13,10,13,10       
  300.  
  301.  
  302.   format  BYTE  "FORMAT: kboom11 [input file] [output file] [/c][/d][/n]",13,10,
  303.                 "        /c - Compression /d - Decompression /n - No logo"
  304.  
  305.  
  306.     ;Assembly-time constants 
  307.  
  308.   MAXINCREMENT  EQU     4     ;AP - All prefixes  
  309.   MAXMATCH      EQU   100     ;max string match=100
  310.   STATICSIZE    EQU   256     ;constant dictionary gaurantees first match
  311.   DICTIONARY    EQU  8192   
  312.   MAXPTR        EQU  DICTIONARY-2    ;highest pointer
  313.   NILPTR        EQU  DICTIONARY-1    ;end code - root code
  314.  
  315.     ;For experimentation.  If the DICTIONARY size is changed, this
  316.     ;text sequence automatically changes CODESIZE and BITSHIFT to fit
  317.     ;the DICTIONARY.  CODESIZE and BITSHIFT are used in the code to
  318.     ;read and write pointers from and to the bit stream.                                                                
  319.     ;Use only the below DICTIONARY values.
  320.  
  321.    IF DICTIONARY EQ 512
  322.       CODESIZE EQU 9
  323.       BITSHIFT EQU 7 
  324.    ELSEIF DICTIONARY EQ 1024
  325.       CODESIZE EQU 10
  326.       BITSHIFT EQU 6    
  327.    ELSEIF DICTIONARY EQ 2048 
  328.       CODESIZE EQU 11
  329.       BITSHIFT EQU 5
  330.    ELSEIF DICTIONARY EQ 4096
  331.       CODESIZE EQU 12
  332.       BITSHIFT EQU 4 
  333.    ELSEIF DICTIONARY EQ 8192
  334.       CODESIZE EQU 13
  335.       BITSHIFT EQU 3
  336.    ENDIF 
  337.  
  338.         ;   I split the array fields between the near and far BSS (un-  
  339.         ;   initialized data) segments.  I couldn't get all the variables 
  340.         ;   and arrays into one data segment, especially when using an 8k
  341.         ;   dictionary.
  342.  
  343. .DATA?           ;DATA? is a default BSS segment in DGROUP
  344.  
  345.  ;-------------------------------------------
  346.  fielder    label  WORD
  347.  
  348.  ctrfield          WORD     DICTIONARY dup (?)
  349.  lcfield           WORD     DICTIONARY dup (?)
  350.  ;-------------------------------------------
  351.  
  352.  match             BYTE     100 dup (?),?
  353.  
  354.  
  355.  
  356. OUTSEG SEGMENT PARA PRIVATE 'FAR_BSS'
  357.  
  358. ;----------------------------------------
  359. fielder_two  label  WORD  
  360.  
  361.   parfield          WORD     DICTIONARY dup (?)
  362.   rsibfield         WORD     DICTIONARY dup (?)
  363.   lsibfield         WORD     DICTIONARY dup (?)
  364. ;----------------------------------------
  365.  
  366.   outbuffer         BYTE     8000 dup (?)    ;file i/o buffers
  367.   inbuffer          BYTE     8000 dup (?)
  368. OUTSEG ENDS
  369.  
  370.  
  371. .CODE 
  372.  
  373. .STARTUP
  374.  
  375. ;-----------------------------MAIN PROGRAM------------------------------
  376.  
  377.  invoke cmdline, ADDR filename,ADDR tempfile,ADDR parabuf                   
  378.  cmp filelen,00h                         ;if source filename length=0,    
  379.  je form                                 ;quit with FORMAT display   
  380.  cmp paraflag,01h                        ;if no parameters, quit with     
  381.  jne form                                ;FORMAT display
  382.  
  383.    call initialize                       ;set variables  
  384.    mov di,seg outbuffer
  385.    mov es,di                             ;set es=far (output) segment
  386.  
  387.    ASSUME es:seg parfield,es:seg lsibfield,es:seg rsibfield
  388.                                   ;ASSUME usage:
  389.                                   ;sets assembler for automatic segment
  390.                                   ;over-rides for the listed variables
  391.  
  392.      invoke caps,ADDR parabuf,50         ;capitalize parameters
  393.  
  394.      mov di, offset parabuf              ;read parameters
  395.      mov cx,50
  396.      @@:
  397.        mov ax,word ptr [di]
  398.        .IF ax=="N/" 
  399.           mov nologo_flag,01h
  400.        .ELSEIF ax=="C/"
  401.           mov comp_flag,01h
  402.        .ELSEIF ax=="D/"
  403.           mov decomp_flag,01h
  404.        .ENDIF
  405.        inc di
  406.        loop @B
  407.  
  408.        .IF comp_flag == 01h
  409.            call compression
  410.            jmp final_exit
  411.        .ELSEIF decomp_flag == 01h
  412.            call decompression
  413.            jmp final_exit
  414.        .ENDIF
  415.  
  416.    form:
  417.        writestring format,SIZEOF format   
  418.  
  419.    final_exit:
  420.  
  421.       .EXIT
  422.  
  423. ;-------------------------------------------------------------------------
  424.  
  425.  
  426.  
  427. ;╔══════════════════════════════════════════════════════════════════════╗
  428. ;║                                                                      ║
  429. ;║                                                                      ║
  430. ;║                            PROCEDURE SECTION                         ║
  431. ;║                                                                      ║
  432. ;║                                                                      ║
  433. ;╚══════════════════════════════════════════════════════════════════════╝ 
  434.  
  435. ;------------------------------------------------------------------------
  436. ;                                                                       |
  437. ;                    MAIN COMPRESSION SEQUENCE                          |
  438. ;                                                                       |
  439. ;------------------------------------------------------------------------  
  440.  
  441.   compression proc near PRIVATE 
  442.  
  443.      call open_source_file            ;open source file
  444.      .IF CARRY?
  445.        jmp final
  446.      .ENDIF
  447.  
  448.      push es
  449.      mov ah,4eh                       ;function 4eh
  450.      mov cx,10h                       ;file attribute
  451.      mov dx,offset filename           ;point to filespec
  452.      int 21h                          ;"first match" interrupt
  453.  
  454.      mov ah,2fh
  455.      int 21h                          ;get dta
  456.      mov ax,word ptr es:[bx+1ah]      ;get file size from dta
  457.      mov dx,word ptr es:[bx+1ah][2]
  458.      mov word ptr [init_size][0],ax   ;record in variable 
  459.      mov word ptr [init_size][2],dx   
  460.      mov ax,word ptr es:[bx+16h]      ;get file time
  461.      mov xtime,ax                                   
  462.      mov ax,word ptr es:[bx+18h]      ;get file date
  463.      mov xdate,ax
  464.      pop es
  465.  
  466.  
  467.      call open_second_file            ;open target file
  468.      .IF CARRY?
  469.        jmp final
  470.      .ENDIF
  471.  
  472.      .IF nologo_flag != 01h
  473.          writestring logo,SIZEOF logo
  474.      .ENDIF
  475.  
  476.   writestring comp,SIZEOF comp          ;"Compressing: "
  477.   writestring filename,filelen          ; [filename]           
  478.  
  479.   writefile kboom_code,file_handle2,4   ;write kboom code to file in
  480.                                         ;first 4 bytes so we won't try to
  481.                                         ;expand any files not generated by
  482.                                         ;this program: ¿MP¿
  483.  
  484.   writefile init_size,file_handle2,4    ;write next 4 bytes to file
  485.                                         ;which represent what file size
  486.                                         ;should be when expansion is
  487.                                         ;finished
  488.  
  489.   writefile xdate,file_handle2,2        ;write date to file
  490.   writefile xtime,file_handle2,2        ;write time to file
  491.  
  492.   mov di,offset outbuffer               ;set output buffer.  es already set
  493.  
  494.   call read_file                        ;read file into buffer
  495.   mov al, es:[si]                       ;get first byte from buffer
  496.   inc si
  497.   inc incount
  498.   xor ah,ah                             ;convert to word  
  499.   mov inputbyte,ax                      ;move byte into variable 
  500.  
  501.  
  502.                ;--------- MAIN COMPRESSION LOOP ----------
  503.  
  504.  .WHILE 1                               ;loop indefinitely
  505.  
  506.    mov ax,inputbyte                     ;same as: child NILPTR, inputbyte
  507.    mov trieptr,ax                       ;first ptr is always character and   
  508.                                         ;gets us into the root level     
  509.  
  510.    mov ax,curptr
  511.    mov prevptr,ax                       ;prevptr=curptr
  512.    mov ax,curlen
  513.    mov prevlen,ax                       ;prevlen=curlen
  514.    mov curlen,0000h
  515.  
  516.          .WHILE trieptr != NILPTR       ;first trieptr is never NILPTR             
  517.  
  518.             mov ax,trieptr              ;curptr=trieptr
  519.             mov curptr,ax
  520.             mov bx,curlen 
  521.             mov ax,inputbyte
  522.             mov match[bx],al            ;record byte in array starting      
  523.             inc curlen                  ;at postion 00.  Curlen indexes in.
  524.                                         ;This is used by update process. 
  525.                                         ;First byte in loop is always a match
  526.  
  527.                 mov ax,incount
  528.                 cmp ax,bytes_read       ;see if we'er at end of input buffer 
  529.                 jae read_leave          ;if not, keep reading
  530.  
  531.            goon:                                     
  532.                 mov al,es:[si]          ;get new byte
  533.                 inc si
  534.                 inc incount
  535.                 xor ah,ah
  536.                 mov inputbyte,ax          ;place in variable
  537.                 child curptr,inputbyte    ;see if new byte is child of curptr
  538.                 mov trieptr,ax            ;result in ax -> trieptr  
  539.                                           ;keep walking down the tree if   
  540.          .ENDW                            ;we have a match (trieptr <> NILPTR)
  541.  
  542.            leaving:    
  543.             mov mstart,00h
  544.             mov bx,curptr                 ;mov curptr in bx
  545.  
  546.             xor ax,ax
  547.             mov al,sixteen_count          ;get number of bit positions left
  548.  
  549.             repeat BITSHIFT
  550.              shl bx,1                     ;CODESIZE bit pointer will now start 
  551.              endm                         ;at left end of word.  We want to
  552.                                           ;output curptr into bit stream.
  553.             xor cx,cx
  554.             bigloop:
  555.               cmp cx,CODESIZE             ;check code bit counter            
  556.               je outbig                   ;done?  then leave.  Shift both in
  557.               shl bx,1                    ;unison.  dx holds bits.
  558.               rcl dx,1                    ;carry added to dl if set by bx.
  559.               inc cx                      ;We are copying bx to dx bit by
  560.               dec ax                      ;bit. ax=dx bit counter
  561.              jnz bigloop
  562.  
  563.           ;---------------- JUMP-OUTS & FALL-THROUGHS ----------------------
  564.           ;                   conditional branches                         ;
  565.           ;             kept out of main loops for speed                   ;
  566.           ;                                                                ;
  567.               mov ax,dx                                                    ;
  568.               stosw                       ;store word in buffer            ;
  569.               xor dx,dx                   ;clear out dl                    ;
  570.               mov ax,16                   ;reset output bit counter        ;
  571.                 inc outcount              ;record byte output              ;
  572.                 inc outcount                                               ;
  573.                 cmp outcount,8000         ;see if we're at end of output   ;
  574.                 jae next6                 ;buffer.  If not, go on.         ;
  575.                                           ;if at end, flush the buffer     ;
  576.             next5:                                                         ;
  577.               cmp cx,CODESIZE-8           ;if we have enough bits left     ;
  578.               ja bigloop                  ;and dx is clear, then we can    ; 
  579.               mov dl,bh                   ;move a whole byte (bh) at once. ; 
  580.               mov bh,bl                   ;move bl over to left of word    ;  
  581.               mov ax,8                    ;adjust output bit counter       ;
  582.               add cx,8                    ;adjust bit counter for CODESIZE ;
  583.               jmp bigloop                                                  ;
  584.                                                                            ;
  585.             next6:                                                         ;
  586.               call write_file             ;flush buffer to file            ;
  587.               jmp next5                   ;continue                        ;
  588.                                                                            ;
  589.             read_leave:                                                    ;
  590.               .IF end_flag==01h       ;check for eof.  End_flag set if eof.;
  591.                   mov all_over,01h     ;set another flag so we can process ;
  592.                   jmp leaving           ;the last byte                     ; 
  593.               .ENDIF                                                       ;
  594.               call read_file          ;read more from file into buffer     ;
  595.               jmp goon                                                     ;
  596.           ;                                                                ;
  597.           ;-----------------------------------------------------------------
  598.  
  599.  
  600.             outbig:    
  601.             mov sixteen_count,al          ;save bit count
  602.             cmp all_over,01h              ;last byte?  then leave
  603.             je endup 
  604.  
  605.             call update                   ;update the tree
  606.  
  607.  .ENDW
  608.  
  609.                ;-------------- END MAIN COMPRESSION LOOP ------------
  610.  
  611.  endup:
  612.  
  613.  .IF  sixteen_count > 00                  ;see if we have leftover in dx
  614.       mov cl,sixteen_count                ;if so, shift them all to the
  615.       shl dx,cl                           ;left so we don't mess up the
  616.       mov ax,dx                           ;bit stream.
  617.       stosw             
  618.       inc outcount                        ;record final bytes
  619.       inc outcount
  620.  .ENDIF
  621.  
  622.  call write_file                          ;flush the buffer
  623.  
  624.  
  625.                  ;--------- INFO/DECORATION ---------------
  626.  
  627.  writestring crlf,2            
  628.  
  629.  writestring isize,SIZEOF isize           ;"Orig. Size: "
  630.  mov ax,word ptr init_size[0]
  631.  mov dx,word ptr init_size[2]
  632.  call convert                             ;Convert to decimal string.
  633.  writestring crlf,2                       ;value is passed to process in 
  634.                                           ;dx:ax pair
  635.  writestring fsize,SIZEOF fsize
  636.  mov ax,word ptr master_size[0]       
  637.  mov dx,word ptr master_size[2]
  638.  call convert 
  639.                                           ;"Comp. size; " 
  640.  writestring crlf,2                       ; carriage return-line feed
  641.  writestring ratio,SIZEOF ratio           ;"Ratio: "
  642.  
  643.                        ;Ratio is not % saved but, rather    
  644.                        ;the new file length divided by the old.  
  645.                        ;However, to achieve this, I multiply the 
  646.                        ;new file length by 100 first, then divide
  647.                        ;it by the old length. 
  648.  xor bx,bx    
  649.  mov bx,100    
  650.  xor dx,dx                        ;file length.                              
  651.  mov ax,word ptr master_size[0]   ;get low word            
  652.  mul bx                           ;multiply by 100 
  653.  mov cx,dx                        ;save dx in cx
  654.  mov si,ax                        ;save low word in si
  655.  xor dx,dx
  656.  mov ax,word ptr master_size[2]   ;get high word                  dx   ax
  657.  mul bx                           ;multiply by 100                     bx
  658.  add dx,cx                        ;add saved high word          ---------
  659.  add dx,ax                        ;add high to high  (bx*ax)      cx   si
  660.  mov ax,si                        ;get back low      (bx*dx)  dx  ax
  661.                                   ;                         -------------
  662.  mov bx,word ptr init_size[0]     ;Oh well, ->                dx+ax+cx,si
  663.  mov cx,word ptr init_size[2]  
  664.  
  665.  ;dx:ax now has the new file size multiplied by 100 
  666.  ;cx:bx has original file size
  667.  
  668.        
  669.                 ;---------DIVISION ROUTINE---------
  670.  
  671. div_num_1:
  672.   or      cx,cx                   ;  Divide both numbers by 2
  673.   je      div_num_2               ;  until high word of
  674.   shr     dx,1                    ;  divisor (cx) is zero.
  675.   rcr     ax,1                    ;  if cf is set by dx shift, the bit
  676.                                   ;  will be added to the left of ax during
  677.   shr     cx,1                    ;  ax rcl
  678.   rcr     bx,1 
  679.   jmp     div_num_1
  680. div_num_2:
  681.   push    ax                      ;Save low word
  682.   mov     ax,dx
  683.   xor     dx,dx
  684.   div     bx                      ;Divide high word
  685.   mov     cx,ax                   ;Save high quotent
  686.   pop     ax
  687.   add     ax,dx                   ;add remainder to low word
  688.   div     bx                      ;Divide low word
  689.   mov     si,dx                   ;save remainder in si   
  690.   mov     dx,cx                   ;386 code is faster and easier and I would
  691.                                   ;much rather use it than going through all
  692.                                   ;this BS.  32-bit registers FOREVER! 
  693.  
  694.   push dx                         ;save high word
  695.   push ax                         ;save low word
  696.   xor dx,dx                       ;zero dx
  697.   mov ax,si                       ;get back last remainder   
  698.   mov cx,10                       ;multiply by 10    
  699.   mul cx
  700.  
  701.   div bx                          ;divide by divisor again
  702.   mov si,ax                       ;save last quotient in si
  703.                                   ;this will be first digit after decimal        
  704.  
  705.   mov ax,dx                       ;put latest remainder into ax
  706.   xor dx,dx                       ;zero dx
  707.   mul cx                          ;multiply by 10
  708.   div bx                          ;divide by divisor
  709.                                   ;this will be second digit after decimal
  710.   mov bx,ax                       ;save quotient in bx
  711.  
  712.  
  713.                 ;-------  END DIVISION ROUTINES  ----------
  714.  
  715.  
  716.   pop ax                          ;get back low word 
  717.   pop dx                          ;get back high word
  718.  
  719.   push bx                         ;save second decimal digit
  720.   push si                         ;save first decimal digit
  721.   call convert                    ;write main ratio
  722.  
  723.   mov ah,02h
  724.   mov dl,"."                      ;write decimal point "."
  725.   int 21h
  726.   pop si                          ;get back first decimal digit
  727.   pop bx                          ;get back second decimal digit
  728.  
  729.   mov dx,si                       ;put first digit into dx
  730.   xor dh,dh
  731.   add dl,48                       ;convert to ascii
  732.   int 21h                         ;write first digit after decimal to screen
  733.  
  734.   mov dl,bl                       ;put second digit into dl
  735.   add dl,48                       ;convert to ascii
  736.   int 21h                         ;write second digit after decimal to screen
  737.  
  738.   mov dl,"%"                      ;"%"
  739.   int 21h
  740.  
  741.  
  742.                  ;---------- END INFO DECORATION -----------
  743.  
  744. final:
  745.  
  746.   ret
  747. compression endp 
  748.  
  749.  
  750. ;------------------------------------------------------------------------
  751. ;                                                                       |
  752. ;                    MAIN DECOMPRESSION SEQUENCE                        |
  753. ;                                                                       |
  754. ;------------------------------------------------------------------------
  755.  
  756.  
  757.   decompression proc near PRIVATE  
  758.  
  759.      call open_source_file           ;open source file
  760.      .IF CARRY?
  761.        jmp final
  762.      .ENDIF
  763.  
  764.     push es
  765.     mov ah,4eh                       ;function 4eh
  766.     mov cx,10h                       ;file attribute
  767.     mov dx,offset filename           ;point to filespec
  768.     int 21h                          ;"first match" interrupt
  769.  
  770.     mov ah,2fh
  771.     int 21h                          ;get dta
  772.     mov ax,word ptr es:[bx+1ah]      ;get file size from dta
  773.     mov dx,word ptr es:[bx+1ah][2]
  774.     sub ax,12                        ;subtract 12 bytes because file size    
  775.     sbb dx,0000h                     ;and code are contained in these bytes  
  776.     mov word ptr [comp_size][0],ax   ;record compressed file size (from dta)
  777.     mov word ptr [comp_size][2],dx   ;date and time also take 4 bytes
  778.     pop es
  779.  
  780.   readfile work_code,file_handle,4   ;first four bytes are compression code
  781.  
  782.   mov si,offset work_code    ;check to see if code is ¿MP¿  
  783.   mov ax, word ptr [si]      ;check first pair         
  784.     cmp ax,"M¿"
  785.     jne @F
  786.     add si,2
  787.     mov ax,word ptr [si]     ;if ok, check second pair
  788.     cmp ax,"¿P"
  789.     je code_ok 
  790.    @@:
  791.     writestring sorry0,SIZEOF sorry0
  792.     writestring filename,filelen
  793.     writestring sorry1,SIZEOF sorry1
  794.     jmp final
  795.  code_ok:
  796.  
  797.    call open_second_file             ;open target file
  798.     .IF CARRY?
  799.       jmp final
  800.     .ENDIF
  801.  
  802.     .IF nologo_flag != 01h
  803.         writestring logo,SIZEOF logo
  804.     .ENDIF
  805.  
  806.   writestring expand,SIZEOF expand      ;"Expanding [] --> []
  807.   writestring filename,filelen
  808.   writestring arrow,SIZEOF arrow
  809.   writestring tempfile,filelen2   
  810.   writestring crlf,2
  811.  
  812.   readfile init_size,file_handle,4    ;second four bytes are file size   
  813.   readfile xdate,file_handle,2        ;read file date into variable
  814.   readfile xtime,file_handle,2        ;read file time into variable
  815.  
  816.   mov di,offset outbuffer
  817.  
  818.   call read_file             ;read file into buffer
  819.   mov dx,word ptr es:[si]    ;load dx with first word       
  820.   inc si
  821.   inc si
  822.   inc incount
  823.   inc incount
  824.  
  825.     ;--------------------MAIN DECOMPRESSION ROUTINE---------------------
  826.  
  827.  .WHILE 1                    ;loop indefinitely
  828.  
  829.    xor ax,ax
  830.    mov al,sixteen_count      ;get saved bit count   
  831.    xor cx,cx                 ;We need to read CODESIZE bits from input stream.
  832.    xor bx,bx                 ;We read a bit at a time from dx into bx.  The 
  833.    bigloop:                  ;leftover is left in dx for next time.
  834.       cmp cx,CODESIZE        ;see if CODESIZE bits have been read
  835.       je outbig              ;if not,read more bits
  836.                              ;if so, we have full CODESIZE bit pointer. Leave.
  837.       shl dx,1
  838.       rcl bx,1               ;bx will have pointer.  Shift in unison with
  839.       inc cx                 ;dx.  Ax keeps bit count ofn dx.  If dx is empty,
  840.       dec ax                 ;fall through and fill dx again.
  841.    jnz bigloop
  842.  
  843.  
  844.    ;-------------------JUMP-OUTS & FALL-THROUGHS ----------------------------
  845.    ;                                                                        ;
  846.        mov ax,incount        ;check byte count                              ;
  847.        cmp ax,bytes_read     ;see if all bytes have been processed from buffer
  848.        jae check_end         ;if not, proceed                               ;
  849.    next0:                                                                   ;
  850.        mov dx, word ptr es:[si]        ;put new word into dl                ;
  851.        inc incount           ;count it                                      ;
  852.        inc incount                                                          ;
  853.        inc si                                                               ;
  854.        inc si                                                               ;
  855.        mov ax,16             ;reset bit count                               ;
  856.    jmp bigloop                                                              ;
  857.                                                                             ;
  858.    check_end:                ;jump-out from above loop                      ;
  859.     .IF end_flag==01h                                                       ;
  860.       mov all_over,01h                                                      ;
  861.       jmp outbig                                                            ;
  862.     .ENDIF                                                                  ;
  863.     call read_file           ;read more of file into buffer                 ;
  864.     jmp next0                                                               ;
  865.     ;                                                                       ;
  866.     ;-----------------------------------------------------------------------;
  867.  
  868.  
  869.    outbig:
  870.    mov sixteen_count,al     ;save bit count  
  871.    mov trieptr,bx           ;put completed pointer into trieptr
  872.                             ;GOT POINTER, NOW START
  873.    mov ax,curptr
  874.    mov prevptr,ax            ;prevptr=curptr
  875.    mov ax,curlen
  876.    mov prevlen,ax            ;prevlen=curlen
  877.    mov ax,trieptr
  878.    mov curptr,ax             ;curptr=trieptr
  879.    mov curlen,0000h
  880.  
  881.  
  882.          .WHILE trieptr != NILPTR
  883.               ctr1 trieptr             ;get character for trieptr (ret in ax)
  884.               mov bx,MAXMATCH
  885.               sub bx,curlen            ;index to end of match array.  Place
  886.               mov match[bx],al         ;character there.  Match array is     
  887.               inc curlen               ;written back to front.        
  888.               parent trieptr           ;get parent of trieptr (ret in ax)
  889.               mov trieptr,ax           ;Move into trieptr.  Walk up the tree
  890.          .ENDW                         ;reading the nodes until we reach the
  891.                                        ;root (NILPTR).
  892.  
  893.          mov ax,MAXMATCH               ;curlen has length of string
  894.          sub ax,curlen                 ;move back in match array to where
  895.          inc ax                        ;string starts.
  896.          mov mstart,ax                 ;move index into mstart.  This is used
  897.          xor bx,bx                     ;by update routine.
  898.          mov bx,ax                     ;index into array
  899.          .WHILE bx <= MAXMATCH         ;max match length is 100 letters
  900.             mov al,match[bx]           ;write the string in the match array
  901.             stosb                      ;to the output buffer.
  902.             inc outcount
  903.             cmp outcount,8000          ;buffer holds 8000.  When full,
  904.             jae chkout                 ;flush buffer.  Do this outside of
  905.           chkout_ret:                  ;loop.  Hate to put jump-arounds
  906.             inc bx                     ;inside loop.  Fall-through is faster
  907.          .ENDW
  908.          cmp all_over,01h
  909.          je endup
  910.  
  911.          call update
  912.  
  913.  .ENDW
  914.  
  915.  chkout:
  916.     call write_file                    ;jumpout from above loop
  917.     jmp chkout_ret
  918.  
  919.  
  920.  endup:
  921.  
  922.  call adjust
  923.  call write_file
  924.  
  925.  writestring fsize,SIZEOF fsize
  926.  mov ax,word ptr comp_size[0]          ;"Init. Size: "
  927.  mov dx,word ptr comp_size[2]
  928.  call convert
  929.  
  930.  writestring crlf,2
  931.  writestring fnl,SIZEOF fnl            ;"Final Size: "
  932.  mov ax,word ptr master_size[0]
  933.  mov dx,word ptr master_size[2]
  934.  call convert      
  935.  
  936.  
  937.  mov ah,57h
  938.  mov al,01h
  939.  mov bx,file_handle2                   ;set date and time
  940.  mov cx,xtime
  941.  mov dx,xdate
  942.  int 21h
  943.  
  944. final:
  945.  
  946.  ret
  947.  decompression endp
  948.  
  949.  
  950. ;----------------------------------------------------------------------
  951. ; INITIALIZE procedure.  Initializes variables and the first 256 nodes
  952. ; of the tree.  The first 256 nodes represent the first level of the
  953. ; tree and they will never be deleted in this particular data structure.
  954. ;----------------------------------------------------------------------
  955.  
  956.    initialize proc near 
  957.  
  958.      mov di,ds
  959.      mov es,di
  960.  
  961.      mov ax,NILPTR
  962.      mov di,offset fielder              ;fill fields with NILPTR 
  963.      mov cx,DICTIONARY*2
  964.      rep stosw
  965.  
  966.      mov ax,NILPTR   
  967.      mov di,seg rsibfield               ;now do far segment
  968.      mov es,di
  969.      mov di,offset fielder_two
  970.      mov cx,DICTIONARY*3
  971.      rep stosw
  972.  
  973.      mov dictsize,00h
  974.      xor bx,bx
  975.      .WHILE dictsize < STATICSIZE       ;fill first 256 bytes of ctr  
  976.         mov ax,dictsize                 ;(character) field with usual    
  977.         mov ctrfield[bx],ax             ;dos characters 00-255.
  978.         inc bx                          ;These will comprise the non-
  979.         inc bx                          ;erasable potion of the dictionary.
  980.         inc dictsize
  981.      .ENDW
  982.  
  983.      mov curptr,NILPTR
  984.      mov curlen,00h
  985.      ret
  986.    initialize endp
  987.  
  988.  
  989. ;-----------------------------------------------------------------------
  990. ; UPDATE procedure.  Updates the tree by adding and deleting appropriate
  991. ; leaves.  Also determines which codewords will be re-used and which
  992. ; leaves will be deleted from the tree.
  993. ; Input:  from main program - trieptr, prevptr, match, etc.
  994. ;------------------------------------------------------------------------             
  995.  
  996.    update proc near
  997.    LOCAL update_flag:BYTE
  998.  
  999.     cmp prevptr,NILPTR
  1000.     je update_out
  1001.  
  1002.        mov update_flag,00h
  1003.        mov mindex,00h
  1004.  
  1005.  
  1006.         .WHILE 1                         ;loop indefinitely
  1007.  
  1008.              mov ax,curlen               ;Don't loop more than current
  1009.              cmp mindex,ax               ;match length.  Leaf nodes are
  1010.              jae update_out              ;added to previous pointer.
  1011.  
  1012.              cmp mindex,MAXINCREMENT     ;MAXINCREMENT is number of pre-
  1013.              jae update_out              ;fixes to add.  Read on...
  1014.  
  1015.              mov ax,prevlen              ;Maximum match length is 100   
  1016.              add ax,mindex               ;in this code.  This routine
  1017.              cmp ax,MAXMATCH             ;adds prefixes one-at-a-time     
  1018.              jae update_out              ;per loop.  Variable mindex is
  1019.                                          ;the loop counter.
  1020.  
  1021.             mov bx,mstart                ;mstart from main program 
  1022.             add bx,mindex                ;index into match array
  1023.             xor ah,ah                    ;make into word
  1024.             mov al,match[bx]             ;get letter from array
  1025.             mov mval,ax                  ;record in mval
  1026.  
  1027.             cmp update_flag,01h          ;skip the child search after first
  1028.             je skip_this                 ;leaf added since the rest will be
  1029.                                          ;new and without children
  1030.  
  1031.             child prevptr,mval           ;see if mval is child of prevptr                
  1032.             mov trieptr,ax               ;record result in trieptr
  1033.                   
  1034.                             ;If no match was found, we will
  1035.                             ;walk down the tree from prevptr and
  1036.                             ;add leaves consisting of the
  1037.                             ;matched prefixes.  The number
  1038.                             ;added is regulated by MAXINCREMENT.   
  1039.  
  1040.             .IF trieptr == NILPTR        ;if not child, then update tree
  1041.              mov update_flag,01h
  1042.              skip_this:
  1043.  
  1044.                   .IF dictsize <= MAXPTR   
  1045.                       mov ax,dictsize    ;get free unused pointer
  1046.                       mov trieptr,ax     ;move pointer into trieptr
  1047.                       inc dictsize       ;increment to next available pointer
  1048.                   .ELSE                  ;No more unused pointers?
  1049.                       mov cx,bigplace    ;Get saved place.  Will loop around
  1050.                     bigtop:              ;from 256 to 8190 progressively and
  1051.                       cmp cx,prevptr     ;re-use pointers.  Don't use prevptr.
  1052.                       je around          ;We'll get the oldest leaf without    
  1053.                       cmp cx,MAXPTR      ;children, delete the leaf,update the
  1054.                       ja bigtop2         ;tree with recycled pointer.Over max?
  1055.                     bigtop1:             ;Then reset to 256 and start over.
  1056.                       mov bx,cx          ;put into bx
  1057.                       shl bx,1           ;word index
  1058.                       cmp lcfield[bx],NILPTR   ;see if pointer has children
  1059.                                          ;NILPTR means no children for this    
  1060.                       je bigtopout       ;node and we can erase & re-use it,
  1061.                     around:              ;else keep trying
  1062.                       inc cx             ;go to next pointer
  1063.                       jmp bigtop         ;repeat 
  1064.                 
  1065.                     bigtop2:             ;jump-out from above loop
  1066.                       mov cx,STATICSIZE  ;reset to 256
  1067.                       jmp bigtop1  
  1068.                     bigtopout:
  1069.  
  1070.                       mov trieptr,cx     ;put leaf node in trieptr
  1071.                       inc cx             ;advance for progressive usage 
  1072.                       mov bigplace,cx    ;Record in bigplace.  We'll start 
  1073.                                          ;here next time we look for a pointer
  1074.                                          ;to re-use.
  1075.                       delete_leaf        ;delete leaf node and,if necessary,
  1076.                                          ;reconnect siblings
  1077.                  .ENDIF
  1078.  
  1079.                 add_leaf                 ;add leaf to tree
  1080.  
  1081.             .ENDIF                                              
  1082.          mov ax,trieptr
  1083.          mov prevptr,ax
  1084.          inc mindex
  1085.         .ENDW
  1086.  
  1087.   update_out:
  1088.    ret
  1089.    update endp  
  1090.  
  1091.  
  1092. ;----------------------------------------------------------------------
  1093. ; READ_FILE procedure.  Reads the file into a buffer for processing
  1094. ; by the program.          
  1095. ; Input: None
  1096. ; Output: eof flag 
  1097. ;-----------------------------------------------------------------------
  1098.  
  1099.    read_file proc near USES dx cx bx ax
  1100.        mov bytes_read,0000h
  1101.        mov ah,3fh
  1102.        mov bx,file_handle
  1103.        mov cx, 8000
  1104.        push ds
  1105.        ASSUME ds:seg inbuffer
  1106.        mov dx,es
  1107.        mov ds,dx
  1108.        mov dx,offset inbuffer
  1109.        int 21h
  1110.        ASSUME ds:@data  
  1111.        pop ds
  1112.        mov bytes_read,ax         ;Number of bytes read will be in ax.  Less
  1113.        .IF ax < 8000             ;than requested bytes indicates eof.
  1114.           mov end_flag,01h
  1115.        .ENDIF
  1116.        mov si,offset inbuffer
  1117.        mov incount,0000h
  1118.        ret
  1119.    read_file endp      
  1120.  
  1121. ;---------------------------------------------------------------------
  1122. ; WRITE_FILE procedure.  Writes the output buffer to disk.
  1123. ; Input: none
  1124. ;---------------------------------------------------------------------     
  1125.  
  1126.  write_file proc near USES ax bx cx dx 
  1127.    mov cx,outcount
  1128.    add word ptr master_size[0],cx       ;keeps track of bytes written
  1129.    adc word ptr master_size[2],0000h    ;to file in variable master_size
  1130.    mov ah,40h                           ;This variable will be referenced    
  1131.    mov bx,file_handle2                  ;later by adjustment routine in
  1132.    push ds                              ;the decoder.  Encoder doesn't
  1133.    mov dx,es                            ;use this variable so no harm done 
  1134.    mov ds,dx                            ;there.
  1135.    ASSUME ds:seg outbuffer
  1136.    mov dx, offset outbuffer
  1137.    int 21h                
  1138.    ASSUME ds:@data
  1139.    pop ds
  1140.    mov di,offset outbuffer
  1141.    mov outcount,0000h
  1142.    ret
  1143.  write_file endp          
  1144.  
  1145. ;--------------------------------------------------------------------------
  1146. ; CMDLINE procedure.  Parses the command line for files.
  1147. ;-------------------------------------------------------------------------
  1148.  
  1149.  cmdline proc near C USES ax bx es si,arg1:WORD,arg2:WORD,arg3:WORD       
  1150.  LOCAL go_around_flag:BYTE  
  1151.  
  1152.         mov go_around_flag,00h
  1153.  
  1154.         mov ah,51h             ;get psp
  1155.         int 21h
  1156.         mov es,bx              ;move psp seg into es
  1157.         xor cx,cx
  1158.         xor bx,bx
  1159.         .IF es:[80h]==cl       ;check for command line arguments
  1160.            ret                 ;value at 80h of the psp is number of bytes
  1161.         .ENDIF                 ;in command line argument.
  1162.  
  1163.         mov bx,82h             ;find start of command line
  1164.         mov si,arg1            ;buffer for command line
  1165.         @@:
  1166.           mov al,es:[bx]       ;get letter from dta (command line)
  1167.           .IF al==13 || al==00
  1168.               ret          
  1169.           .ENDIF
  1170.           .IF al < 33 && go_around_flag==0 
  1171.              mov si,arg2                  ;buffer for output file  
  1172.              inc  go_around_flag       
  1173.              mov filelen,cx
  1174.              xor cx,cx
  1175.              jmp skp  
  1176.           .ENDIF     
  1177.           .IF al < 33 && go_around_flag==1
  1178.              mov si,arg3                  ;buffer for parameter line  
  1179.              mov filelen2,cx
  1180.              mov paraflag,01h
  1181.              inc go_around_flag
  1182.           .ENDIF     
  1183.           mov [si],al
  1184.           inc si
  1185.           skp:
  1186.           inc bx
  1187.           inc cx                   ;byte count of file name
  1188.           jmp @B
  1189.   cmdline endp
  1190.  
  1191. ;--------------------------------------------------------------------------
  1192. ;                                                                         |
  1193. ;                ADJUSTMENT FOR DECOMPRESSION FINAL OUTPUT                |
  1194. ;                                                                         |
  1195. ;--------------------------------------------------------------------------
  1196.  
  1197.  adjust proc near PRIVATE
  1198.        ;NOTES:
  1199.        ;This decompression routine may add on an extra byte or two
  1200.        ;on the end.  This is usually the letter coded as 00 since the 
  1201.        ;encoder has to flush the final byte to the file, whether it is 
  1202.        ;full or not.  These extra bytes are removed by this routine.  The
  1203.        ;decoder never generates fewer bytes than what the final size
  1204.        ;of the file should be.  The encoder writes the original file
  1205.        ;size to the file at bytes 5-8.  The decoder keeps track of the
  1206.        ;number of bytes generated and compares it with this figure.
  1207.        ;This routine then subtacts the extra byte(s) off the end.  Don't
  1208.        ;worry, they're never needed and are really extra bytes. This
  1209.        ;is one way to do things and it works without fail.
  1210.  
  1211.        mov dx,word ptr [master_size][2]  ;load high word of byte count
  1212.        mov ax,word ptr [master_size][0]  ;load low word of byte count
  1213.        add ax,[outcount]                 ;add the last count
  1214.        adc dx,0000h                      ;add the carry flag to high word
  1215.  
  1216.        cmp dx,word ptr [init_size][2]  ;see if high word of byte count=
  1217.        je nxt                          ;high word of header info.
  1218.        cmp dx,word ptr [init_size][2]  ;see if high word of byte count is
  1219.        jb lving                        ;lower than high word of header info
  1220.        sub ax,word ptr [init_size][0]  ;If so , leave without adjusting
  1221.        sbb dx,word ptr [init_size][2]  ;otherwise, if byte count is greater
  1222.                                        ;than header info, subtact the two
  1223.        sub [outcount],ax               ;and take the difference off the end
  1224.        jmp short lving                 ;so that the file size will be correct
  1225.      nxt:
  1226.        cmp ax,word ptr [init_size]     ;compare low words
  1227.        jbe lving                       ;if expanded file is smaller, leave
  1228.        sub ax,word ptr [init_size]     ;without adjusting, otherwise, subtract
  1229.        sub [outcount],ax               ;the two and take the difference off
  1230.                                        ;the end again
  1231.    lving:
  1232.        ret
  1233.   adjust endp
  1234.  
  1235.  
  1236. ;---------------------------------------------------------------------------
  1237. ;                                                                          |
  1238. ;                        OPENS SOURCE FILE                                 |
  1239. ; Input: Nothing                                                           |
  1240. ; Output: Carry flag set if error                                          |
  1241. ;---------------------------------------------------------------------------
  1242.  
  1243.  
  1244.  open_source_file proc near
  1245.  
  1246.      mov ah,3dh
  1247.      mov al,00h
  1248.      mov dx,offset filename        ;open input file
  1249.      int 21h
  1250.      .IF CARRY?                    ;check to see if carry flag is set
  1251.        print error
  1252.        stc         
  1253.        jmp @F
  1254.     .ENDIF     
  1255.      mov file_handle,ax
  1256.    @@:
  1257.    ret
  1258.  open_source_file endp    
  1259.  
  1260. ;---------------------------------------------------------------------------
  1261. ;                                                                          |
  1262. ;                        OPENS OUTPUT FILE                                 |
  1263. ; Input: Nothing                                                           |
  1264. ; Output: Carry flag set if error                                          |
  1265. ;---------------------------------------------------------------------------
  1266.  
  1267.  open_second_file proc near
  1268.        mov ah,3ch
  1269.        mov cx,00h                   ;create/truncate output file
  1270.        mov dx,offset tempfile
  1271.        int 21h
  1272.        .IF CARRY?                   ;check to see if carry flag is set
  1273.          print error
  1274.          stc
  1275.          jmp @F
  1276.        .ENDIF     
  1277.       mov file_handle2,ax   
  1278.       @@:
  1279.       ret
  1280.  open_second_file endp 
  1281.  
  1282.  
  1283. ;--------------------------------------------------------------------------
  1284. ; CAPS procedure                                                          |
  1285. ; Capitalizes any string                                                  |
  1286. ; Input: near pointer to string,length of buffer                          |
  1287. ;--------------------------------------------------------------------------
  1288.  
  1289.    caps  proc near C PUBLIC USES si cx ax,arg1:WORD,arg2:WORD
  1290.             mov si,arg1
  1291.             xor cx,cx
  1292.             mov cx,arg2
  1293.             cap_loop:
  1294.             mov al,[si]
  1295.                  cmp al,61h             ;below a?
  1296.                  jb capon
  1297.                  cmp al,7ah             ;above z?
  1298.                  ja capon
  1299.                  AND al,0dfh            ;clear the 6th bit
  1300.                  mov [si],al
  1301.                capon:
  1302.                  inc si
  1303.                  loop cap_loop
  1304.         ret
  1305.         caps endp
  1306.  
  1307.  
  1308. ;--------------------------------------------------------------------------
  1309. ; CONVERT procedure                                                       |
  1310. ; Converts any Hex number to displayable decimal string.                  |
  1311. ; Input: Doubleword in dx:ax                                              |
  1312. ; Output: To screen automatically (from variable: ascii_string)           |
  1313. ;--------------------------------------------------------------------------
  1314.  
  1315.  
  1316. convert       proc near    
  1317.  
  1318.               mov di,ds
  1319.               mov es,di                ;load ds into es
  1320.  
  1321.               mov si,10                ;load base 10 into si
  1322.               xor bx,bx                ;zero bx
  1323.               xor cx,cx                ;zero cx
  1324.               mov bx,ax                ;move low word into bx
  1325.               mov cx,dx                ;load high word into cx
  1326.               mov dx,-1                ;set end-of-string flag
  1327.               push dx                  ;save it as last string byte
  1328. hex_loop_1:
  1329.               xchg ax,cx               ;load ax with high word
  1330.               xor dx,dx                ;zero dx
  1331.               div si                   ;divde by 10, leave rem. in dx
  1332.               xchg cx,ax               ;save high word back in cx
  1333.               xchg ax,bx               ;load ax with low word
  1334.               div si                   ;divide by ten
  1335.               xchg bx,ax               ;save low word back in bx
  1336.               add dl,30h               ;convert remainder to ascii
  1337.               push dx                  ;save as digit
  1338.               or bx,bx                 ;see if low word is zero
  1339.               jne hex_loop_1
  1340.               or cx,cx                 ;see if high word is zero
  1341.               jne hex_loop_1
  1342.  
  1343.              xor cx,cx
  1344.              xor dx,dx
  1345.              lea di, ascii_string      ;point di to string
  1346.  
  1347. hex_loop_2:
  1348.              pop ax                    ;pop first digit
  1349.              cmp ax,-1                 ;see if end-of-string
  1350.              je write_it
  1351.              stosb                     ;write it to string
  1352.              inc cx                    ;increase digit counter
  1353.              jmp hex_loop_2
  1354.  
  1355. write_it:
  1356.               cmp cx,1                 ;see if string is 1 digit long
  1357.               jne write                ;if not, write string
  1358.               lea di, ascii_string     ;point di to string
  1359.               mov al,[di]              ;move only digit to al
  1360.               mov ah,"0"               ;move "0" into ah
  1361.               mov [di+1],al            ;write "0" as first letter
  1362.               mov [di],ah              ;write digit as second
  1363.               mov cx,2                 ;adjust counter to two
  1364. write:
  1365.               mov [count],cx
  1366.               writestring ascii_string,count
  1367.  
  1368.               ret 
  1369. convert       endp
  1370.  
  1371. END
  1372.