home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / HPACK78S.ZIP / lza / lza.c next >
C/C++ Source or Header  |  1992-11-30  |  22KB  |  761 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                                 LZA Main Compressor Code                        *
  7. *                              LZA.C  Updated 08/04/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1989 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. /* "That is not dead which can eternal run
  19.     And over strange eons even HPACK may finish compressing"
  20.  
  21.         - Apologies to H.P.Lovecraft */
  22.  
  23. #include <ctype.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #ifdef __MAC__
  27.   #include "defs.h"
  28.   #include "choice.h"
  29.   #include "error.h"
  30.   #include "flags.h"
  31.   #include "frontend.h"
  32.   #include "hpacklib.h"
  33.   #include "crc16.h"
  34.   #include "crypt.h"
  35.   #include "fastio.h"
  36.   #include "hpackio.h"
  37.   #include "model.h"
  38.   #include "model2.h"
  39.   #include "model3.h"
  40.   #include "model4.h"
  41. #else
  42.   #include "defs.h"
  43.   #include "choice.h"
  44.   #include "error.h"
  45.   #include "flags.h"
  46.   #include "frontend.h"
  47.   #include "hpacklib.h"
  48.   #include "crc/crc16.h"
  49.   #include "crypt/crypt.h"
  50.   #include "io/fastio.h"
  51.   #include "io/hpackio.h"
  52.   #include "lza/model.h"
  53.   #include "lza/model2.h"
  54.   #include "lza/model3.h"
  55.   #include "lza/model4.h"
  56. #endif /* __MAC__ */
  57.  
  58. /* Prototypes for functions in GUI.C */
  59.  
  60. void updateProgressReport( void );
  61.  
  62. /* Prototypes for the arithmetic coder */
  63.  
  64. void startEncode( void );
  65. void endEncode( void );
  66. void encode( const int cumFreq0, const int cumFreqLower, const int cumFreqUpper );
  67.  
  68. void startDecode( void );
  69. int decodeOrder1( void );
  70. int decodeOrder0( const int *cumFreq );
  71.  
  72. /* Prototypes for the models for various encodings */
  73.  
  74. void startLiteralModel( void );
  75.  
  76. /* Prototypes for the order-1 arithcoder */
  77.  
  78. void initModels( void );
  79. void endModels( void );
  80. void haveAGoAt( const int value );
  81.  
  82. #ifdef __MAC__
  83.  
  84. /* Prototypes for Mac-specific routines */
  85.  
  86. void yieldTimeSlice( void );
  87.  
  88. #endif /* __MAC__ */
  89.  
  90. /* LZSS Coding Parameters */
  91.  
  92. #define MAX_POSITION        32768    /* Window size - must be a power of 2 */
  93. #define MAX_LENGTH            64        /* Max. match length - must be pwr.of 2 */
  94.  
  95. #define STR_BUF_SIZE        MAX_POSITION    /* Size of string buffer */
  96. #define STR_BUF_MASK        ( STR_BUF_SIZE - 1 )    /* For fast "% STR_BUF_SIZE" */
  97. #define LOOKAHEAD_BUF_SIZE    MAX_LENGTH        /* Size of look-ahead buffer */
  98. #define LOOKAHEAD_BUF_MASK    ( LOOKAHEAD_BUF_SIZE - 1 )    /* For fast "% LOOKAHEAD_BUF_SIZE" */
  99. #define MATCH_THRESHOLD        5        /* When changing this value, remember to
  100.                                        change NO_SYMBOLS in model.h, and the
  101.                                        hashTable size in model.c */
  102. #define LZSS_ESC            256        /* Escape value for LZSS code */
  103.  
  104. #define LIST_SIZE            8192    /* The number of hashed list headers */
  105. #define LIST_END            -1        /* Marker for end of list */
  106.  
  107. static BYTE *textBuffer, *lookAheadBuffer;    /* The string and lookahead buffers */
  108. static int *linkBuffer, *tailList;    /* The list1 data structure */
  109. int *headList;                        /* Must be externally visible for findMatch() */
  110.  
  111. /* The output byte count (used by PACK.C, UNPACK.C) */
  112.  
  113. LONG outByteCount;
  114.  
  115. /* The count of the number of bytes processed for the variable-adaptivity
  116.    count scaling */
  117.  
  118. unsigned int modelByteCount;
  119.  
  120. /* The byte count for which we bother updating modelByteCount.  Some
  121.    compilers can't handle 'U' so we declare it as 'L' instead.  If possible
  122.    it should be declared as 'U' for 16-bit systems */
  123.  
  124. #ifdef IRIX
  125.   #define SCALE_RANGE        40000L
  126. #else
  127.   #define SCALE_RANGE        40000U
  128. #endif /* IRIX */
  129.  
  130. /****************************************************************************
  131. *                                                                            *
  132. *                                Encoding Routines                            *
  133. *                                                                            *
  134. ****************************************************************************/
  135.  
  136. WORD isText;    /* Actually a BOOLEAN but WORD makes it faster to handle */
  137. int windowSize;    /* Whether we're using an 8K, 16K or 32K window */
  138.  
  139. /* Set up the models for the various encoders */
  140.  
  141. void startModels( void )
  142.     {
  143.     /* Set up the models for the encoder */
  144.     h291();
  145.     startHighPosModel();
  146.     startLowPosModel();
  147.     startLengthModel();
  148.  
  149.     /* Reset the byte count for the count scaling */
  150.     modelByteCount = 0;
  151.     }
  152.  
  153. /* Encode a literal */
  154.  
  155. #define encodeLiteral(value)    haveAGoAt( value )
  156.  
  157. /* Encode a high position */
  158.  
  159. void encodeHighPos( const int theCode )
  160.     {
  161.     const int symbol = highPosToIndex[ theCode ];    /* Translate code to an index */
  162.  
  163.     encode( highPosCumFreq[ 0 ], highPosCumFreq[ symbol - 1 ], highPosCumFreq[ symbol ] );
  164.  
  165.     /* Now update the model */
  166.     updateHighPosModel( symbol );
  167.     }
  168.  
  169. /* Encode a low position */
  170.  
  171. void encodeLowPos( const int theCode )
  172.     {
  173.     const int symbol = lowPosToIndex[ theCode ];    /* Translate code to an index */
  174.  
  175.     encode( lowPosCumFreq[ 0 ], lowPosCumFreq[ symbol - 1 ], lowPosCumFreq[ symbol ] );
  176.  
  177.     /* Now update the model */
  178.     if( !isText )
  179.         updateLowPosModel( symbol );
  180.     }
  181.  
  182. /* Encode a length */
  183.  
  184. void encodeLength( const int theCode )
  185.     {
  186.     const int symbol = lengthToIndex[ theCode ];    /* Translate code to an index */
  187.  
  188.     encode( lengthCumFreq[ 0 ], lengthCumFreq[ symbol - 1 ], lengthCumFreq[ symbol ] );
  189.  
  190.     /* Now update the model */
  191.     updateLengthModel( symbol );
  192.     }
  193.  
  194. /* Decode a literal */
  195.  
  196. #define decodeLiteral()    decodeOrder1()
  197.  
  198. /* Decode a high position */
  199.  
  200. int decodeHighPos( void )
  201.     {
  202.     const int symbol = decodeOrder0( highPosCumFreq );
  203.     const int retVal = indexToHighPos[ symbol ];
  204.  
  205.     /* Update the model */
  206.     updateHighPosModel( symbol );
  207.  
  208.     /* Return translated value */
  209.     return( retVal );
  210.     }
  211.  
  212. /* Decode a low position */
  213.  
  214. int decodeLowPos( void )
  215.     {
  216.     const int symbol = decodeOrder0( lowPosCumFreq );
  217.     const int retVal = indexToLowPos[ symbol ];
  218.  
  219.     /* Update the model */
  220.     if( !isText )
  221.         updateLowPosModel( symbol );
  222.  
  223.     /* Return translated value */
  224.     return( retVal );
  225.     }
  226.  
  227. /* Decode a length */
  228.  
  229. int decodeLength( void )
  230.     {
  231.     const int symbol = decodeOrder0( lengthCumFreq );
  232.     const int retVal = indexToLength[ symbol ];
  233.  
  234.     /* Update the model */
  235.     updateLengthModel( symbol );
  236.  
  237.     /* Return translated value */
  238.     return( retVal );
  239.     }
  240.  
  241. /****************************************************************************
  242. *                                                                            *
  243. *                    LZSS Compression/Decompression Routines                    *
  244. *                                                                            *
  245. ****************************************************************************/
  246.  
  247. /* Various variables used by the assembly language findMatch() routine */
  248.  
  249. int listIndex, lookAheadIndex, matchPos, lastMatchLen, currBufPos;
  250. long noBytes;
  251.  
  252. /* Set up buffers for LZSS compression and order-1 arithcoder */
  253.  
  254. void initPack( const BOOLEAN initAllBuffers )
  255.     {
  256.     if( ( textBuffer = ( BYTE * ) hmalloc( STR_BUF_SIZE + MAX_LENGTH ) ) == NULL )
  257.         error( OUT_OF_MEMORY );
  258.  
  259.     /* Only allocate the following buffers if we need them - saves 64K */
  260.     if( initAllBuffers )
  261.         {
  262.         if( ( lookAheadBuffer = ( BYTE * ) hmalloc( LOOKAHEAD_BUF_SIZE * 2 ) ) == NULL || \
  263.             ( linkBuffer = ( int * ) hmalloc( ( STR_BUF_SIZE * sizeof( int ) ) ) ) == NULL || \
  264.             ( headList = ( int * ) hmalloc( LIST_SIZE * sizeof( int ) ) ) == NULL || \
  265.             ( tailList = ( int * ) hmalloc( LIST_SIZE * sizeof( int ) ) ) == NULL )
  266.             error( OUT_OF_MEMORY );
  267.         }
  268.  
  269.     initModels();
  270.     }
  271.  
  272. /* Free LZSS buffers and order-1 arithcoder data */
  273.  
  274. void endPack( void )
  275.     {
  276.     sfree( textBuffer, STR_BUF_SIZE + MAX_LENGTH );
  277.     if( choice != EXTRACT && choice != TEST && choice != DISPLAY )
  278.         {
  279.         sfree( lookAheadBuffer, LOOKAHEAD_BUF_SIZE * 2 );
  280.         sfree( linkBuffer, STR_BUF_SIZE * sizeof( int ) );
  281.         sfree( headList, LIST_SIZE * sizeof( int ) );
  282.         sfree( tailList, LIST_SIZE * sizeof( int ) );
  283.         }
  284.     endModels();
  285.     }
  286.  
  287. /* Perform the compression */
  288.  
  289. #ifdef __TSC__
  290.   #ifdef inline        /* Undo nulling-out of inline for TopSpeed C */
  291.     #undef inline
  292.   #endif
  293.  
  294.   #pragma save
  295.   #pragma call( inline=>on, reg_param => (si, dx, di, es, cx), \
  296.                 reg_return => (cx), reg_saved => (bx, dx, ds, st1, st2) )
  297.   static int doloop( BYTE *srcPtr, BYTE *destPtr, int Count ) =
  298.         {
  299.         0x1E,                /* push ds   */
  300.         0x8E, 0xDA,            /* mov ds,dx */
  301.         0xF3, 0xA6,            /* rep ; cmpsb */
  302.         0x83, 0xF9, 0x00,    /* cmp   cx,0
  303.         0x75, 0x09,            /* jne   $0 */
  304.         0x4E,                /* dec   si */
  305.         0x4F,                /* dec   di */
  306.         0x26, 0x8A, 0x05,    /* mov   ax,es:[di] */
  307.         0x3A, 0x04,            /* cmp   ax,[si] */
  308.         0x74, 0x01,         /* je    $1 */
  309.         0x41,                /* $0: inc   cx */
  310.         0x1F,                /* $1: pop ds */
  311.         0xC3                /* ret */
  312.         };
  313.   #pragma restore
  314. #endif
  315.  
  316. LONG pack( BOOLEAN *localIsText, long localNoBytes )
  317.     {
  318.     int ch, count, currMatchLen;
  319.     long printCount;
  320.     static BOOLEAN textBufferFull;
  321.     static unsigned int textBufferCount;
  322.     BOOLEAN flipFlop = FALSE;
  323.     int offset, endByte = 0;
  324.     int tailIndex, headIndex;
  325.     BYTE *srcPtr, *destPtr;
  326. #ifdef __TSC__
  327.     int CountDown;
  328. #endif /* __TSC__ */
  329. #ifdef LATTICE
  330.     /* Yet another Lattice C bug - nothing in the world will convince it that
  331.        a value >32767 is unsigned when used in an address expression so we
  332.        just set a constant variable to this value and use that instead of the
  333.        literal constant */
  334.     const int latticeFix = STR_BUF_SIZE;
  335. #endif /* LATTICE */
  336.  
  337.     /* Copy various local parameters to global parameters */
  338.     noBytes = localNoBytes;
  339.  
  340.     /* Evaluate size of input file */
  341.     noBytes += CHECKSUM_LEN;
  342. #ifdef LATTICE
  343.     /* Wanna see a compiler really lose it?  Then replace the following code
  344.        with the #else stuff.  For the following code, Lattice C 5.10 produces:
  345.  
  346.        move.l <offset>(a4), d1
  347.        subi.l #00000800, d1
  348.  
  349.        With everything on one line, you get:
  350.  
  351.        <F-line trap> */
  352.     printCount = noBytes;
  353.     printCount -= 2048L;            /* Make sure we don't print a spurious dit */
  354. #else
  355.     printCount = noBytes - 2048L;    /* Make sure we don't print a spurious dit */
  356. #endif /* LATTICE */
  357.     if( flags & BLOCK_MODE )
  358.         /* Always use largest window in block mode */
  359.         windowSize = 0;
  360.     else
  361.         /* Select window size depending on data file size */
  362.         windowSize = ( noBytes > 16384 ) ? 0 : ( noBytes > 8192 ) ? 1 : 2;
  363.  
  364.     /* Initialise the I/O system */
  365.     resetFastIn();
  366.  
  367.     /* Initialise the arithmetic encoder and models */
  368.     if( firstFile || !( flags & BLOCK_MODE ) )
  369.         {
  370.         textBufferFull = FALSE;
  371.         textBufferCount = 0;
  372.         startModels();
  373.         }
  374.     else
  375.         /* Always reset the lowPos model in block mode in case we go from
  376.            text <-> binary mode */
  377.         startLowPosModel();
  378.     startEncode();
  379.     outByteCount = 0L;
  380.  
  381.     /* See if the file is a text file or binary and use the appropriate
  382.        model.  If at least 95% of the file's chars are in the following
  383.        category, we assume it's text */
  384.     for( count = 0, currMatchLen = 0; count < 50; count++ )
  385.         if( ( ( ( ( ch = _inBuffer[ count ] ) >= 0x20 ) && ( ch <= 0x7E ) ) ) || \
  386.             ch == '\r' || ch == '\n' || ch == '\t' )
  387.             currMatchLen++;
  388.     *localIsText = isText = ( currMatchLen > 47 ) ? TRUE : FALSE;
  389.  
  390.     /* Initialize various data structures if necessary.  The memset() of the
  391.        linkBuffer is done in two halves for use on 16-bit systems */
  392.     if( firstFile || !( flags & BLOCK_MODE ) )
  393.         {
  394.         memset( headList, LIST_END, LIST_SIZE * sizeof( int ) );
  395.         memset( tailList, LIST_END, LIST_SIZE * sizeof( int ) );
  396.         memset( linkBuffer, LIST_END, STR_BUF_SIZE );
  397.         memset( ( char * ) linkBuffer + STR_BUF_SIZE, LIST_END, STR_BUF_SIZE );
  398.         currBufPos = 0;
  399.         }
  400.  
  401.     /* Now fill the lookahead buffer and sigma buffer */
  402.     for( lookAheadIndex = 0; \
  403.          lookAheadIndex < LOOKAHEAD_BUF_SIZE && ( ch = fgetByte() ) != FEOF; \
  404.          lookAheadBuffer[ lookAheadIndex ] = \
  405.          lookAheadBuffer[ lookAheadIndex + LOOKAHEAD_BUF_SIZE ] = ch,
  406.          lookAheadIndex++ );
  407.  
  408.     /* If the file is < LOOKAHEAD_BUF_SIZE bytes long we append the checksum
  409.        value now */
  410.     if( lookAheadIndex < LOOKAHEAD_BUF_SIZE )
  411.         for( count = 0; count < CHECKSUM_LEN && lookAheadIndex < LOOKAHEAD_BUF_SIZE; \
  412.              count++, lookAheadIndex++ )
  413.                 lookAheadBuffer[ lookAheadIndex ] = \
  414.                 lookAheadBuffer[ lookAheadIndex + LOOKAHEAD_BUF_SIZE ] = \
  415.                             ( isText ) ? CHECKSUM_TEXT[ endByte++ ] : \
  416.                                          CHECKSUM_BIN[ endByte++ ];
  417.     lookAheadIndex = 0;
  418.  
  419.     do
  420.         {
  421.         /* Find the longest match of the lookahead buffer in the text buffer */
  422.         lastMatchLen = 1;
  423.         listIndex = lookAheadBuffer[ lookAheadIndex ] << 5;
  424.         ch = lookAheadBuffer[ ( lookAheadIndex + 1 ) & LOOKAHEAD_BUF_MASK ];
  425.         ch ^= lookAheadBuffer[ ( lookAheadIndex + 2 ) & LOOKAHEAD_BUF_MASK ];
  426.         listIndex |= ch & 0x1F;
  427.         headIndex = headList[ listIndex ];
  428.         while( headIndex != LIST_END )
  429.             {
  430.             /* Match ( position + 1 ) (since we already know there is a match
  431.                at ( position )) with the text in the lookahead buffer */
  432.             currMatchLen = 1;
  433.  
  434.             /* Make sure we don't try and match past the current position in
  435.                the buffer.  Use an offset of -1 since we've already matched
  436.                the first char */
  437.             count = currBufPos - headIndex - 1;
  438.             if( count < 0 )
  439.                 count += STR_BUF_SIZE;
  440.             if( count >= LOOKAHEAD_BUF_SIZE )
  441.                 count = LOOKAHEAD_BUF_SIZE - 1;
  442.  
  443.             /* Perform the actual string match */
  444.             srcPtr = textBuffer + headIndex + 1;
  445.             destPtr = lookAheadBuffer + ( ( lookAheadIndex + 1 ) & LOOKAHEAD_BUF_MASK );
  446. #ifdef __TSC__
  447.             if( count )
  448.                 {
  449.                 CountDown = count;
  450.                 count = doloop( srcPtr, destPtr, count );
  451.                 currMatchLen += CountDown - count;
  452.                 }
  453. #else
  454.             while( *srcPtr++ == *destPtr++ && count-- )
  455.                 currMatchLen++;
  456. #endif /* __TSC__ */
  457.  
  458.             /* See if the new match is longer than an older match */
  459.             if( currMatchLen >= lastMatchLen )
  460.                 {
  461.                 lastMatchLen = currMatchLen;
  462.                 matchPos = headIndex;
  463.                 }
  464.  
  465.             /* Move to next match in list */
  466.             headIndex = linkBuffer[ headIndex ];
  467.             }
  468.  
  469.         /* Special case:  At the very end of the file we may have a match
  470.            longer than the number of chars left.  In this case we decrease
  471.            the match length, and compress as single chars if necessary */
  472.         if( noBytes < lastMatchLen )
  473.             lastMatchLen = ( int ) noBytes;
  474.  
  475.         /* See if we have a match long enough to make it worthwhile ouputting
  476.            it as an LZSS code */
  477.         if( lastMatchLen <= MATCH_THRESHOLD )
  478.             {
  479.             /* Output literal character */
  480.             lastMatchLen = 1;
  481.             encodeLiteral( lookAheadBuffer[ lookAheadIndex ] );
  482.             }
  483.         else
  484.             {
  485.             /* Output ( length, position ) pair */
  486.             encodeLiteral( LZSS_ESC );    /* Encode escape for LZSS code */
  487.             encodeLength( lastMatchLen - MATCH_THRESHOLD );
  488.             if( isText )
  489.                 /* Take position from end of match not start */
  490.                 matchPos += lastMatchLen;
  491.             offset = ( currBufPos - matchPos ) & STR_BUF_MASK;
  492.             encodeHighPos( offset >> 7 );
  493.             encodeLowPos( offset & 0x7F );
  494.             }
  495.  
  496.         /* Now move the matched string from the lookahead buffer to the text
  497.            buffer, updating the head and tail lists as we go */
  498.         for( count = 0; count < lastMatchLen; count++ )
  499.             {
  500.             /* See if we need to start deleting chars from the text buffer */
  501.             if( textBufferFull )
  502.                 {
  503.                 /* Unlink the old char at currBufPos from lists */
  504.                 listIndex = textBuffer[ currBufPos ] << 5;
  505.                 ch = textBuffer[ ( currBufPos + 1 ) & STR_BUF_MASK ];
  506.                 ch ^= textBuffer[ ( currBufPos + 2 ) & STR_BUF_MASK ];
  507.                 listIndex |= ch & 0x1F;
  508.                 tailIndex = tailList[ listIndex ];
  509.                 if( tailIndex == currBufPos )
  510.                     /* Last char deleted */
  511.                     headList[ listIndex ] = tailList[ listIndex ] = LIST_END;
  512.                 else
  513.                     /* Point to next char in list */
  514.                     headList[ listIndex ] = linkBuffer[ currBufPos ];
  515.                 }
  516.             else
  517.                 {
  518.                 textBufferCount++;
  519.  
  520.                 /* Check whether the buffer is now full */
  521.                 if( textBufferCount >= STR_BUF_SIZE )
  522.                     textBufferFull = TRUE;
  523.                 }
  524.  
  525.             /* Move a char from the lookahead buffer into the string buffer
  526.                and read in a new char to replace it */
  527.             textBuffer[ currBufPos ] = ch = lookAheadBuffer[ lookAheadIndex ];
  528.             if( currBufPos < MAX_LENGTH )
  529.                 /* Add to sigma buffer as well */
  530. #ifdef LATTICE
  531.                 textBuffer[ latticeFix + currBufPos ] = ch;
  532. #else
  533.                 textBuffer[ STR_BUF_SIZE + currBufPos ] = ch;
  534. #endif /* LATTICE */
  535.             if( noBytes <= CHECKSUM_LEN + LOOKAHEAD_BUF_SIZE )
  536.                 lookAheadBuffer[ lookAheadIndex ] = \
  537.                 lookAheadBuffer[ lookAheadIndex + LOOKAHEAD_BUF_SIZE ] = \
  538.                             ( isText ) ? CHECKSUM_TEXT[ endByte++ ] : \
  539.                                          CHECKSUM_BIN[ endByte++ ];
  540.             else
  541.                 lookAheadBuffer[ lookAheadIndex ] = \
  542.                 lookAheadBuffer[ lookAheadIndex + LOOKAHEAD_BUF_SIZE ] = \
  543.                                                     fgetByte();
  544.             lookAheadIndex = ++lookAheadIndex & LOOKAHEAD_BUF_MASK;
  545.  
  546.             /* Add it to the link buffer/lists at currBufPos */
  547.             listIndex = ch << 5;
  548.             ch = lookAheadBuffer[ lookAheadIndex ]; /* lAI has been inc'd in the meantime */
  549.             ch ^= lookAheadBuffer[ ( lookAheadIndex + 1 ) & LOOKAHEAD_BUF_MASK ];
  550.             listIndex |= ch & 0x1F;
  551.             tailIndex = tailList[ listIndex ];
  552.             if( tailIndex == LIST_END )
  553.                 /* No chars in list */
  554.                 headList[ listIndex ] = currBufPos;
  555.             else
  556.                 /* Add to end of list */
  557.                 linkBuffer[ tailIndex ] = currBufPos;
  558.             tailList[ listIndex ] = currBufPos;
  559.             linkBuffer[ currBufPos ] = LIST_END;
  560.  
  561.             /* Increment currBufPos */
  562.             currBufPos = ++currBufPos & STR_BUF_MASK;
  563.  
  564.             /* Decrement bytes seen */
  565.             noBytes--;
  566.             if( modelByteCount < SCALE_RANGE )
  567.                 modelByteCount++;
  568.             }
  569.  
  570.         /* Output a dit for every 2K processed */
  571.         if( noBytes < printCount )
  572.             {
  573. #ifdef GUI
  574.             updateProgressReport();
  575. #else
  576.             if( flipFlop )
  577.                 {
  578.                 hputchars( '\b' );
  579.                 hputchars( 'O' );
  580.                 }
  581.             else
  582.                 hputchars( 'o' );
  583.             hflush( stdout );
  584.             flipFlop = !flipFlop;
  585.             printCount -= 2048L;
  586. #endif /* GUI */
  587. #ifdef __MAC__
  588.             yieldTimeSlice();
  589. #endif /* __MAC__ */
  590.             }
  591.         }
  592.     while( noBytes > 0 );
  593.  
  594.     /* Clean up any loose ends */
  595.     endEncode();
  596. #ifndef GUI
  597.     if( flipFlop )
  598.         {
  599.         hputchars( '\b' );
  600.         hputchars( 'O' );
  601.         hflush( stdout );
  602.         }
  603. #endif /* GUI */
  604.  
  605.     return( outByteCount );
  606.     }
  607.  
  608. /* Perform the decompression */
  609.  
  610. LONG dataLen;    /* Used in UNPACK.C */
  611.  
  612. BOOLEAN unpack( const BOOLEAN localIsText, const long dataSize, const long localNoBytes )
  613.     {
  614.     static int bufIndex;    /* Must be static for block mode */
  615.     int position, length, ch;
  616.     int endByte = 0, printCount = 0, checkBytes = 0;
  617.     BYTE checkSum[ CHECKSUM_LEN ];
  618.     BOOLEAN flipFlop = FALSE;
  619.  
  620.     /* Copy the local parameters to their global equivalents */
  621.     noBytes = localNoBytes;
  622.  
  623.     /* Initialise the I/O system */
  624.     dataLen = dataSize;
  625.     resetFastOut();
  626.     noBytes += CHECKSUM_LEN;    /* Non-test version stores only orig.file size */
  627.  
  628.     /* Determine which model was used for compression */
  629.     isText = localIsText;
  630.     if( flags & BLOCK_MODE )
  631.         /* Always use largest window in block mode */
  632.         windowSize = 0;
  633.     else
  634.         /* Select window size depending on data file size */
  635.         windowSize = ( noBytes > 16384 ) ? 0 : ( noBytes > 8192 ) ? 1 : 2;
  636.  
  637.     /* Initialise various data structures */
  638.     if( firstFile || !( flags & BLOCK_MODE ) )
  639.         startModels();
  640.     else
  641.         /* Always reset the lowPos model in block mode in case we go from
  642.            text <-> binary mode */
  643.         startLowPosModel();
  644.     startDecode();
  645.     memset( checkSum, 0xFF, CHECKSUM_LEN );    /* Clear checksum */
  646.  
  647.     if( firstFile || !( flags & BLOCK_MODE ) )
  648.         bufIndex = 0;
  649.     while( noBytes > 0 )
  650.         {
  651.         /* Decode a literal char or length byte */
  652.         if( ( ch = decodeLiteral() ) != LZSS_ESC )
  653.             {
  654.             /* Output byte and add to circular buffer */
  655.             if( noBytes <= CHECKSUM_LEN )
  656.                 {
  657.                 /* If the data is corrupted we may end up decoding a random
  658.                    string, so we insert a sanity check here */
  659.                 if( endByte >= CHECKSUM_LEN )
  660.                     {
  661.                     flushBuffer();        /* Flush any remaining data */
  662.                     return( FALSE );
  663.                     }
  664.  
  665.                 checkSum[ endByte++ ] = ch;
  666.                 }
  667.             else
  668.                 fputByte( ch );
  669.  
  670.             textBuffer[ bufIndex++ ] = ch;
  671.             bufIndex &= STR_BUF_MASK;
  672.             noBytes--;
  673.             printCount++;
  674.             if( modelByteCount < SCALE_RANGE )
  675.                 modelByteCount++;
  676.             }
  677.         else
  678.             {
  679.             /* Decode ( length, position ) pair */
  680.             length = decodeLength() + MATCH_THRESHOLD;
  681.             position = decodeHighPos() << 7;
  682.             position |= decodeLowPos();
  683.             position = bufIndex - position;
  684.             if( isText )
  685.                 position -= length;
  686.             position &= STR_BUF_MASK;
  687.  
  688.             /* Adjust byte count and printCount for string */
  689.             noBytes -= length;
  690.             if( noBytes <= CHECKSUM_LEN )
  691.                 checkBytes = CHECKSUM_LEN - ( int ) noBytes;
  692.             printCount += length;
  693.             if( modelByteCount < SCALE_RANGE )
  694.                 modelByteCount += length;
  695.  
  696.             /* Copy length bytes, starting at position, to the output */
  697.             while( length-- )
  698.                 {
  699.                 /* Read bytes of the string out of the circular buffer */
  700.                 ch = textBuffer[ position++ & STR_BUF_MASK ];
  701.                 if( checkBytes && length < checkBytes )
  702.                     {
  703.                     /* If the data is corrupted we may end up decoding a
  704.                        random string, so we insert a sanity check here */
  705.                     if( endByte >= CHECKSUM_LEN )
  706.                         {
  707.                         flushBuffer();        /* Flush any remaining data */
  708.                         return( FALSE );
  709.                         }
  710.  
  711.                     checkSum[ endByte++ ] = ch;
  712.                     }
  713.                 else
  714.                     fputByte( ch );
  715.  
  716.                 /* Add them to the tail end of the buffer */
  717.                 textBuffer[ bufIndex++ ] = ch;
  718.                 bufIndex &= STR_BUF_MASK;
  719.                 }
  720.             }
  721.  
  722.         /* Output a dit for every 2K processed */
  723.         if( printCount >= 2048 )
  724.             {
  725. #ifdef GUI
  726.             updateProgressReport();
  727. #else
  728.             if( flipFlop )
  729.                 {
  730.                 hputchars( '\b' );
  731.                 hputchars( 'O' );
  732.                 }
  733.             else
  734.                 hputchars( 'o' );
  735.             hflush( stdout );
  736.             flipFlop = !flipFlop;
  737.             printCount -= 2048;
  738. #endif /* GUI */
  739. #ifdef __MAC__
  740.             yieldTimeSlice();
  741. #endif /* __MAC__ */
  742.             }
  743.         }
  744.  
  745.     /* Flush the output buffer and print the last dit if necessary */
  746.     flushBuffer();
  747. #ifndef GUI
  748.     if( flipFlop )
  749.         {
  750.         hputchars( '\b' );
  751.         hputchars( 'O' );
  752.         hflush( stdout );
  753.         }
  754. #endif /* GUI */
  755.  
  756.     /* Compare the final CHECKSUM_LEN decoded bytes against the checksum as
  757.        a data integrity check */
  758.     return( !memcmp( checkSum, ( isText ) ? CHECKSUM_TEXT : CHECKSUM_BIN, \
  759.                      CHECKSUM_LEN ) );
  760.     }
  761.