Back to index

plt-scheme  4.2.1
inffast.c
Go to the documentation of this file.
00001 /* inffast.c -- process literals and length/distance pairs fast
00002  * Copyright (C) 1995-2002 Mark Adler
00003  * For conditions of distribution and use, see copyright notice in zlib.h 
00004  */
00005 
00006 #include "zutil.h"
00007 #include "inftrees.h"
00008 #include "infblock.h"
00009 #include "infcodes.h"
00010 #include "infutil.h"
00011 #include "inffast.h"
00012 
00013 struct inflate_codes_state {int dummy;}; /* for buggy compilers */
00014 
00015 /* simplify the use of the inflate_huft type with some defines */
00016 #define exop word.what.Exop
00017 #define bits word.what.Bits
00018 
00019 /* macros for bit input with no checking and for returning unused bytes */
00020 #define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
00021 #define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
00022 
00023 /* Called with number of bytes left to write in window at least 258
00024    (the maximum string length) and number of input bytes available
00025    at least ten.  The ten bytes are six bytes for the longest length/
00026    distance pair plus four bytes for overloading the bit buffer. */
00027 
00028 int inflate_fast(bl, bd, tl, td, s, z)
00029 uInt bl, bd;
00030 inflate_huft *tl;
00031 inflate_huft *td; /* need separate declaration for Borland C++ */
00032 inflate_blocks_statef *s;
00033 z_streamp z;
00034 {
00035   inflate_huft *t;      /* temporary pointer */
00036   uInt e;               /* extra bits or operation */
00037   uLong b;              /* bit buffer */
00038   uInt k;               /* bits in bit buffer */
00039   Bytef *p;             /* input data pointer */
00040   uInt n;               /* bytes available there */
00041   Bytef *q;             /* output window write pointer */
00042   uInt m;               /* bytes to end of window or read pointer */
00043   uInt ml;              /* mask for literal/length tree */
00044   uInt md;              /* mask for distance tree */
00045   uInt c;               /* bytes to copy */
00046   uInt d;               /* distance back to copy from */
00047   Bytef *r;             /* copy source pointer */
00048 
00049   /* load input, output, bit values */
00050   LOAD
00051 
00052   /* initialize masks */
00053   ml = inflate_mask[bl];
00054   md = inflate_mask[bd];
00055 
00056   /* do until not enough input or output space for fast loop */
00057   do {                          /* assume called with m >= 258 && n >= 10 */
00058     /* get literal/length code */
00059     GRABBITS(20)                /* max bits for literal/length code */
00060     if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
00061     {
00062       DUMPBITS(t->bits)
00063       Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
00064                 "inflate:         * literal '%c'\n" :
00065                 "inflate:         * literal 0x%02x\n", t->base));
00066       *q++ = (Byte)t->base;
00067       m--;
00068       continue;
00069     }
00070     do {
00071       DUMPBITS(t->bits)
00072       if (e & 16)
00073       {
00074         /* get extra bits for length */
00075         e &= 15;
00076         c = t->base + ((uInt)b & inflate_mask[e]);
00077         DUMPBITS(e)
00078         Tracevv((stderr, "inflate:         * length %u\n", c));
00079 
00080         /* decode distance base of block to copy */
00081         GRABBITS(15);           /* max bits for distance code */
00082         e = (t = td + ((uInt)b & md))->exop;
00083         do {
00084           DUMPBITS(t->bits)
00085           if (e & 16)
00086           {
00087             /* get extra bits to add to distance base */
00088             e &= 15;
00089             GRABBITS(e)         /* get extra bits (up to 13) */
00090             d = t->base + ((uInt)b & inflate_mask[e]);
00091             DUMPBITS(e)
00092             Tracevv((stderr, "inflate:         * distance %u\n", d));
00093 
00094             /* do the copy */
00095             m -= c;
00096             r = q - d;
00097             if (r < s->window)                  /* wrap if needed */
00098             {
00099               do {
00100                 r += s->end - s->window;        /* force pointer in window */
00101               } while (r < s->window);          /* covers invalid distances */
00102               e = s->end - r;
00103               if (c > e)
00104               {
00105                 c -= e;                         /* wrapped copy */
00106                 do {
00107                     *q++ = *r++;
00108                 } while (--e);
00109                 r = s->window;
00110                 do {
00111                     *q++ = *r++;
00112                 } while (--c);
00113               }
00114               else                              /* normal copy */
00115               {
00116                 *q++ = *r++;  c--;
00117                 *q++ = *r++;  c--;
00118                 do {
00119                     *q++ = *r++;
00120                 } while (--c);
00121               }
00122             }
00123             else                                /* normal copy */
00124             {
00125               *q++ = *r++;  c--;
00126               *q++ = *r++;  c--;
00127               do {
00128                 *q++ = *r++;
00129               } while (--c);
00130             }
00131             break;
00132           }
00133           else if ((e & 64) == 0)
00134           {
00135             t += t->base;
00136             e = (t += ((uInt)b & inflate_mask[e]))->exop;
00137           }
00138           else
00139           {
00140             z->msg = (char*)"invalid distance code";
00141             UNGRAB
00142             UPDATE
00143             return Z_DATA_ERROR;
00144           }
00145         } while (1);
00146         break;
00147       }
00148       if ((e & 64) == 0)
00149       {
00150         t += t->base;
00151         if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
00152         {
00153           DUMPBITS(t->bits)
00154           Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
00155                     "inflate:         * literal '%c'\n" :
00156                     "inflate:         * literal 0x%02x\n", t->base));
00157           *q++ = (Byte)t->base;
00158           m--;
00159           break;
00160         }
00161       }
00162       else if (e & 32)
00163       {
00164         Tracevv((stderr, "inflate:         * end of block\n"));
00165         UNGRAB
00166         UPDATE
00167         return Z_STREAM_END;
00168       }
00169       else
00170       {
00171         z->msg = (char*)"invalid literal/length code";
00172         UNGRAB
00173         UPDATE
00174         return Z_DATA_ERROR;
00175       }
00176     } while (1);
00177   } while (m >= 258 && n >= 10);
00178 
00179   /* not enough input or output--restore pointers and return */
00180   UNGRAB
00181   UPDATE
00182   return Z_OK;
00183 }