• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

fastlz.c

Go to the documentation of this file.
00001 /*
00002   FastLZ - lightning-fast lossless compression library
00003 
00004   Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
00005   Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
00006   Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
00007 
00008   Permission is hereby granted, free of charge, to any person obtaining a copy
00009   of this software and associated documentation files (the "Software"), to deal
00010   in the Software without restriction, including without limitation the rights
00011   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012   copies of the Software, and to permit persons to whom the Software is
00013   furnished to do so, subject to the following conditions:
00014 
00015   The above copyright notice and this permission notice shall be included in
00016   all copies or substantial portions of the Software.
00017 
00018   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024   THE SOFTWARE.
00025 */
00026 
00027 #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
00028 
00029 /*
00030  * Always check for bound when decompressing.
00031  * Generally it is best to leave it defined.
00032  */
00033 #define FASTLZ_SAFE
00034 
00035 /*
00036  * Give hints to the compiler for branch prediction optimization.
00037  */
00038 #if defined(__GNUC__) && (__GNUC__ > 2)
00039 #define FASTLZ_EXPECT_CONDITIONAL(c)    (__builtin_expect((c), 1))
00040 #define FASTLZ_UNEXPECT_CONDITIONAL(c)  (__builtin_expect((c), 0))
00041 #else
00042 #define FASTLZ_EXPECT_CONDITIONAL(c)    (c)
00043 #define FASTLZ_UNEXPECT_CONDITIONAL(c)  (c)
00044 #endif
00045 
00046 /*
00047  * Use inlined functions for supported systems.
00048  */
00049 #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
00050 #define FASTLZ_INLINE inline
00051 #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
00052 #define FASTLZ_INLINE __inline
00053 #else
00054 #define FASTLZ_INLINE
00055 #endif
00056 
00057 /*
00058  * Prevent accessing more than 8-bit at once, except on x86 architectures.
00059  */
00060 #if !defined(FASTLZ_STRICT_ALIGN)
00061 #define FASTLZ_STRICT_ALIGN
00062 #if defined(__i386__) || defined(__386)  /* GNU C, Sun Studio */
00063 #undef FASTLZ_STRICT_ALIGN
00064 #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
00065 #undef FASTLZ_STRICT_ALIGN
00066 #elif defined(_M_IX86) /* Intel, MSVC */
00067 #undef FASTLZ_STRICT_ALIGN
00068 #elif defined(__386)
00069 #undef FASTLZ_STRICT_ALIGN
00070 #elif defined(_X86_) /* MinGW */
00071 #undef FASTLZ_STRICT_ALIGN
00072 #elif defined(__I86__) /* Digital Mars */
00073 #undef FASTLZ_STRICT_ALIGN
00074 #endif
00075 #endif
00076 
00077 /*
00078  * FIXME: use preprocessor magic to set this on different platforms!
00079  */
00080 typedef unsigned char  flzuint8;
00081 typedef unsigned short flzuint16;
00082 typedef unsigned int   flzuint32;
00083 
00084 /* prototypes */
00085 int fastlz_compress(const void* input, int length, void* output);
00086 int fastlz_compress_level(int level, const void* input, int length, void* output);
00087 int fastlz_decompress(const void* input, int length, void* output, int maxout);
00088 
00089 #define MAX_COPY       32
00090 #define MAX_LEN       264  /* 256 + 8 */
00091 #define MAX_DISTANCE 8192
00092 
00093 #if !defined(FASTLZ_STRICT_ALIGN)
00094 #define FASTLZ_READU16(p) *((const flzuint16*)(p))
00095 #else
00096 #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
00097 #endif
00098 
00099 #define HASH_LOG  13
00100 #define HASH_SIZE (1<< HASH_LOG)
00101 #define HASH_MASK  (HASH_SIZE-1)
00102 #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
00103 
00104 #undef FASTLZ_LEVEL
00105 #define FASTLZ_LEVEL 1
00106 
00107 #undef FASTLZ_COMPRESSOR
00108 #undef FASTLZ_DECOMPRESSOR
00109 #define FASTLZ_COMPRESSOR fastlz1_compress
00110 #define FASTLZ_DECOMPRESSOR fastlz1_decompress
00111 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
00112 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
00113 #include "fastlz.c"
00114 
00115 #undef FASTLZ_LEVEL
00116 #define FASTLZ_LEVEL 2
00117 
00118 #undef MAX_DISTANCE
00119 #define MAX_DISTANCE 8191
00120 #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
00121 
00122 #undef FASTLZ_COMPRESSOR
00123 #undef FASTLZ_DECOMPRESSOR
00124 #define FASTLZ_COMPRESSOR fastlz2_compress
00125 #define FASTLZ_DECOMPRESSOR fastlz2_decompress
00126 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
00127 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
00128 #include "fastlz.c"
00129 
00130 int fastlz_compress(const void* input, int length, void* output)
00131 {
00132   /* for short block, choose fastlz1 */
00133   if(length < 65536)
00134     return fastlz1_compress(input, length, output);
00135 
00136   /* else... */
00137   return fastlz2_compress(input, length, output);
00138 }
00139 
00140 int fastlz_decompress(const void* input, int length, void* output, int maxout)
00141 {
00142   /* magic identifier for compression level */
00143   int level = ((*(const flzuint8*)input) >> 5) + 1;
00144 
00145   if(level == 1)
00146     return fastlz1_decompress(input, length, output, maxout);
00147   if(level == 2)
00148     return fastlz2_decompress(input, length, output, maxout);
00149 
00150   /* unknown level, trigger error */
00151   return 0;
00152 }
00153 
00154 int fastlz_compress_level(int level, const void* input, int length, void* output)
00155 {
00156   if(level == 1)
00157     return fastlz1_compress(input, length, output);
00158   if(level == 2)
00159     return fastlz2_compress(input, length, output);
00160 
00161   return 0;
00162 }
00163 
00164 #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
00165 
00166 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
00167 {
00168   const flzuint8* ip = (const flzuint8*) input;
00169   const flzuint8* ip_bound = ip + length - 2;
00170   const flzuint8* ip_limit = ip + length - 12;
00171   flzuint8* op = (flzuint8*) output;
00172 
00173   const flzuint8* htab[HASH_SIZE];
00174   const flzuint8** hslot;
00175   flzuint32 hval;
00176 
00177   flzuint32 copy;
00178 
00179   /* sanity check */
00180   if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
00181   {
00182     if(length)
00183     {
00184       /* create literal copy only */
00185       *op++ = length-1;
00186       ip_bound++;
00187       while(ip <= ip_bound)
00188         *op++ = *ip++;
00189       return length+1;
00190     }
00191     else
00192       return 0;
00193   }
00194 
00195   /* initializes hash table */
00196   for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
00197     *hslot = ip;
00198 
00199   /* we start with literal copy */
00200   copy = 2;
00201   *op++ = MAX_COPY-1;
00202   *op++ = *ip++;
00203   *op++ = *ip++;
00204 
00205   /* main loop */
00206   while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
00207   {
00208     const flzuint8* ref;
00209     flzuint32 distance;
00210 
00211     /* minimum match length */
00212     flzuint32 len = 3;
00213 
00214     /* comparison starting-point */
00215     const flzuint8* anchor = ip;
00216 
00217     /* check for a run */
00218 #if FASTLZ_LEVEL==2
00219     if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
00220     {
00221       distance = 1;
00222       ref = anchor - 1 + 3;
00223       goto match;
00224     }
00225 #endif
00226 
00227     /* find potential match */
00228     HASH_FUNCTION(hval,ip);
00229     hslot = htab + hval;
00230     ref = htab[hval];
00231 
00232     /* calculate distance to the match */
00233     distance = anchor - ref;
00234 
00235     /* update hash table */
00236     *hslot = anchor;
00237 
00238     /* is this a match? check the first 3 bytes */
00239     if(distance==0 ||
00240 #if FASTLZ_LEVEL==1
00241     (distance >= MAX_DISTANCE) ||
00242 #else
00243     (distance >= MAX_FARDISTANCE) ||
00244 #endif
00245     *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
00246       goto literal;
00247 
00248 #if FASTLZ_LEVEL==2
00249     /* far, needs at least 5-byte match */
00250     if(distance >= MAX_DISTANCE)
00251     {
00252       if(*ip++ != *ref++ || *ip++!= *ref++)
00253         goto literal;
00254       len += 2;
00255     }
00256 
00257     match:
00258 #endif
00259 
00260     /* last matched byte */
00261     ip = anchor + len;
00262 
00263     /* distance is biased */
00264     distance--;
00265 
00266     if(!distance)
00267     {
00268       /* zero distance means a run */
00269       flzuint8 x = ip[-1];
00270       while(ip < ip_bound)
00271         if(*ref++ != x) break; else ip++;
00272     }
00273     else
00274     for(;;)
00275     {
00276       /* safe because the outer check against ip limit */
00277       if(*ref++ != *ip++) break;
00278       if(*ref++ != *ip++) break;
00279       if(*ref++ != *ip++) break;
00280       if(*ref++ != *ip++) break;
00281       if(*ref++ != *ip++) break;
00282       if(*ref++ != *ip++) break;
00283       if(*ref++ != *ip++) break;
00284       if(*ref++ != *ip++) break;
00285       while(ip < ip_bound)
00286         if(*ref++ != *ip++) break;
00287       break;
00288     }
00289 
00290     /* if we have copied something, adjust the copy count */
00291     if(copy)
00292       /* copy is biased, '0' means 1 byte copy */
00293       *(op-copy-1) = copy-1;
00294     else
00295       /* back, to overwrite the copy count */
00296       op--;
00297 
00298     /* reset literal counter */
00299     copy = 0;
00300 
00301     /* length is biased, '1' means a match of 3 bytes */
00302     ip -= 3;
00303     len = ip - anchor;
00304 
00305     /* encode the match */
00306 #if FASTLZ_LEVEL==2
00307     if(distance < MAX_DISTANCE)
00308     {
00309       if(len < 7)
00310       {
00311         *op++ = (len << 5) + (distance >> 8);
00312         *op++ = (distance & 255);
00313       }
00314       else
00315       {
00316         *op++ = (7 << 5) + (distance >> 8);
00317         for(len-=7; len >= 255; len-= 255)
00318           *op++ = 255;
00319         *op++ = len;
00320         *op++ = (distance & 255);
00321       }
00322     }
00323     else
00324     {
00325       /* far away, but not yet in the another galaxy... */
00326       if(len < 7)
00327       {
00328         distance -= MAX_DISTANCE;
00329         *op++ = (len << 5) + 31;
00330         *op++ = 255;
00331         *op++ = distance >> 8;
00332         *op++ = distance & 255;
00333       }
00334       else
00335       {
00336         distance -= MAX_DISTANCE;
00337         *op++ = (7 << 5) + 31;
00338         for(len-=7; len >= 255; len-= 255)
00339           *op++ = 255;
00340         *op++ = len;
00341         *op++ = 255;
00342         *op++ = distance >> 8;
00343         *op++ = distance & 255;
00344       }
00345     }
00346 #else
00347 
00348     if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
00349       while(len > MAX_LEN-2)
00350       {
00351         *op++ = (7 << 5) + (distance >> 8);
00352         *op++ = MAX_LEN - 2 - 7 -2;
00353         *op++ = (distance & 255);
00354         len -= MAX_LEN-2;
00355       }
00356 
00357     if(len < 7)
00358     {
00359       *op++ = (len << 5) + (distance >> 8);
00360       *op++ = (distance & 255);
00361     }
00362     else
00363     {
00364       *op++ = (7 << 5) + (distance >> 8);
00365       *op++ = len - 7;
00366       *op++ = (distance & 255);
00367     }
00368 #endif
00369 
00370     /* update the hash at match boundary */
00371     HASH_FUNCTION(hval,ip);
00372     htab[hval] = ip++;
00373     HASH_FUNCTION(hval,ip);
00374     htab[hval] = ip++;
00375 
00376     /* assuming literal copy */
00377     *op++ = MAX_COPY-1;
00378 
00379     continue;
00380 
00381     literal:
00382       *op++ = *anchor++;
00383       ip = anchor;
00384       copy++;
00385       if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
00386       {
00387         copy = 0;
00388         *op++ = MAX_COPY-1;
00389       }
00390   }
00391 
00392   /* left-over as literal copy */
00393   ip_bound++;
00394   while(ip <= ip_bound)
00395   {
00396     *op++ = *ip++;
00397     copy++;
00398     if(copy == MAX_COPY)
00399     {
00400       copy = 0;
00401       *op++ = MAX_COPY-1;
00402     }
00403   }
00404 
00405   /* if we have copied something, adjust the copy length */
00406   if(copy)
00407     *(op-copy-1) = copy-1;
00408   else
00409     op--;
00410 
00411 #if FASTLZ_LEVEL==2
00412   /* marker for fastlz2 */
00413   *(flzuint8*)output |= (1 << 5);
00414 #endif
00415 
00416   return op - (flzuint8*)output;
00417 }
00418 
00419 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
00420 {
00421   const flzuint8* ip = (const flzuint8*) input;
00422   const flzuint8* ip_limit  = ip + length;
00423   flzuint8* op = (flzuint8*) output;
00424   flzuint8* op_limit = op + maxout;
00425   flzuint32 ctrl = (*ip++) & 31;
00426   int loop = 1;
00427 
00428   do
00429   {
00430     const flzuint8* ref = op;
00431     flzuint32 len = ctrl >> 5;
00432     flzuint32 ofs = (ctrl & 31) << 8;
00433 
00434     if(ctrl >= 32)
00435     {
00436 #if FASTLZ_LEVEL==2
00437       flzuint8 code;
00438 #endif
00439       len--;
00440       ref -= ofs;
00441       if (len == 7-1)
00442 #if FASTLZ_LEVEL==1
00443         len += *ip++;
00444       ref -= *ip++;
00445 #else
00446         do
00447         {
00448           code = *ip++;
00449           len += code;
00450         } while (code==255);
00451       code = *ip++;
00452       ref -= code;
00453 
00454       /* match from 16-bit distance */
00455       if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
00456       if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
00457       {
00458         ofs = (*ip++) << 8;
00459         ofs += *ip++;
00460         ref = op - ofs - MAX_DISTANCE;
00461       }
00462 #endif
00463 
00464 #ifdef FASTLZ_SAFE
00465       if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
00466         return 0;
00467 
00468       if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
00469         return 0;
00470 #endif
00471 
00472       if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
00473         ctrl = *ip++;
00474       else
00475         loop = 0;
00476 
00477       if(ref == op)
00478       {
00479         /* optimize copy for a run */
00480         flzuint8 b = ref[-1];
00481         *op++ = b;
00482         *op++ = b;
00483         *op++ = b;
00484         for(; len; --len)
00485           *op++ = b;
00486       }
00487       else
00488       {
00489 #if !defined(FASTLZ_STRICT_ALIGN)
00490         const flzuint16* p;
00491         flzuint16* q;
00492 #endif
00493         /* copy from reference */
00494         ref--;
00495         *op++ = *ref++;
00496         *op++ = *ref++;
00497         *op++ = *ref++;
00498 
00499 #if !defined(FASTLZ_STRICT_ALIGN)
00500         /* copy a byte, so that now it's word aligned */
00501         if(len & 1)
00502         {
00503           *op++ = *ref++;
00504           len--;
00505         }
00506 
00507         /* copy 16-bit at once */
00508         q = (flzuint16*) op;
00509         op += len;
00510         p = (const flzuint16*) ref;
00511         for(len>>=1; len > 4; len-=4)
00512         {
00513           *q++ = *p++;
00514           *q++ = *p++;
00515           *q++ = *p++;
00516           *q++ = *p++;
00517         }
00518         for(; len; --len)
00519           *q++ = *p++;
00520 #else
00521         for(; len; --len)
00522           *op++ = *ref++;
00523 #endif
00524       }
00525     }
00526     else
00527     {
00528       ctrl++;
00529 #ifdef FASTLZ_SAFE
00530       if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
00531         return 0;
00532       if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
00533         return 0;
00534 #endif
00535 
00536       *op++ = *ip++;
00537       for(--ctrl; ctrl; ctrl--)
00538         *op++ = *ip++;
00539 
00540       loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
00541       if(loop)
00542         ctrl = *ip++;
00543     }
00544   }
00545   while(FASTLZ_EXPECT_CONDITIONAL(loop));
00546 
00547   return op - (flzuint8*)output;
00548 }
00549 
00550 #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */

Generated by  doxygen 1.7.1