home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / System / XFD / Developer / Sources / C / UNIX-Compress.c < prev   
Encoding:
C/C++ Source or Header  |  2001-09-16  |  9.1 KB  |  315 lines

  1. unsigned char version[] = "$VER: UNIX-Compress 1.2 (04.08.1998) by SDI";
  2.  
  3. /* Objectheader
  4.  
  5.     Name:        UNIX-Compress.c
  6.     Description:    xfd external decruncher for UNIX compress files
  7.     Author:        SDI (stoecker@epost.de)
  8.     Distribution:    PD
  9.  
  10.  1.0   22.12.97 : first version
  11.  1.1   23.12.97 : added memory expansion
  12.  1.2   04.08.98 : bug fix for block compress, added internal SysBase
  13. */
  14.  
  15. /* Because there is no way to find out the size of uncrunched file, this
  16.    routine uses a destination buffer, which is 4 times as large as the
  17.    source file. When there is not enough memory, the largest memory block
  18.    is used.
  19.    This does surely not cover all Compress files! So there may be some
  20.    which cannot be decrunched. XPKERR_CORRUPTEDDATA should be reported for
  21.    these. In this case the program tries to allocate the largest available
  22.    memory block and restarts decrunching.
  23.  
  24.    Has anyone a better idea how to find out destination length?
  25. */
  26.  
  27. #include <libraries/xfdmaster.h>
  28. #include <proto/exec.h>
  29. #include <exec/memory.h>
  30. #include "SDI_compiler.h"
  31.  
  32. #define MAXCODE(n)    (((ULONG) 1 << (n)) - 1)
  33.  
  34. #define BITS           16
  35. #define STACKSIZE     8000
  36. #define FIRST          257        /* first free entry */
  37. #define CLEAR          256        /* table clear output code */
  38. #define INIT_BITS        9        /* initial number of bits/code */
  39.  
  40. /* Defines for third byte of header */
  41. #define BIT_MASK    0x1f
  42. #define BLOCK_MASK    0x80
  43. #define LZW_RESERVED    0x60
  44.     /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that
  45.        there is a fourth header byte (for expansion). */
  46.  
  47. static UBYTE rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  48.  
  49. struct CompressData {
  50.   UWORD      block_compress;
  51.   WORD        clear_flg;
  52.   UWORD        n_bits;            /* number of bits/code */
  53.   UWORD      maxbits;        /* user settable max # bits/code */
  54.   ULONG     maxcode;        /* maximum code, given n_bits */
  55.   ULONG     maxmaxcode;
  56.   LONG         free_ent;
  57.   LONG        offset;
  58.   LONG        size;
  59.   STRPTR    inptr;            /* current input pointer */
  60.   STRPTR    inendptr;        /* end of input buffer */
  61.   UWORD *    tab_prefixof;
  62.   STRPTR     tab_suffixof;
  63.   STRPTR     stack;
  64.   UBYTE        buf[BITS];
  65. };
  66.  
  67. /************** Here starts xfd stuff - the xfdSlave structure **********/
  68.  
  69. #define MASTER_VERS    36
  70.  
  71. typedef BOOL (*xfdFunc) ();
  72.  
  73. ASM(LONG) RecogCompress(REG(a0, STRPTR buf), REG(d0, ULONG length));
  74. ASM(BOOL) DecrunchCompress(REG(a0, struct xfdBufferInfo * xbi),
  75.  REG(a6, struct xfdMasterBase *xfdMasterBase));
  76. static LONG decomp(struct CompressData *, STRPTR, ULONG, STRPTR, ULONG);
  77. static LONG getcode(struct CompressData *);
  78.  
  79. struct xfdSlave FirstSlave = {
  80.   0, XFDS_VERSION, MASTER_VERS, "UNIX Compress", XFDPFF_DATA, 0, 
  81.   (xfdFunc) RecogCompress, (xfdFunc) DecrunchCompress, 0, 0, 0, 0, 4};
  82.  
  83. ASM(LONG) RecogCompress(REG(a0, STRPTR buf), REG(d0, ULONG length))
  84. {
  85.   if(*((UWORD *)buf) == 0x1F9D)
  86.   {
  87.     UBYTE mb = buf[2];
  88.     if(mb & LZW_RESERVED)        /* Unknown format */
  89.       return 0;
  90.     if((mb & BIT_MASK) > BITS)        /* Too much bits */
  91.       return 0;
  92.     return 1;    /* Now should be a correct file */
  93.   }
  94.   return 0;
  95. }
  96.  
  97. ASM(BOOL) DecrunchCompress(REG(a0, struct xfdBufferInfo * xbi),
  98. REG(a6, struct xfdMasterBase *xfdMasterBase))
  99. {
  100.   struct CompressData cd;
  101.   LONG ret = -XFDERR_NOMEMORY;
  102.   ULONG maxmaxcode = 1<<((((STRPTR)xbi->xfdbi_SourceBuffer)[2])&BIT_MASK);
  103.   struct ExecBase *SysBase;
  104.  
  105.   SysBase = xfdMasterBase->xfdm_ExecBase;
  106.  
  107.   if((cd.tab_prefixof = (UWORD *) AllocMem(sizeof(UWORD)*maxmaxcode, MEMF_ANY)))
  108.   {
  109.     if((cd.stack = (STRPTR) AllocMem(STACKSIZE, MEMF_ANY)))
  110.     {
  111.       if((cd.tab_suffixof = (STRPTR) AllocMem(maxmaxcode, MEMF_ANY)))
  112.       {
  113.         ULONG bufsize;
  114.  
  115.     bufsize = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
  116.  
  117.         if((xbi->xfdbi_TargetBufLen = xbi->xfdbi_SourceBufLen<<2) > bufsize)
  118.           xbi->xfdbi_TargetBufLen = bufsize;
  119.  
  120.         if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
  121.         xbi->xfdbi_TargetBufMemType)))
  122.         {
  123.           if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
  124.           xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
  125.           xbi->xfdbi_TargetBufLen)) > 0)
  126.             xbi->xfdbi_TargetBufSaveLen = ret;
  127.           else
  128.           {
  129.             FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
  130.             if(bufsize != xbi->xfdbi_TargetBufLen)
  131.             {
  132.           /* expand memory to full available and retry */
  133.               xbi->xfdbi_TargetBufLen = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
  134.               if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
  135.               xbi->xfdbi_TargetBufMemType)))
  136.               {
  137.                 if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
  138.                 xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
  139.                 xbi->xfdbi_TargetBufLen)) > 0)
  140.                   xbi->xfdbi_TargetBufSaveLen = ret;
  141.                 else
  142.                   FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
  143.               }
  144.             }
  145.           }
  146.         }
  147.  
  148.         FreeMem(cd.tab_suffixof, maxmaxcode);
  149.       }
  150.       FreeMem(cd.stack, STACKSIZE);
  151.     }
  152.     FreeMem(cd.tab_prefixof, sizeof(UWORD)*maxmaxcode);
  153.   }
  154.  
  155.   if(ret <= 0)
  156.   {
  157.     xbi->xfdbi_TargetBufLen = xbi->xfdbi_TargetBufSaveLen = 0;
  158.     xbi->xfdbi_TargetBuffer = 0;
  159.     xbi->xfdbi_Error = -ret;
  160.     return 0;
  161.   }
  162.  
  163.   return (BOOL) ret;
  164. }
  165.  
  166. /* Decompress. This routine adapts to the codes in the file building the
  167.  * "string" table on-the-fly; requiring no table to be stored in the
  168.  * compressed file.
  169.  */
  170.  
  171. /* negative values are error codes, positive value is resulting size */
  172. static LONG decomp(struct CompressData *cd, STRPTR inbuf, ULONG insize,
  173. STRPTR outbuf, ULONG outsize)
  174. {
  175.   LONG finchar, code, oldcode, incode, blockcomp;
  176.   STRPTR outptr = outbuf, stackp = cd->stack,
  177.   stack = cd->stack, outend = outbuf+outsize;
  178.  
  179.   cd->maxbits = inbuf[2];
  180.   blockcomp = cd->block_compress = cd->maxbits & BLOCK_MASK;
  181.   cd->maxbits &= BIT_MASK;
  182.   cd->maxmaxcode = 1 << cd->maxbits;
  183.   cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
  184.   cd->free_ent = ((cd->block_compress) ? FIRST : 256);
  185.   cd->clear_flg = cd->offset = cd->size = 0;
  186.   cd->inptr = inbuf+3;
  187.   cd->inendptr = inbuf+insize;
  188.  
  189.   /* Initialize the first 256 entries in the table. */
  190.   for(code = 255; code >= 0; code--)
  191.   {
  192.     cd->tab_prefixof[code] = 0;
  193.     cd->tab_suffixof[code] = (UBYTE) code;
  194.   }
  195.  
  196.   if((finchar = oldcode = getcode(cd)) == -1)    /* EOF already ? */
  197.     return -XFDERR_CORRUPTEDDATA;        /* Get out of here */
  198.   *(outptr++) = (UBYTE) finchar; /* first code must be 8 bits = UBYTE */
  199.  
  200.   while((code = getcode(cd)) > -1)
  201.   {
  202.     if((code == CLEAR) && blockcomp)
  203.     {
  204.       for(code = 255; code >= 0; code--)
  205.     cd->tab_prefixof[code] = 0;
  206.       cd->clear_flg = 1;
  207.       cd->free_ent = FIRST - 1;
  208.       if((code = getcode(cd)) == -1)
  209.     break;                    /* O, untimely death! */
  210.     }
  211.     incode = code;
  212.  
  213.     /* Special case for KwKwK string. */
  214.     if(code >= cd->free_ent)
  215.     {
  216.       *stackp++ = finchar;
  217.       code = oldcode;
  218.     }
  219.  
  220.     /* Generate output characters in reverse order */
  221.     while(code >= 256)
  222.     {
  223.       *stackp++ = cd->tab_suffixof[code];
  224.       code = cd->tab_prefixof[code];
  225.     }
  226.     *stackp++ = finchar = cd->tab_suffixof[code];
  227.  
  228.     if(stackp - stack > outend - outptr) /* buffer was to short :-( */
  229.       return -XFDERR_CORRUPTEDDATA;
  230.  
  231.     /* And put them out in forward order */
  232.     do
  233.     {
  234.       *(outptr++) = *(--stackp);
  235.     } while(stackp > stack);
  236.  
  237.     /* Generate the new entry. */
  238.     if((code = cd->free_ent) < cd->maxmaxcode)
  239.     {
  240.       cd->tab_prefixof[code] = (UWORD) oldcode;
  241.       cd->tab_suffixof[code] = finchar;
  242.       cd->free_ent = code+1;
  243.     }
  244.     /* Remember previous code. */
  245.     oldcode = incode;
  246.   }
  247.   return (outptr-outbuf);
  248. }
  249.  
  250. /* Read one code from input. If EOF, return -1. */
  251. static LONG getcode(struct CompressData *cd)
  252. {
  253.   LONG code, r_off, bits;
  254.   UBYTE *bp = cd->buf;
  255.  
  256.   if(cd->clear_flg > 0 || cd->offset >= cd->size || cd->free_ent > cd->maxcode)
  257.   {
  258.     /*
  259.      * If the next entry will be too big for the current code
  260.      * size, then we must increase the size.  This implies reading
  261.      * a new buffer full, too.
  262.      */
  263.     if(cd->free_ent > cd->maxcode)
  264.     {
  265.       if(++cd->n_bits == cd->maxbits)
  266.     cd->maxcode = cd->maxmaxcode;    /* won't get any bigger now */
  267.       else
  268.     cd->maxcode = MAXCODE(cd->n_bits);
  269.     }
  270.     if(cd->clear_flg > 0)
  271.     {
  272.       cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
  273.       cd->clear_flg = 0;
  274.     }
  275.  
  276.     if(cd->inendptr <= cd->inptr)
  277.       return -1;            /* end of file */
  278.  
  279.     /* This reads maximum n_bits characters into buf */
  280.     cd->size = 0;
  281.     while(cd->size < cd->n_bits && cd->inptr < cd->inendptr)
  282.       cd->buf[cd->size++] = *(cd->inptr++);
  283.  
  284.     cd->offset = 0;
  285.     /* Round size down to integral number of codes */
  286.     cd->size = (cd->size << 3) - (cd->n_bits - 1);
  287.   }
  288.   r_off = cd->offset;
  289.   bits = cd->n_bits;
  290.  
  291.   /* Get to the first byte. */
  292.   bp += (r_off >> 3);
  293.   r_off &= 7;
  294.  
  295.   /* Get first part (low order bits) */
  296.   code = (*bp++ >> r_off);
  297.   bits -= (8 - r_off);
  298.   r_off = 8 - r_off;            /* now, offset into code word */
  299.  
  300.   /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  301.   if(bits >= 8)
  302.   {
  303.     code |= *bp++ << r_off;
  304.     r_off += 8;
  305.     bits -= 8;
  306.   }
  307.  
  308.   /* high order bits. */
  309.   code |= (*bp & rmask[bits]) << r_off;
  310.   cd->offset += cd->n_bits;
  311.  
  312.   return code;
  313. }
  314.  
  315.