⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deflate.c

📁 压缩算法的C语言源程序
💻 C
字号:
/*
   deflate.c
   Deflate and Inflate Algorithm v1.2 for gsLib
*/
#include <stdlib.h>
#include <string.h>
#include <compress.h>

#define WINDOW_SIZE 32768 // 32k Sliding Window
#define WINDOW_MASK (WINDOW_SIZE - 1)

// extra bits in the length table
static const int extra_lenbits[] = {
   0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0
};

// length table bases
static const int lenbase[] =
{
   3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,
   115,131,163,195,227,258,999
};

// extra bits in the distance table
static const int extra_distbits[] = {
   0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13
};

// distance table bases
static const int distbase[] = {
   1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,
   1537,2049,3073,4097,6145,8193,12289,16385,24577,99999
};

static STREAM *in, *out;
static dword bytesread, byteswritten, readlimit, writelimit;

// defines a few macros for file io transfer
inline static int getByte()
{
   if(bytesread < readlimit) {
      bytesread++;
      return stream_getc(in);
   }
   return -1;
}

inline static void putByte(int ch)
{
   if(byteswritten < writelimit) {
      byteswritten++;
      stream_putc(ch,out);
   }
}

inline static dword ReadBitr(dword size)
{
   int before;
   dword ch;

   if(bytesread < readlimit) {
      before = stream_tell(in);
      ch = stream_read_bitr(in,size);
      bytesread += stream_tell(in) - before;
      return ch;
   }
   return 0;
}

inline static void WriteBitr(dword code,dword size)
{
   int before;

   if(byteswritten < writelimit) {
      before = stream_tell(out);
      stream_write_bitr(out,code,size);
      byteswritten += stream_tell(out) - before;
   }
}

inline static void WriteHuffCode(HuffTable bin)
{
   int before;

   before = stream_tell(out);
   WriteHuffmanCode(out,bin);
   byteswritten += stream_tell(out) - before;
}

inline static void FlushReadBuffer()
{
   stream_flush_read_buffer(in);
}

inline static void FlushWriteBufferR()
{
   stream_flush_write_bufferr(out);
}

/*
   dword deflate(STREAM *dest,STREAM *src,dword length,int level):
   Compresses `src' to `dest' using the deflate algorithm.
*/
dword deflate(STREAM *dest,STREAM *src,dword length,int level)
{
   STREAM *lz;
   HuffTable *littab, *disttab;
   int mask = 0, ch, len, dist, prefixcnt = 0, before, i;
   byte *data;

   in = src;
   out = dest;
   bytesread = byteswritten = 0;
   writelimit = 0xFFFFFFFF;

   // allocate temporary memory
   lz = stream_alloc(length + (length >> 3));
   if(!lz) return 0;

   littab = (HuffTable *)malloc((286 + 30) * sizeof(HuffTable));
   if(!littab) {
      stream_close(lz);
      gerror("Not enough memory for literal table.");
      THROW (E_MEMORY) return 0;
   }

   disttab = &littab[286];
   // initialize the table
   for(i = 0; i < 286; i++) {
      littab[i].code = i;
      littab[i].len = 0;
      if(i < 30) {
         disttab[i].code = i;
         disttab[i].len = 0;
      }
   }

   // lz77 encode it first
   length = lz77_encode(lz,in,length,level);
   if(!length) {
      stream_close(lz);
      free(littab);
      return 0;
   }
   readlimit = length;

   // get data
   data = lz->handle.mp;
   // first pass: count number of lit/dist
   while(bytesread < length) {
      if(!prefixcnt) {
         mask = data[bytesread++];  // get prefix
         prefixcnt = 8;
      }
      if(mask & 0x80) { // if prefix is flagged
         len = *(data + bytesread) + 3;
         dist = *(word *)(data + bytesread + 1) + 1;
         bytesread += 3;

         for(i = 0; i < 29; i++) if(len < lenbase[i + 1]) break;
         littab[i + 257].len++;
         for(i = 0; i < 30; i++) if(dist < distbase[i + 1]) break;
         disttab[i].len++;
      } else { // otherwise literal output
         ch = data[bytesread++];
         littab[ch].len++;
      }

      mask <<= 1;
      prefixcnt--;
   }

   littab[256].len = 1; // EOF len = 1

   // generate huffman codes
   CalculateMinimumRedundancy(littab,286);
   BuildHuffTable(littab,286);
   CalculateMinimumRedundancy(disttab,30);
   BuildHuffTable(disttab,30);
   before = stream_tell(out);
   WriteHuffmanHeader(out,littab,286,30); // write deflate header
   byteswritten = stream_tell(out) - before;

   // pass 2: genertae codes
   prefixcnt = 0;
   mask = 0;

   bytesread = 0;
   while(bytesread < length) {
      if(!prefixcnt) {
         mask = data[bytesread++];  // get prefix
         prefixcnt = 8;
      }
      if(mask & 0x80) { // if prefix is flagged
         len = *(data + bytesread) + 3;
         dist = *(word *)(data + bytesread + 1) + 1;
         bytesread += 3;

         for(i = 0; i < 29; i++) if(len < lenbase[i + 1]) break;
         WriteHuffCode(littab[i + 257]);
         len -= lenbase[i];
         if(extra_lenbits[i]) WriteBitr(len,extra_lenbits[i]);
         for(i = 0; i < 30; i++) if(dist < distbase[i + 1]) break;
         WriteHuffCode(disttab[i]);
         dist -= distbase[i];
         if(extra_distbits[i]) WriteBitr(dist,extra_distbits[i]);
      } else { // otherwise literal output
         ch = data[bytesread++];
         WriteHuffCode(littab[ch]);
      }

      mask <<= 1;
      prefixcnt--;
   }

   WriteHuffCode(littab[256]); // write EOF
   before = stream_tell(out);
   FlushWriteBufferR();
   byteswritten = stream_tell(out) - before;

   free(littab);
   stream_close(lz);

   return byteswritten;
}

/*
   dword inflate(STREAM *dest,STREAM *src,dword length):
   Decompress `src' to `dest' by the method inflate
*/
dword inflate(STREAM *dest,STREAM *src,dword length)
{
   int i, nlit, ndist, len, dist, code, final = 0;
   byte *sw;
   HuffTable *littab, *disttab;
   HuffLookup *litlk, *distlk;
   dword winoffset = 0;

   in = src;
   out = dest;
   bytesread = byteswritten = 0;
   readlimit = 0xFFFFFFFF;
   writelimit = length;

   sw = (byte *)malloc(WINDOW_SIZE);
   if(!sw) {
      gerror("Not enough memory for sliding window.");
      THROW (E_MEMORY) return 0;
   }

   littab = (HuffTable *)malloc((286 + 30) * sizeof(HuffTable));
   if(!littab) {
      free(sw);
      gerror("Not enough memory for Literal/Distance Tables.");
      THROW (E_MEMORY) return 0;
   }

   while(!(final & 1)) {
      final = ReadHuffmanHeader(in,littab,&disttab,&nlit,&ndist);

      if(final & 2) {            // if literal data
         FlushReadBuffer();      // clear remaining bits
         len = getByte();
         len |= getByte() << 8;  // read Len
         code = getByte();
         code |= getByte() << 8;  // read length compliment
         if(len + code != 0xFFFF) {
            gerror("Len and nLen are not compliment! Please report bug.");
            free(sw); free(littab);
            THROW (E_UNKNOWN) return 0;
         }
         // copy literal byte to output
         for(i = 0; i < len; i++) {
            code = getByte();
            putByte(code);
            sw[winoffset] = code;
            winoffset++;
            winoffset &= WINDOW_MASK;
         }
         continue;
      }

      litlk = BuildHuffmanLookupTable(littab,nlit);
      if(!litlk) {
         free(sw); free(littab);
         gerror("Not enough memory for literal lookup table.");
         THROW (E_MEMORY) return 0;
      }
      distlk = BuildHuffmanLookupTable(disttab,ndist);
      if(!distlk) {
         free(sw); free(littab); free(litlk);
         gerror("Not enough memory for distance lookup table.");
         THROW (E_MEMORY) return 0;
      }

      while(byteswritten < length) {
         code = FetchHuffmanCode(in,litlk);

         if(code == 256) break; // eof code
         else {
            if(code > 256) { // len code
               // decode len
               len = lenbase[code - 257];
               if(extra_lenbits[code - 257])
                  len += ReadBitr(extra_lenbits[code - 257]);

               // decode distance
               code = FetchHuffmanCode(in,distlk);

               dist = distbase[code];
               if(extra_distbits[code])
                  dist += ReadBitr(extra_distbits[code]);

               // go bask dist bytes, and copy len bytes to the output
               for(i = 0; i < len; i++) {
                  putByte(sw[(winoffset - dist) & WINDOW_MASK]);
                  sw[winoffset] = sw[(winoffset - dist) & WINDOW_MASK];
                  winoffset++;
                  winoffset &= WINDOW_MASK;
               }
            } else { // code is < 256 mean its a literal
               putByte(code);
               sw[winoffset] = code;
               winoffset++;
               winoffset &= WINDOW_MASK;
            }
         }
      } // end while

      free(litlk);
      free(distlk);
   } // end while

   free(sw);
   free(littab);

   return byteswritten;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -