ReactOS Fundraising Campaign 2012
 
€ 3,303 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

fdi.c

Go to the documentation of this file.
00001 /*
00002  * File Decompression Interface
00003  *
00004  * Copyright 2000-2002 Stuart Caie
00005  * Copyright 2002 Patrik Stridvall
00006  * Copyright 2003 Greg Turner
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  *
00022  *
00023  * This is a largely redundant reimplementation of the stuff in cabextract.c.  It
00024  * would be theoretically preferable to have only one, shared implementation, however
00025  * there are semantic differences which may discourage efforts to unify the two.  It
00026  * should be possible, if awkward, to go back and reimplement cabextract.c using FDI.
00027  * But this approach would be quite a bit less performant.  Probably a better way
00028  * would be to create a "library" of routines in cabextract.c which do the actual
00029  * decompression, and have both fdi.c and cabextract share those routines.  The rest
00030  * of the code is not sufficiently similar to merit a shared implementation.
00031  *
00032  * The worst thing about this API is the bug.  "The bug" is this: when you extract a
00033  * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that
00034  * there is no subsequent cabinet, even if there is one.  wine faithfully reproduces
00035  * this behavior.
00036  *
00037  * TODO:
00038  *
00039  * Wine does not implement the AFAIK undocumented "enumerate" callback during
00040  * FDICopy.  It is implemented in Windows and therefore worth investigating...
00041  *
00042  * Lots of pointers flying around here... am I leaking RAM?
00043  *
00044  * WTF is FDITruncate?
00045  *
00046  * Probably, I need to weed out some dead code-paths.
00047  *
00048  * Test unit(s).
00049  *
00050  * The fdintNEXT_CABINET callbacks are probably not working quite as they should.
00051  * There are several FIXMEs in the source describing some of the deficiencies in
00052  * some detail.  Additionally, we do not do a very good job of returning the right
00053  * error codes to this callback.
00054  *
00055  * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller
00056  * functions would be nice.
00057  *
00058  *   -gmt
00059  */
00060 
00061 #include "config.h"
00062 
00063 #include <stdarg.h>
00064 #include <stdio.h>
00065 
00066 #include "windef.h"
00067 #include "winbase.h"
00068 #include "winerror.h"
00069 #include "fdi.h"
00070 #include "cabinet.h"
00071 
00072 #include "wine/debug.h"
00073 
00074 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
00075 
00076 THOSE_ZIP_CONSTS;
00077 
00078 struct fdi_file {
00079   struct fdi_file *next;               /* next file in sequence          */
00080   LPSTR filename;                     /* output name of file            */
00081   int    fh;                           /* open file handle or NULL       */
00082   cab_ULONG length;                    /* uncompressed length of file    */
00083   cab_ULONG offset;                    /* uncompressed offset in folder  */
00084   cab_UWORD index;                     /* magic index number of folder   */
00085   cab_UWORD time, date, attribs;       /* MS-DOS time/date/attributes    */
00086   BOOL oppressed;                      /* never to be processed          */
00087 };
00088 
00089 struct fdi_folder {
00090   struct fdi_folder *next;
00091   cab_off_t offset;                    /* offset to data blocks (32 bit) */
00092   cab_UWORD comp_type;                 /* compression format/window size */
00093   cab_ULONG comp_size;                 /* compressed size of folder      */
00094   cab_UBYTE num_splits;                /* number of split blocks + 1     */
00095   cab_UWORD num_blocks;                /* total number of blocks         */
00096 };
00097 
00098 /*
00099  * this structure fills the gaps between what is available in a PFDICABINETINFO
00100  * vs what is needed by FDICopy.  Memory allocated for these becomes the responsibility
00101  * of the caller to free.  Yes, I am aware that this is totally, utterly inelegant.
00102  * To make things even more unnecessarily confusing, we now attach these to the
00103  * fdi_decomp_state.
00104  */
00105 typedef struct {
00106    char *prevname, *previnfo;
00107    char *nextname, *nextinfo;
00108    BOOL hasnext;  /* bug free indicator */
00109    int folder_resv, header_resv;
00110    cab_UBYTE block_resv;
00111 } MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;
00112 
00113 typedef struct
00114 {
00115   unsigned int magic;
00116   PFNALLOC     alloc;
00117   PFNFREE      free;
00118   PFNOPEN      open;
00119   PFNREAD      read;
00120   PFNWRITE     write;
00121   PFNCLOSE     close;
00122   PFNSEEK      seek;
00123   PERF         perf;
00124 } FDI_Int;
00125 
00126 #define FDI_INT_MAGIC 0xfdfdfd05
00127 
00128 /*
00129  * ugh, well, this ended up being pretty damn silly...
00130  * now that I've conceded to build equivalent structures to struct cab.*,
00131  * I should have just used those, or, better yet, unified the two... sue me.
00132  * (Note to Microsoft: That's a joke.  Please /don't/ actually sue me! -gmt).
00133  * Nevertheless, I've come this far, it works, so I'm not gonna change it
00134  * for now.  This implementation has significant semantic differences anyhow.
00135  */
00136 
00137 typedef struct fdi_cds_fwd {
00138   FDI_Int *fdi;                    /* the hfdi we are using                 */
00139   INT_PTR filehf, cabhf;           /* file handle we are using              */
00140   struct fdi_folder *current;      /* current folder we're extracting from  */
00141   cab_ULONG offset;                /* uncompressed offset within folder     */
00142   cab_UBYTE *outpos;               /* (high level) start of data to use up  */
00143   cab_UWORD outlen;                /* (high level) amount of data to use up */
00144   int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn  */
00145   cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows!       */
00146   cab_UBYTE outbuf[CAB_BLOCKMAX];
00147   union {
00148     struct ZIPstate zip;
00149     struct QTMstate qtm;
00150     struct LZXstate lzx;
00151   } methods;
00152   /* some temp variables for use during decompression */
00153   cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
00154   cab_ULONG q_position_base[42];
00155   cab_ULONG lzx_position_base[51];
00156   cab_UBYTE extra_bits[51];
00157   USHORT  setID;                   /* Cabinet set ID */
00158   USHORT  iCabinet;                /* Cabinet number in set (0 based) */
00159   struct fdi_cds_fwd *decomp_cab;
00160   MORE_ISCAB_INFO mii;
00161   struct fdi_folder *firstfol; 
00162   struct fdi_file   *firstfile;
00163   struct fdi_cds_fwd *next;
00164 } fdi_decomp_state;
00165 
00166 #define ZIPNEEDBITS(n) {while(k<(n)){cab_LONG c=*(ZIP(inpos)++);\
00167     b|=((cab_ULONG)c)<<k;k+=8;}}
00168 #define ZIPDUMPBITS(n) {b>>=(n);k-=(n);}
00169 
00170 /* endian-neutral reading of little-endian data */
00171 #define EndGetI32(a)  ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0]))
00172 #define EndGetI16(a)  ((((a)[1])<<8)|((a)[0]))
00173 
00174 #define CAB(x) (decomp_state->x)
00175 #define ZIP(x) (decomp_state->methods.zip.x)
00176 #define QTM(x) (decomp_state->methods.qtm.x)
00177 #define LZX(x) (decomp_state->methods.lzx.x)
00178 #define DECR_OK           (0)
00179 #define DECR_DATAFORMAT   (1)
00180 #define DECR_ILLEGALDATA  (2)
00181 #define DECR_NOMEMORY     (3)
00182 #define DECR_CHECKSUM     (4)
00183 #define DECR_INPUT        (5)
00184 #define DECR_OUTPUT       (6)
00185 #define DECR_USERABORT    (7)
00186 
00187 static void set_error( FDI_Int *fdi, int oper, int err )
00188 {
00189     fdi->perf->erfOper = oper;
00190     fdi->perf->erfType = err;
00191     fdi->perf->fError = TRUE;
00192     if (err) SetLastError( err );
00193 }
00194 
00195 static FDI_Int *get_fdi_ptr( HFDI hfdi )
00196 {
00197     FDI_Int *fdi= (FDI_Int *)hfdi;
00198 
00199     if (!fdi || fdi->magic != FDI_INT_MAGIC)
00200     {
00201         SetLastError( ERROR_INVALID_HANDLE );
00202         return NULL;
00203     }
00204     return fdi;
00205 }
00206 
00207 /****************************************************************
00208  * QTMupdatemodel (internal)
00209  */
00210 static void QTMupdatemodel(struct QTMmodel *model, int sym) {
00211   struct QTMmodelsym temp;
00212   int i, j;
00213 
00214   for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8;
00215 
00216   if (model->syms[0].cumfreq > 3800) {
00217     if (--model->shiftsleft) {
00218       for (i = model->entries - 1; i >= 0; i--) {
00219         /* -1, not -2; the 0 entry saves this */
00220         model->syms[i].cumfreq >>= 1;
00221         if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
00222           model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
00223         }
00224       }
00225     }
00226     else {
00227       model->shiftsleft = 50;
00228       for (i = 0; i < model->entries ; i++) {
00229         /* no -1, want to include the 0 entry */
00230         /* this converts cumfreqs into frequencies, then shifts right */
00231         model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
00232         model->syms[i].cumfreq++; /* avoid losing things entirely */
00233         model->syms[i].cumfreq >>= 1;
00234       }
00235 
00236       /* now sort by frequencies, decreasing order -- this must be an
00237        * inplace selection sort, or a sort with the same (in)stability
00238        * characteristics
00239        */
00240       for (i = 0; i < model->entries - 1; i++) {
00241         for (j = i + 1; j < model->entries; j++) {
00242           if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
00243             temp = model->syms[i];
00244             model->syms[i] = model->syms[j];
00245             model->syms[j] = temp;
00246           }
00247         }
00248       }
00249 
00250       /* then convert frequencies back to cumfreq */
00251       for (i = model->entries - 1; i >= 0; i--) {
00252         model->syms[i].cumfreq += model->syms[i+1].cumfreq;
00253       }
00254       /* then update the other part of the table */
00255       for (i = 0; i < model->entries; i++) {
00256         model->tabloc[model->syms[i].sym] = i;
00257       }
00258     }
00259   }
00260 }
00261 
00262 /*************************************************************************
00263  * make_decode_table (internal)
00264  *
00265  * This function was coded by David Tritscher. It builds a fast huffman
00266  * decoding table out of just a canonical huffman code lengths table.
00267  *
00268  * PARAMS
00269  *   nsyms:  total number of symbols in this huffman tree.
00270  *   nbits:  any symbols with a code length of nbits or less can be decoded
00271  *           in one lookup of the table.
00272  *   length: A table to get code lengths from [0 to syms-1]
00273  *   table:  The table to fill up with decoded symbols and pointers.
00274  *
00275  * RETURNS
00276  *   OK:    0
00277  *   error: 1
00278  */
00279 static int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits,
00280                              const cab_UBYTE *length, cab_UWORD *table) {
00281   register cab_UWORD sym;
00282   register cab_ULONG leaf;
00283   register cab_UBYTE bit_num = 1;
00284   cab_ULONG fill;
00285   cab_ULONG pos         = 0; /* the current position in the decode table */
00286   cab_ULONG table_mask  = 1 << nbits;
00287   cab_ULONG bit_mask    = table_mask >> 1; /* don't do 0 length codes */
00288   cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */
00289 
00290   /* fill entries for codes short enough for a direct mapping */
00291   while (bit_num <= nbits) {
00292     for (sym = 0; sym < nsyms; sym++) {
00293       if (length[sym] == bit_num) {
00294         leaf = pos;
00295 
00296         if((pos += bit_mask) > table_mask) return 1; /* table overrun */
00297 
00298         /* fill all possible lookups of this symbol with the symbol itself */
00299         fill = bit_mask;
00300         while (fill-- > 0) table[leaf++] = sym;
00301       }
00302     }
00303     bit_mask >>= 1;
00304     bit_num++;
00305   }
00306 
00307   /* if there are any codes longer than nbits */
00308   if (pos != table_mask) {
00309     /* clear the remainder of the table */
00310     for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
00311 
00312     /* give ourselves room for codes to grow by up to 16 more bits */
00313     pos <<= 16;
00314     table_mask <<= 16;
00315     bit_mask = 1 << 15;
00316 
00317     while (bit_num <= 16) {
00318       for (sym = 0; sym < nsyms; sym++) {
00319         if (length[sym] == bit_num) {
00320           leaf = pos >> 16;
00321           for (fill = 0; fill < bit_num - nbits; fill++) {
00322             /* if this path hasn't been taken yet, 'allocate' two entries */
00323             if (table[leaf] == 0) {
00324               table[(next_symbol << 1)] = 0;
00325               table[(next_symbol << 1) + 1] = 0;
00326               table[leaf] = next_symbol++;
00327             }
00328             /* follow the path and select either left or right for next bit */
00329             leaf = table[leaf] << 1;
00330             if ((pos >> (15-fill)) & 1) leaf++;
00331           }
00332           table[leaf] = sym;
00333 
00334           if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
00335         }
00336       }
00337       bit_mask >>= 1;
00338       bit_num++;
00339     }
00340   }
00341 
00342   /* full table? */
00343   if (pos == table_mask) return 0;
00344 
00345   /* either erroneous table, or all elements are 0 - let's find out. */
00346   for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
00347   return 0;
00348 }
00349 
00350 /*************************************************************************
00351  * checksum (internal)
00352  */
00353 static cab_ULONG checksum(const cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) {
00354   int len;
00355   cab_ULONG ul = 0;
00356 
00357   for (len = bytes >> 2; len--; data += 4) {
00358     csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
00359   }
00360 
00361   switch (bytes & 3) {
00362   case 3: ul |= *data++ << 16;
00363   /* fall through */
00364   case 2: ul |= *data++ <<  8;
00365   /* fall through */
00366   case 1: ul |= *data;
00367   }
00368   csum ^= ul;
00369 
00370   return csum;
00371 }
00372 
00373 /***********************************************************************
00374  *      FDICreate (CABINET.20)
00375  *
00376  * Provided with several callbacks (all of them are mandatory),
00377  * returns a handle which can be used to perform operations
00378  * on cabinet files.
00379  *
00380  * PARAMS
00381  *   pfnalloc [I]  A pointer to a function which allocates ram.  Uses
00382  *                 the same interface as malloc.
00383  *   pfnfree  [I]  A pointer to a function which frees ram.  Uses the
00384  *                 same interface as free.
00385  *   pfnopen  [I]  A pointer to a function which opens a file.  Uses
00386  *                 the same interface as _open.
00387  *   pfnread  [I]  A pointer to a function which reads from a file into
00388  *                 a caller-provided buffer.  Uses the same interface
00389  *                 as _read
00390  *   pfnwrite [I]  A pointer to a function which writes to a file from
00391  *                 a caller-provided buffer.  Uses the same interface
00392  *                 as _write.
00393  *   pfnclose [I]  A pointer to a function which closes a file handle.
00394  *                 Uses the same interface as _close.
00395  *   pfnseek  [I]  A pointer to a function which seeks in a file.
00396  *                 Uses the same interface as _lseek.
00397  *   cpuType  [I]  The type of CPU; ignored in wine (recommended value:
00398  *                 cpuUNKNOWN, aka -1).
00399  *   perf     [IO] A pointer to an ERF structure.  When FDICreate
00400  *                 returns an error condition, error information may
00401  *                 be found here as well as from GetLastError.
00402  *
00403  * RETURNS
00404  *   On success, returns an FDI handle of type HFDI.
00405  *   On failure, the NULL file handle is returned. Error
00406  *   info can be retrieved from perf.
00407  *
00408  * INCLUDES
00409  *   fdi.h
00410  * 
00411  */
00412 HFDI __cdecl FDICreate(
00413     PFNALLOC pfnalloc,
00414     PFNFREE  pfnfree,
00415     PFNOPEN  pfnopen,
00416     PFNREAD  pfnread,
00417     PFNWRITE pfnwrite,
00418     PFNCLOSE pfnclose,
00419     PFNSEEK  pfnseek,
00420     int      cpuType,
00421     PERF     perf)
00422 {
00423   FDI_Int *fdi;
00424 
00425   TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, "
00426         "pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n",
00427         pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek,
00428         cpuType, perf);
00429 
00430   if ((!pfnalloc) || (!pfnfree)) {
00431     perf->erfOper = FDIERROR_NONE;
00432     perf->erfType = ERROR_BAD_ARGUMENTS;
00433     perf->fError = TRUE;
00434 
00435     SetLastError(ERROR_BAD_ARGUMENTS);
00436     return NULL;
00437   }
00438 
00439   if (!((fdi = pfnalloc(sizeof(FDI_Int))))) {
00440     perf->erfOper = FDIERROR_ALLOC_FAIL;
00441     perf->erfType = 0;
00442     perf->fError = TRUE;
00443     return NULL;
00444   }
00445 
00446   fdi->magic = FDI_INT_MAGIC;
00447   fdi->alloc = pfnalloc;
00448   fdi->free  = pfnfree;
00449   fdi->open  = pfnopen;
00450   fdi->read  = pfnread;
00451   fdi->write = pfnwrite;
00452   fdi->close = pfnclose;
00453   fdi->seek  = pfnseek;
00454   /* no-brainer: we ignore the cpu type; this is only used
00455      for the 16-bit versions in Windows anyhow... */
00456   fdi->perf = perf;
00457 
00458   return (HFDI)fdi;
00459 }
00460 
00461 /*******************************************************************
00462  * FDI_getoffset (internal)
00463  *
00464  * returns the file pointer position of a file handle.
00465  */
00466 static LONG FDI_getoffset(FDI_Int *fdi, INT_PTR hf)
00467 {
00468   return fdi->seek(hf, 0, SEEK_CUR);
00469 }
00470 
00471 /**********************************************************************
00472  * FDI_read_string (internal)
00473  *
00474  * allocate and read an arbitrarily long string from the cabinet
00475  */
00476 static char *FDI_read_string(FDI_Int *fdi, INT_PTR hf, long cabsize)
00477 {
00478   size_t len=256,
00479          base = FDI_getoffset(fdi, hf),
00480          maxlen = cabsize - base;
00481   BOOL ok = FALSE;
00482   unsigned int i;
00483   cab_UBYTE *buf = NULL;
00484 
00485   TRACE("(fdi == %p, hf == %ld, cabsize == %ld)\n", fdi, hf, cabsize);
00486 
00487   do {
00488     if (len > maxlen) len = maxlen;
00489     if (!(buf = fdi->alloc(len))) break;
00490     if (!fdi->read(hf, buf, len)) break;
00491 
00492     /* search for a null terminator in what we've just read */
00493     for (i=0; i < len; i++) {
00494       if (!buf[i]) {ok=TRUE; break;}
00495     }
00496 
00497     if (!ok) {
00498       if (len == maxlen) {
00499         ERR("cabinet is truncated\n");
00500         break;
00501       }
00502       /* The buffer is too small for the string. Reset the file to the point
00503        * were we started, free the buffer and increase the size for the next try
00504        */
00505       fdi->seek(hf, base, SEEK_SET);
00506       fdi->free(buf);
00507       buf = NULL;
00508       len *= 2;
00509     }
00510   } while (!ok);
00511 
00512   if (!ok) {
00513     if (buf)
00514       fdi->free(buf);
00515     else
00516       ERR("out of memory!\n");
00517     return NULL;
00518   }
00519 
00520   /* otherwise, set the stream to just after the string and return */
00521   fdi->seek(hf, base + strlen((char *)buf) + 1, SEEK_SET);
00522 
00523   return (char *) buf;
00524 }
00525 
00526 /******************************************************************
00527  * FDI_read_entries (internal)
00528  *
00529  * process the cabinet header in the style of FDIIsCabinet, but
00530  * without the sanity checks (and bug)
00531  */
00532 static BOOL FDI_read_entries(
00533         FDI_Int         *fdi,
00534         INT_PTR          hf,
00535         PFDICABINETINFO  pfdici,
00536         PMORE_ISCAB_INFO pmii)
00537 {
00538   int num_folders, num_files, header_resv, folder_resv = 0;
00539   LONG base_offset, cabsize;
00540   USHORT setid, cabidx, flags;
00541   cab_UBYTE buf[64], block_resv;
00542   char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL;
00543 
00544   TRACE("(fdi == ^%p, hf == %ld, pfdici == ^%p)\n", fdi, hf, pfdici);
00545 
00546   /* 
00547    * FIXME: I just noticed that I am memorizing the initial file pointer
00548    * offset and restoring it before reading in the rest of the header
00549    * information in the cabinet.  Perhaps that's correct -- that is, perhaps
00550    * this API is supposed to support "streaming" cabinets which are embedded
00551    * in other files, or cabinets which begin at file offsets other than zero.
00552    * Otherwise, I should instead go to the absolute beginning of the file.
00553    * (Either way, the semantics of wine's FDICopy require me to leave the
00554    * file pointer where it is afterwards -- If Windows does not do so, we
00555    * ought to duplicate the native behavior in the FDIIsCabinet API, not here.
00556    * 
00557    * So, the answer lies in Windows; will native cabinet.dll recognize a
00558    * cabinet "file" embedded in another file?  Note that cabextract.c does
00559    * support this, which implies that Microsoft's might.  I haven't tried it
00560    * yet so I don't know.  ATM, most of wine's FDI cabinet routines (except
00561    * this one) would not work in this way.  To fix it, we could just make the
00562    * various references to absolute file positions in the code relative to an
00563    * initial "beginning" offset.  Because the FDICopy API doesn't take a
00564    * file-handle like this one, we would therein need to search through the
00565    * file for the beginning of the cabinet (as we also do in cabextract.c).
00566    * Note that this limits us to a maximum of one cabinet per. file: the first.
00567    *
00568    * So, in summary: either the code below is wrong, or the rest of fdi.c is
00569    * wrong... I cannot imagine that both are correct ;)  One of these flaws
00570    * should be fixed after determining the behavior on Windows.   We ought
00571    * to check both FDIIsCabinet and FDICopy for the right behavior.
00572    *
00573    * -gmt
00574    */
00575 
00576   /* get basic offset & size info */
00577   base_offset = FDI_getoffset(fdi, hf);
00578 
00579   if (fdi->seek(hf, 0, SEEK_END) == -1) {
00580     if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
00581     return FALSE;
00582   }
00583 
00584   cabsize = FDI_getoffset(fdi, hf);
00585 
00586   if ((cabsize == -1) || (base_offset == -1) || 
00587       ( fdi->seek(hf, base_offset, SEEK_SET) == -1 )) {
00588     if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
00589     return FALSE;
00590   }
00591 
00592   /* read in the CFHEADER */
00593   if (fdi->read(hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) {
00594     if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
00595     return FALSE;
00596   }
00597   
00598   /* check basic MSCF signature */
00599   if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) {
00600     if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
00601     return FALSE;
00602   }
00603 
00604   /* get the number of folders */
00605   num_folders = EndGetI16(buf+cfhead_NumFolders);
00606 
00607   /* get the number of files */
00608   num_files = EndGetI16(buf+cfhead_NumFiles);
00609 
00610   /* setid */
00611   setid = EndGetI16(buf+cfhead_SetID);
00612 
00613   /* cabinet (set) index */
00614   cabidx = EndGetI16(buf+cfhead_CabinetIndex);
00615 
00616   /* check the header revision */
00617   if ((buf[cfhead_MajorVersion] > 1) ||
00618       (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
00619   {
00620     WARN("cabinet format version > 1.3\n");
00621     if (pmii) set_error( fdi, FDIERROR_UNKNOWN_CABINET_VERSION, 0 /* ? */ );
00622     return FALSE;
00623   }
00624 
00625   /* pull the flags out */
00626   flags = EndGetI16(buf+cfhead_Flags);
00627 
00628   /* read the reserved-sizes part of header, if present */
00629   if (flags & cfheadRESERVE_PRESENT) {
00630     if (fdi->read(hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) {
00631       ERR("bunk reserve-sizes?\n");
00632       if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
00633       return FALSE;
00634     }
00635 
00636     header_resv = EndGetI16(buf+cfheadext_HeaderReserved);
00637     if (pmii) pmii->header_resv = header_resv;
00638     folder_resv = buf[cfheadext_FolderReserved];
00639     if (pmii) pmii->folder_resv = folder_resv;
00640     block_resv  = buf[cfheadext_DataReserved];
00641     if (pmii) pmii->block_resv = block_resv;
00642 
00643     if (header_resv > 60000) {
00644       WARN("WARNING; header reserved space > 60000\n");
00645     }
00646 
00647     /* skip the reserved header */
00648     if ((header_resv) && (fdi->seek(hf, header_resv, SEEK_CUR) == -1)) {
00649       ERR("seek failure: header_resv\n");
00650       if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
00651       return FALSE;
00652     }
00653   }
00654 
00655   if (flags & cfheadPREV_CABINET) {
00656     prevname = FDI_read_string(fdi, hf, cabsize);
00657     if (!prevname) {
00658       if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
00659       return FALSE;
00660     } else
00661       if (pmii)
00662         pmii->prevname = prevname;
00663       else
00664         fdi->free(prevname);
00665     previnfo = FDI_read_string(fdi, hf, cabsize);
00666     if (previnfo) {
00667       if (pmii) 
00668         pmii->previnfo = previnfo;
00669       else
00670         fdi->free(previnfo);
00671     }
00672   }
00673 
00674   if (flags & cfheadNEXT_CABINET) {
00675     if (pmii)
00676       pmii->hasnext = TRUE;
00677     nextname = FDI_read_string(fdi, hf, cabsize);
00678     if (!nextname) {
00679       if ((flags & cfheadPREV_CABINET) && pmii) {
00680         if (pmii->prevname) fdi->free(prevname);
00681         if (pmii->previnfo) fdi->free(previnfo);
00682       }
00683       set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
00684       return FALSE;
00685     } else
00686       if (pmii)
00687         pmii->nextname = nextname;
00688       else
00689         fdi->free(nextname);
00690     nextinfo = FDI_read_string(fdi, hf, cabsize);
00691     if (nextinfo) {
00692       if (pmii)
00693         pmii->nextinfo = nextinfo;
00694       else
00695         fdi->free(nextinfo);
00696     }
00697   }
00698 
00699   /* we could process the whole cabinet searching for problems;
00700      instead lets stop here.  Now let's fill out the paperwork */
00701   pfdici->cbCabinet = cabsize;
00702   pfdici->cFolders  = num_folders;
00703   pfdici->cFiles    = num_files;
00704   pfdici->setID     = setid;
00705   pfdici->iCabinet  = cabidx;
00706   pfdici->fReserve  = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE;
00707   pfdici->hasprev   = (flags & cfheadPREV_CABINET) ? TRUE : FALSE;
00708   pfdici->hasnext   = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE;
00709   return TRUE;
00710 }
00711 
00712 /***********************************************************************
00713  *      FDIIsCabinet (CABINET.21)
00714  *
00715  * Informs the caller as to whether or not the provided file handle is
00716  * really a cabinet or not, filling out the provided PFDICABINETINFO
00717  * structure with information about the cabinet.  Brief explanations of
00718  * the elements of this structure are available as comments accompanying
00719  * its definition in wine's include/fdi.h.
00720  *
00721  * PARAMS
00722  *   hfdi   [I]  An HFDI from FDICreate
00723  *   hf     [I]  The file handle about which the caller inquires
00724  *   pfdici [IO] Pointer to a PFDICABINETINFO structure which will
00725  *               be filled out with information about the cabinet
00726  *               file indicated by hf if, indeed, it is determined
00727  *               to be a cabinet.
00728  * 
00729  * RETURNS
00730  *   TRUE  if the file is a cabinet.  The info pointed to by pfdici will
00731  *         be provided.
00732  *   FALSE if the file is not a cabinet, or if an error was encountered
00733  *         while processing the cabinet.  The PERF structure provided to
00734  *         FDICreate can be queried for more error information.
00735  *
00736  * INCLUDES
00737  *   fdi.c
00738  */
00739 BOOL __cdecl FDIIsCabinet(
00740     HFDI            hfdi,
00741     INT_PTR         hf,
00742     PFDICABINETINFO pfdici)
00743 {
00744   BOOL rv;
00745   FDI_Int *fdi = get_fdi_ptr( hfdi );
00746 
00747   TRACE("(hfdi == ^%p, hf == ^%ld, pfdici == ^%p)\n", hfdi, hf, pfdici);
00748 
00749   if (!fdi) return FALSE;
00750 
00751   if (!hf) {
00752     ERR("(!hf)!\n");
00753     SetLastError(ERROR_INVALID_HANDLE);
00754     return FALSE;
00755   }
00756 
00757   if (!pfdici) {
00758     ERR("(!pfdici)!\n");
00759     SetLastError(ERROR_BAD_ARGUMENTS);
00760     return FALSE;
00761   }
00762   rv = FDI_read_entries(fdi, hf, pfdici, NULL);
00763 
00764   if (rv)
00765     pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */
00766 
00767   return rv;
00768 }
00769 
00770 /******************************************************************
00771  * QTMfdi_initmodel (internal)
00772  *
00773  * Initialize a model which decodes symbols from [s] to [s]+[n]-1
00774  */
00775 static void QTMfdi_initmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) {
00776   int i;
00777   m->shiftsleft = 4;
00778   m->entries    = n;
00779   m->syms       = sym;
00780   memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */
00781   for (i = 0; i < n; i++) {
00782     m->tabloc[i+s]     = i;   /* set up a look-up entry for symbol */
00783     m->syms[i].sym     = i+s; /* actual symbol */
00784     m->syms[i].cumfreq = n-i; /* current frequency of that symbol */
00785   }
00786   m->syms[n].cumfreq = 0;
00787 }
00788 
00789 /******************************************************************
00790  * QTMfdi_init (internal)
00791  */
00792 static int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
00793   unsigned int wndsize = 1 << window;
00794   int msz = window * 2, i;
00795   cab_ULONG j;
00796 
00797   /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
00798   /* if a previously allocated window is big enough, keep it    */
00799   if (window < 10 || window > 21) return DECR_DATAFORMAT;
00800   if (QTM(actual_size) < wndsize) {
00801     if (QTM(window)) CAB(fdi)->free(QTM(window));
00802     QTM(window) = NULL;
00803   }
00804   if (!QTM(window)) {
00805     if (!(QTM(window) = CAB(fdi)->alloc(wndsize))) return DECR_NOMEMORY;
00806     QTM(actual_size) = wndsize;
00807   }
00808   QTM(window_size) = wndsize;
00809   QTM(window_posn) = 0;
00810 
00811   /* initialize static slot/extrabits tables */
00812   for (i = 0, j = 0; i < 27; i++) {
00813     CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
00814     CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]);
00815   }
00816   for (i = 0, j = 0; i < 42; i++) {
00817     CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1;
00818     CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i];
00819   }
00820 
00821   /* initialize arithmetic coding models */
00822 
00823   QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0);
00824 
00825   QTMfdi_initmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00);
00826   QTMfdi_initmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40);
00827   QTMfdi_initmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80);
00828   QTMfdi_initmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0);
00829 
00830   /* model 4 depends on table size, ranges from 20 to 24  */
00831   QTMfdi_initmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0);
00832   /* model 5 depends on table size, ranges from 20 to 36  */
00833   QTMfdi_initmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0);
00834   /* model 6pos depends on table size, ranges from 20 to 42 */
00835   QTMfdi_initmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0);
00836   QTMfdi_initmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0);
00837 
00838   return DECR_OK;
00839 }
00840 
00841 /************************************************************
00842  * LZXfdi_init (internal)
00843  */
00844 static int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
00845   static const cab_UBYTE bits[]  =
00846                         { 0,  0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,
00847                           7,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
00848                          15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
00849                          17, 17, 17};
00850   static const cab_ULONG base[] =
00851                 {      0,       1,       2,       3,       4,       6,       8,      12,
00852                       16,      24,      32,      48,      64,      96,     128,     192,
00853                      256,     384,     512,     768,    1024,    1536,    2048,    3072,
00854                     4096,    6144,    8192,   12288,   16384,   24576,   32768,   49152,
00855                    65536,   98304,  131072,  196608,  262144,  393216,  524288,  655360,
00856                   786432,  917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
00857                  1835008, 1966080, 2097152};
00858   cab_ULONG wndsize = 1 << window;
00859   int posn_slots;
00860 
00861   /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
00862   /* if a previously allocated window is big enough, keep it     */
00863   if (window < 15 || window > 21) return DECR_DATAFORMAT;
00864   if (LZX(actual_size) < wndsize) {
00865     if (LZX(window)) CAB(fdi)->free(LZX(window));
00866     LZX(window) = NULL;
00867   }
00868   if (!LZX(window)) {
00869     if (!(LZX(window) = CAB(fdi)->alloc(wndsize))) return DECR_NOMEMORY;
00870     LZX(actual_size) = wndsize;
00871   }
00872   LZX(window_size) = wndsize;
00873 
00874   /* initialize static tables */
00875   memcpy(CAB(extra_bits), bits, sizeof(bits));
00876   memcpy(CAB(lzx_position_base), base, sizeof(base));
00877 
00878   /* calculate required position slots */
00879   if (window == 20) posn_slots = 42;
00880   else if (window == 21) posn_slots = 50;
00881   else posn_slots = window << 1;
00882 
00883   /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */
00884 
00885   LZX(R0)  =  LZX(R1)  = LZX(R2) = 1;
00886   LZX(main_elements)   = LZX_NUM_CHARS + (posn_slots << 3);
00887   LZX(header_read)     = 0;
00888   LZX(frames_read)     = 0;
00889   LZX(block_remaining) = 0;
00890   LZX(block_type)      = LZX_BLOCKTYPE_INVALID;
00891   LZX(intel_curpos)    = 0;
00892   LZX(intel_started)   = 0;
00893   LZX(window_posn)     = 0;
00894 
00895   /* initialize tables to 0 (because deltas will be applied to them) */
00896   memset(LZX(MAINTREE_len), 0, sizeof(LZX(MAINTREE_len)));
00897   memset(LZX(LENGTH_len), 0, sizeof(LZX(LENGTH_len)));
00898 
00899   return DECR_OK;
00900 }
00901 
00902 /****************************************************
00903  * NONEfdi_decomp(internal)
00904  */
00905 static int NONEfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
00906 {
00907   if (inlen != outlen) return DECR_ILLEGALDATA;
00908   if (outlen > CAB_BLOCKMAX) return DECR_DATAFORMAT;
00909   memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen);
00910   return DECR_OK;
00911 }
00912 
00913 /********************************************************
00914  * Ziphuft_free (internal)
00915  */
00916 static void fdi_Ziphuft_free(FDI_Int *fdi, struct Ziphuft *t)
00917 {
00918   register struct Ziphuft *p, *q;
00919 
00920   /* Go through linked list, freeing from the allocated (t[-1]) address. */
00921   p = t;
00922   while (p != NULL)
00923   {
00924     q = (--p)->v.t;
00925     fdi->free(p);
00926     p = q;
00927   } 
00928 }
00929 
00930 /*********************************************************
00931  * fdi_Ziphuft_build (internal)
00932  */
00933 static cab_LONG fdi_Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, const cab_UWORD *d, const cab_UWORD *e,
00934 struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state)
00935 {
00936   cab_ULONG a;                      /* counter for codes of length k */
00937   cab_ULONG el;                     /* length of EOB code (value 256) */
00938   cab_ULONG f;                      /* i repeats in table every f entries */
00939   cab_LONG g;                       /* maximum code length */
00940   cab_LONG h;                       /* table level */
00941   register cab_ULONG i;             /* counter, current code */
00942   register cab_ULONG j;             /* counter */
00943   register cab_LONG k;              /* number of bits in current code */
00944   cab_LONG *l;                      /* stack of bits per table */
00945   register cab_ULONG *p;            /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */
00946   register struct Ziphuft *q;           /* points to current table */
00947   struct Ziphuft r;                     /* table entry for structure assignment */
00948   register cab_LONG w;                  /* bits before this table == (l * h) */
00949   cab_ULONG *xp;                    /* pointer into x */
00950   cab_LONG y;                           /* number of dummy codes added */
00951   cab_ULONG z;                      /* number of entries in current table */
00952 
00953   l = ZIP(lx)+1;
00954 
00955   /* Generate counts for each bit length */
00956   el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
00957 
00958   for(i = 0; i < ZIPBMAX+1; ++i)
00959     ZIP(c)[i] = 0;
00960   p = b;  i = n;
00961   do
00962   {
00963     ZIP(c)[*p]++; p++;               /* assume all entries <= ZIPBMAX */
00964   } while (--i);
00965   if (ZIP(c)[0] == n)                /* null input--all zero length codes */
00966   {
00967     *t = NULL;
00968     *m = 0;
00969     return 0;
00970   }
00971 
00972   /* Find minimum and maximum length, bound *m by those */
00973   for (j = 1; j <= ZIPBMAX; j++)
00974     if (ZIP(c)[j])
00975       break;
00976   k = j;                        /* minimum code length */
00977   if ((cab_ULONG)*m < j)
00978     *m = j;
00979   for (i = ZIPBMAX; i; i--)
00980     if (ZIP(c)[i])
00981       break;
00982   g = i;                        /* maximum code length */
00983   if ((cab_ULONG)*m > i)
00984     *m = i;
00985 
00986   /* Adjust last length count to fill out codes, if needed */
00987   for (y = 1 << j; j < i; j++, y <<= 1)
00988     if ((y -= ZIP(c)[j]) < 0)
00989       return 2;                 /* bad input: more codes than bits */
00990   if ((y -= ZIP(c)[i]) < 0)
00991     return 2;
00992   ZIP(c)[i] += y;
00993 
00994   /* Generate starting offsets LONGo the value table for each length */
00995   ZIP(x)[1] = j = 0;
00996   p = ZIP(c) + 1;  xp = ZIP(x) + 2;
00997   while (--i)
00998   {                 /* note that i == g from above */
00999     *xp++ = (j += *p++);
01000   }
01001 
01002   /* Make a table of values in order of bit lengths */
01003   p = b;  i = 0;
01004   do{
01005     if ((j = *p++) != 0)
01006       ZIP(v)[ZIP(x)[j]++] = i;
01007   } while (++i < n);
01008 
01009 
01010   /* Generate the Huffman codes and for each, make the table entries */
01011   ZIP(x)[0] = i = 0;                 /* first Huffman code is zero */
01012   p = ZIP(v);                        /* grab values in bit order */
01013   h = -1;                       /* no tables yet--level -1 */
01014   w = l[-1] = 0;                /* no bits decoded yet */
01015   ZIP(u)[0] = NULL;             /* just to keep compilers happy */
01016   q = NULL;                     /* ditto */
01017   z = 0;                        /* ditto */
01018 
01019   /* go through the bit lengths (k already is bits in shortest code) */
01020   for (; k <= g; k++)
01021   {
01022     a = ZIP(c)[k];
01023     while (a--)
01024     {
01025       /* here i is the Huffman code of length k bits for value *p */
01026       /* make tables up to required level */
01027       while (k > w + l[h])
01028       {
01029         w += l[h++];            /* add bits already decoded */
01030 
01031         /* compute minimum size table less than or equal to *m bits */
01032         if ((z = g - w) > (cab_ULONG)*m)    /* upper limit */
01033           z = *m;
01034         if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
01035         {                       /* too few codes for k-w bit table */
01036           f -= a + 1;           /* deduct codes from patterns left */
01037           xp = ZIP(c) + k;
01038           while (++j < z)       /* try smaller tables up to z bits */
01039           {
01040             if ((f <<= 1) <= *++xp)
01041               break;            /* enough codes to use up j bits */
01042             f -= *xp;           /* else deduct codes from patterns */
01043           }
01044         }
01045         if ((cab_ULONG)w + j > el && (cab_ULONG)w < el)
01046           j = el - w;           /* make EOB code end at table */
01047         z = 1 << j;             /* table entries for j-bit table */
01048         l[h] = j;               /* set table size in stack */
01049 
01050         /* allocate and link in new table */
01051         if (!(q = CAB(fdi)->alloc((z + 1)*sizeof(struct Ziphuft))))
01052         {
01053           if(h)
01054             fdi_Ziphuft_free(CAB(fdi), ZIP(u)[0]);
01055           return 3;             /* not enough memory */
01056         }
01057         *t = q + 1;             /* link to list for Ziphuft_free() */
01058         *(t = &(q->v.t)) = NULL;
01059         ZIP(u)[h] = ++q;             /* table starts after link */
01060 
01061         /* connect to last table, if there is one */
01062         if (h)
01063         {
01064           ZIP(x)[h] = i;              /* save pattern for backing up */
01065           r.b = (cab_UBYTE)l[h-1];    /* bits to dump before this table */
01066           r.e = (cab_UBYTE)(16 + j);  /* bits in this table */
01067           r.v.t = q;                  /* pointer to this table */
01068           j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
01069           ZIP(u)[h-1][j] = r;        /* connect to last table */
01070         }
01071       }
01072 
01073       /* set up table entry in r */
01074       r.b = (cab_UBYTE)(k - w);
01075       if (p >= ZIP(v) + n)
01076         r.e = 99;               /* out of values--invalid code */
01077       else if (*p < s)
01078       {
01079         r.e = (cab_UBYTE)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
01080         r.v.n = *p++;           /* simple code is just the value */
01081       }
01082       else
01083       {
01084         r.e = (cab_UBYTE)e[*p - s];   /* non-simple--look up in lists */
01085         r.v.n = d[*p++ - s];
01086       }
01087 
01088       /* fill code-like entries with r */
01089       f = 1 << (k - w);
01090       for (j = i >> w; j < z; j += f)
01091         q[j] = r;
01092 
01093       /* backwards increment the k-bit code i */
01094       for (j = 1 << (k - 1); i & j; j >>= 1)
01095         i ^= j;
01096       i ^= j;
01097 
01098       /* backup over finished tables */
01099       while ((i & ((1 << w) - 1)) != ZIP(x)[h])
01100         w -= l[--h];            /* don't need to update q */
01101     }
01102   }
01103 
01104   /* return actual size of base table */
01105   *m = l[0];
01106 
01107   /* Return true (1) if we were given an incomplete table */
01108   return y != 0 && g != 1;
01109 }
01110 
01111 /*********************************************************
01112  * fdi_Zipinflate_codes (internal)
01113  */
01114 static cab_LONG fdi_Zipinflate_codes(const struct Ziphuft *tl, const struct Ziphuft *td,
01115   cab_LONG bl, cab_LONG bd, fdi_decomp_state *decomp_state)
01116 {
01117   register cab_ULONG e;     /* table entry flag/number of extra bits */
01118   cab_ULONG n, d;           /* length and index for copy */
01119   cab_ULONG w;              /* current window position */
01120   const struct Ziphuft *t;  /* pointer to table entry */
01121   cab_ULONG ml, md;         /* masks for bl and bd bits */
01122   register cab_ULONG b;     /* bit buffer */
01123   register cab_ULONG k;     /* number of bits in bit buffer */
01124 
01125   /* make local copies of globals */
01126   b = ZIP(bb);                       /* initialize bit buffer */
01127   k = ZIP(bk);
01128   w = ZIP(window_posn);                       /* initialize window position */
01129 
01130   /* inflate the coded data */
01131   ml = Zipmask[bl];             /* precompute masks for speed */
01132   md = Zipmask[bd];
01133 
01134   for(;;)
01135   {
01136     ZIPNEEDBITS((cab_ULONG)bl)
01137     if((e = (t = tl + (b & ml))->e) > 16)
01138       do
01139       {
01140         if (e == 99)
01141           return 1;
01142         ZIPDUMPBITS(t->b)
01143         e -= 16;
01144         ZIPNEEDBITS(e)
01145       } while ((e = (t = t->v.t + (b & Zipmask[e]))->e) > 16);
01146     ZIPDUMPBITS(t->b)
01147     if (e == 16)                /* then it's a literal */
01148       CAB(outbuf)[w++] = (cab_UBYTE)t->v.n;
01149     else                        /* it's an EOB or a length */
01150     {
01151       /* exit if end of block */
01152       if(e == 15)
01153         break;
01154 
01155       /* get length of block to copy */
01156       ZIPNEEDBITS(e)
01157       n = t->v.n + (b & Zipmask[e]);
01158       ZIPDUMPBITS(e);
01159 
01160       /* decode distance of block to copy */
01161       ZIPNEEDBITS((cab_ULONG)bd)
01162       if ((e = (t = td + (b & md))->e) > 16)
01163         do {
01164           if (e == 99)
01165             return 1;
01166           ZIPDUMPBITS(t->b)
01167           e -= 16;
01168           ZIPNEEDBITS(e)
01169         } while ((e = (t = t->v.t + (b & Zipmask[e]))->e) > 16);
01170       ZIPDUMPBITS(t->b)
01171       ZIPNEEDBITS(e)
01172       d = w - t->v.n - (b & Zipmask[e]);
01173       ZIPDUMPBITS(e)
01174       do
01175       {
01176         d &= ZIPWSIZE - 1;
01177         e = ZIPWSIZE - max(d, w);
01178         e = min(e, n);
01179         n -= e;
01180         do
01181         {
01182           CAB(outbuf)[w++] = CAB(outbuf)[d++];
01183         } while (--e);
01184       } while (n);
01185     }
01186   }
01187 
01188   /* restore the globals from the locals */
01189   ZIP(window_posn) = w;              /* restore global window pointer */
01190   ZIP(bb) = b;                       /* restore global bit buffer */
01191   ZIP(bk) = k;
01192 
01193   /* done */
01194   return 0;
01195 }
01196 
01197 /***********************************************************
01198  * Zipinflate_stored (internal)
01199  */
01200 static cab_LONG fdi_Zipinflate_stored(fdi_decomp_state *decomp_state)
01201 /* "decompress" an inflated type 0 (stored) block. */
01202 {
01203   cab_ULONG n;           /* number of bytes in block */
01204   cab_ULONG w;           /* current window position */
01205   register cab_ULONG b;  /* bit buffer */
01206   register cab_ULONG k;  /* number of bits in bit buffer */
01207 
01208   /* make local copies of globals */
01209   b = ZIP(bb);                       /* initialize bit buffer */
01210   k = ZIP(bk);
01211   w = ZIP(window_posn);              /* initialize window position */
01212 
01213   /* go to byte boundary */
01214   n = k & 7;
01215   ZIPDUMPBITS(n);
01216 
01217   /* get the length and its complement */
01218   ZIPNEEDBITS(16)
01219   n = (b & 0xffff);
01220   ZIPDUMPBITS(16)
01221   ZIPNEEDBITS(16)
01222   if (n != ((~b) & 0xffff))
01223     return 1;                   /* error in compressed data */
01224   ZIPDUMPBITS(16)
01225 
01226   /* read and output the compressed data */
01227   while(n--)
01228   {
01229     ZIPNEEDBITS(8)
01230     CAB(outbuf)[w++] = (cab_UBYTE)b;
01231     ZIPDUMPBITS(8)
01232   }
01233 
01234   /* restore the globals from the locals */
01235   ZIP(window_posn) = w;              /* restore global window pointer */
01236   ZIP(bb) = b;                       /* restore global bit buffer */
01237   ZIP(bk) = k;
01238   return 0;
01239 }
01240 
01241 /******************************************************
01242  * fdi_Zipinflate_fixed (internal)
01243  */
01244 static cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state)
01245 {
01246   struct Ziphuft *fixed_tl;
01247   struct Ziphuft *fixed_td;
01248   cab_LONG fixed_bl, fixed_bd;
01249   cab_LONG i;                /* temporary variable */
01250   cab_ULONG *l;
01251 
01252   l = ZIP(ll);
01253 
01254   /* literal table */
01255   for(i = 0; i < 144; i++)
01256     l[i] = 8;
01257   for(; i < 256; i++)
01258     l[i] = 9;
01259   for(; i < 280; i++)
01260     l[i] = 7;
01261   for(; i < 288; i++)          /* make a complete, but wrong code set */
01262     l[i] = 8;
01263   fixed_bl = 7;
01264   if((i = fdi_Ziphuft_build(l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl, decomp_state)))
01265     return i;
01266 
01267   /* distance table */
01268   for(i = 0; i < 30; i++)      /* make an incomplete code set */
01269     l[i] = 5;
01270   fixed_bd = 5;
01271   if((i = fdi_Ziphuft_build(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, decomp_state)) > 1)
01272   {
01273     fdi_Ziphuft_free(CAB(fdi), fixed_tl);
01274     return i;
01275   }
01276 
01277   /* decompress until an end-of-block code */
01278   i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state);
01279 
01280   fdi_Ziphuft_free(CAB(fdi), fixed_td);
01281   fdi_Ziphuft_free(CAB(fdi), fixed_tl);
01282   return i;
01283 }
01284 
01285 /**************************************************************
01286  * fdi_Zipinflate_dynamic (internal)
01287  */
01288 static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
01289  /* decompress an inflated type 2 (dynamic Huffman codes) block. */
01290 {
01291   cab_LONG i;           /* temporary variables */
01292   cab_ULONG j;
01293   cab_ULONG *ll;
01294   cab_ULONG l;              /* last length */
01295   cab_ULONG m;              /* mask for bit lengths table */
01296   cab_ULONG n;              /* number of lengths to get */
01297   struct Ziphuft *tl;           /* literal/length code table */
01298   struct Ziphuft *td;           /* distance code table */
01299   cab_LONG bl;                  /* lookup bits for tl */
01300   cab_LONG bd;                  /* lookup bits for td */
01301   cab_ULONG nb;             /* number of bit length codes */
01302   cab_ULONG nl;             /* number of literal/length codes */
01303   cab_ULONG nd;             /* number of distance codes */
01304   register cab_ULONG b;         /* bit buffer */
01305   register cab_ULONG k;         /* number of bits in bit buffer */
01306 
01307   /* make local bit buffer */
01308   b = ZIP(bb);
01309   k = ZIP(bk);
01310   ll = ZIP(ll);
01311 
01312   /* read in table lengths */
01313   ZIPNEEDBITS(5)
01314   nl = 257 + (b & 0x1f);      /* number of literal/length codes */
01315   ZIPDUMPBITS(5)
01316   ZIPNEEDBITS(5)
01317   nd = 1 + (b & 0x1f);        /* number of distance codes */
01318   ZIPDUMPBITS(5)
01319   ZIPNEEDBITS(4)
01320   nb = 4 + (b & 0xf);         /* number of bit length codes */
01321   ZIPDUMPBITS(4)
01322   if(nl > 288 || nd > 32)
01323     return 1;                   /* bad lengths */
01324 
01325   /* read in bit-length-code lengths */
01326   for(j = 0; j < nb; j++)
01327   {
01328     ZIPNEEDBITS(3)
01329     ll[Zipborder[j]] = b & 7;
01330     ZIPDUMPBITS(3)
01331   }
01332   for(; j < 19; j++)
01333     ll[Zipborder[j]] = 0;
01334 
01335   /* build decoding table for trees--single level, 7 bit lookup */
01336   bl = 7;
01337   if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0)
01338   {
01339     if(i == 1)
01340       fdi_Ziphuft_free(CAB(fdi), tl);
01341     return i;                   /* incomplete code set */
01342   }
01343 
01344   /* read in literal and distance code lengths */
01345   n = nl + nd;
01346   m = Zipmask[bl];
01347   i = l = 0;
01348   while((cab_ULONG)i < n)
01349   {
01350     ZIPNEEDBITS((cab_ULONG)bl)
01351     j = (td = tl + (b & m))->b;
01352     ZIPDUMPBITS(j)
01353     j = td->v.n;
01354     if (j < 16)                 /* length of code in bits (0..15) */
01355       ll[i++] = l = j;          /* save last length in l */
01356     else if (j == 16)           /* repeat last length 3 to 6 times */
01357     {
01358       ZIPNEEDBITS(2)
01359       j = 3 + (b & 3);
01360       ZIPDUMPBITS(2)
01361       if((cab_ULONG)i + j > n)
01362         return 1;
01363       while (j--)
01364         ll[i++] = l;
01365     }
01366     else if (j == 17)           /* 3 to 10 zero length codes */
01367     {
01368       ZIPNEEDBITS(3)
01369       j = 3 + (b & 7);
01370       ZIPDUMPBITS(3)
01371       if ((cab_ULONG)i + j > n)
01372         return 1;
01373       while (j--)
01374         ll[i++] = 0;
01375       l = 0;
01376     }
01377     else                        /* j == 18: 11 to 138 zero length codes */
01378     {
01379       ZIPNEEDBITS(7)
01380       j = 11 + (b & 0x7f);
01381       ZIPDUMPBITS(7)
01382       if ((cab_ULONG)i + j > n)
01383         return 1;
01384       while (j--)
01385         ll[i++] = 0;
01386       l = 0;
01387     }
01388   }
01389 
01390   /* free decoding table for trees */
01391   fdi_Ziphuft_free(CAB(fdi), tl);
01392 
01393   /* restore the global bit buffer */
01394   ZIP(bb) = b;
01395   ZIP(bk) = k;
01396 
01397   /* build the decoding tables for literal/length and distance codes */
01398   bl = ZIPLBITS;
01399   if((i = fdi_Ziphuft_build(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, decomp_state)) != 0)
01400   {
01401     if(i == 1)
01402       fdi_Ziphuft_free(CAB(fdi), tl);
01403     return i;                   /* incomplete code set */
01404   }
01405   bd = ZIPDBITS;
01406   fdi_Ziphuft_build(ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd, decomp_state);
01407 
01408   /* decompress until an end-of-block code */
01409   if(fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state))
01410     return 1;
01411 
01412   /* free the decoding tables, return */
01413   fdi_Ziphuft_free(CAB(fdi), tl);
01414   fdi_Ziphuft_free(CAB(fdi), td);
01415   return 0;
01416 }
01417 
01418 /*****************************************************
01419  * fdi_Zipinflate_block (internal)
01420  */
01421 static cab_LONG fdi_Zipinflate_block(cab_LONG *e, fdi_decomp_state *decomp_state) /* e == last block flag */
01422 { /* decompress an inflated block */
01423   cab_ULONG t;              /* block type */
01424   register cab_ULONG b;     /* bit buffer */
01425   register cab_ULONG k;     /* number of bits in bit buffer */
01426 
01427   /* make local bit buffer */
01428   b = ZIP(bb);
01429   k = ZIP(bk);
01430 
01431   /* read in last block bit */
01432   ZIPNEEDBITS(1)
01433   *e = (cab_LONG)b & 1;
01434   ZIPDUMPBITS(1)
01435 
01436   /* read in block type */
01437   ZIPNEEDBITS(2)
01438   t = b & 3;
01439   ZIPDUMPBITS(2)
01440 
01441   /* restore the global bit buffer */
01442   ZIP(bb) = b;
01443   ZIP(bk) = k;
01444 
01445   /* inflate that block type */
01446   if(t == 2)
01447     return fdi_Zipinflate_dynamic(decomp_state);
01448   if(t == 0)
01449     return fdi_Zipinflate_stored(decomp_state);
01450   if(t == 1)
01451     return fdi_Zipinflate_fixed(decomp_state);
01452   /* bad block type */
01453   return 2;
01454 }
01455 
01456 /****************************************************
01457  * ZIPfdi_decomp(internal)
01458  */
01459 static int ZIPfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
01460 {
01461   cab_LONG e;               /* last block flag */
01462 
01463   TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
01464 
01465   ZIP(inpos) = CAB(inbuf);
01466   ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0;
01467   if(outlen > ZIPWSIZE)
01468     return DECR_DATAFORMAT;
01469 
01470   /* CK = Chris Kirmse, official Microsoft purloiner */
01471   if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B)
01472     return DECR_ILLEGALDATA;
01473   ZIP(inpos) += 2;
01474 
01475   do {
01476     if(fdi_Zipinflate_block(&e, decomp_state))
01477       return DECR_ILLEGALDATA;
01478   } while(!e);
01479 
01480   /* return success */
01481   return DECR_OK;
01482 }
01483 
01484 /*******************************************************************
01485  * QTMfdi_decomp(internal)
01486  */
01487 static int QTMfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
01488 {
01489   cab_UBYTE *inpos  = CAB(inbuf);
01490   cab_UBYTE *window = QTM(window);
01491   cab_UBYTE *runsrc, *rundest;
01492   cab_ULONG window_posn = QTM(window_posn);
01493   cab_ULONG window_size = QTM(window_size);
01494 
01495   /* used by bitstream macros */
01496   register int bitsleft, bitrun, bitsneed;
01497   register cab_ULONG bitbuf;
01498 
01499   /* used by GET_SYMBOL */
01500   cab_ULONG range;
01501   cab_UWORD symf;
01502   int i;
01503 
01504   int extra, togo = outlen, match_length = 0, copy_length;
01505   cab_UBYTE selector, sym;
01506   cab_ULONG match_offset = 0;
01507 
01508   cab_UWORD H = 0xFFFF, L = 0, C;
01509 
01510   TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
01511 
01512   /* read initial value of C */
01513   Q_INIT_BITSTREAM;
01514   Q_READ_BITS(C, 16);
01515 
01516   /* apply 2^x-1 mask */
01517   window_posn &= window_size - 1;
01518   /* runs can't straddle the window wraparound */
01519   if ((window_posn + togo) > window_size) {
01520     TRACE("straddled run\n");
01521     return DECR_DATAFORMAT;
01522   }
01523 
01524   while (togo > 0) {
01525     GET_SYMBOL(model7, selector);
01526     switch (selector) {
01527     case 0:
01528       GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--;
01529       break;
01530     case 1:
01531       GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--;
01532       break;
01533     case 2:
01534       GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--;
01535       break;
01536     case 3:
01537       GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--;
01538       break;
01539 
01540     case 4:
01541       /* selector 4 = fixed length of 3 */
01542       GET_SYMBOL(model4, sym);
01543       Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
01544       match_offset = CAB(q_position_base)[sym] + extra + 1;
01545       match_length = 3;
01546       break;
01547 
01548     case 5:
01549       /* selector 5 = fixed length of 4 */
01550       GET_SYMBOL(model5, sym);
01551       Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
01552       match_offset = CAB(q_position_base)[sym] + extra + 1;
01553       match_length = 4;
01554       break;
01555 
01556     case 6:
01557       /* selector 6 = variable length */
01558       GET_SYMBOL(model6len, sym);
01559       Q_READ_BITS(extra, CAB(q_length_extra)[sym]);
01560       match_length = CAB(q_length_base)[sym] + extra + 5;
01561       GET_SYMBOL(model6pos, sym);
01562       Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
01563       match_offset = CAB(q_position_base)[sym] + extra + 1;
01564       break;
01565 
01566     default:
01567       TRACE("Selector is bogus\n");
01568       return DECR_ILLEGALDATA;
01569     }
01570 
01571     /* if this is a match */
01572     if (selector >= 4) {
01573       rundest = window + window_posn;
01574       togo -= match_length;
01575 
01576       /* copy any wrapped around source data */
01577       if (window_posn >= match_offset) {
01578         /* no wrap */
01579         runsrc = rundest - match_offset;
01580       } else {
01581         runsrc = rundest + (window_size - match_offset);
01582         copy_length = match_offset - window_posn;
01583         if (copy_length < match_length) {
01584           match_length -= copy_length;
01585           window_posn += copy_length;
01586           while (copy_length-- > 0) *rundest++ = *runsrc++;
01587           runsrc = window;
01588         }
01589       }
01590       window_posn += match_length;
01591 
01592       /* copy match data - no worries about destination wraps */
01593       while (match_length-- > 0) *rundest++ = *runsrc++;
01594     }
01595   } /* while (togo > 0) */
01596 
01597   if (togo != 0) {
01598     TRACE("Frame overflow, this_run = %d\n", togo);
01599     return DECR_ILLEGALDATA;
01600   }
01601 
01602   memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) -
01603     outlen, outlen);
01604 
01605   QTM(window_posn) = window_posn;
01606   return DECR_OK;
01607 }
01608 
01609 /************************************************************
01610  * fdi_lzx_read_lens (internal)
01611  */
01612 static int fdi_lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb,
01613                   fdi_decomp_state *decomp_state) {
01614   cab_ULONG i,j, x,y;
01615   int z;
01616 
01617   register cab_ULONG bitbuf = lb->bb;
01618   register int bitsleft = lb->bl;
01619   cab_UBYTE *inpos = lb->ip;
01620   cab_UWORD *hufftbl;
01621   
01622   for (x = 0; x < 20; x++) {
01623     READ_BITS(y, 4);
01624     LENTABLE(PRETREE)[x] = y;
01625   }
01626   BUILD_TABLE(PRETREE);
01627 
01628   for (x = first; x < last; ) {
01629     READ_HUFFSYM(PRETREE, z);
01630     if (z == 17) {
01631       READ_BITS(y, 4); y += 4;
01632       while (y--) lens[x++] = 0;
01633     }
01634     else if (z == 18) {
01635       READ_BITS(y, 5); y += 20;
01636       while (y--) lens[x++] = 0;
01637     }
01638     else if (z == 19) {
01639       READ_BITS(y, 1); y += 4;
01640       READ_HUFFSYM(PRETREE, z);
01641       z = lens[x] - z; if (z < 0) z += 17;
01642       while (y--) lens[x++] = z;
01643     }
01644     else {
01645       z = lens[x] - z; if (z < 0) z += 17;
01646       lens[x++] = z;
01647     }
01648   }
01649 
01650   lb->bb = bitbuf;
01651   lb->bl = bitsleft;
01652   lb->ip = inpos;
01653   return 0;
01654 }
01655 
01656 /*******************************************************
01657  * LZXfdi_decomp(internal)
01658  */
01659 static int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) {
01660   cab_UBYTE *inpos  = CAB(inbuf);
01661   const cab_UBYTE *endinp = inpos + inlen;
01662   cab_UBYTE *window = LZX(window);
01663   cab_UBYTE *runsrc, *rundest;
01664   cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
01665 
01666   cab_ULONG window_posn = LZX(window_posn);
01667   cab_ULONG window_size = LZX(window_size);
01668   cab_ULONG R0 = LZX(R0);
01669   cab_ULONG R1 = LZX(R1);
01670   cab_ULONG R2 = LZX(R2);
01671 
01672   register cab_ULONG bitbuf;
01673   register int bitsleft;
01674   cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
01675   struct lzx_bits lb; /* used in READ_LENGTHS macro */
01676 
01677   int togo = outlen, this_run, main_element, aligned_bits;
01678   int match_length, copy_length, length_footer, extra, verbatim_bits;
01679 
01680   TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
01681 
01682   INIT_BITSTREAM;
01683 
01684   /* read header if necessary */
01685   if (!LZX(header_read)) {
01686     i = j = 0;
01687     READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); }
01688     LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */
01689     LZX(header_read) = 1;
01690   }
01691 
01692   /* main decoding loop */
01693   while (togo > 0) {
01694     /* last block finished, new block expected */
01695     if (LZX(block_remaining) == 0) {
01696       if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) {
01697         if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */
01698         INIT_BITSTREAM;
01699       }
01700 
01701       READ_BITS(LZX(block_type), 3);
01702       READ_BITS(i, 16);
01703       READ_BITS(j, 8);
01704       LZX(block_remaining) = LZX(block_length) = (i << 8) | j;
01705 
01706       switch (LZX(block_type)) {
01707       case LZX_BLOCKTYPE_ALIGNED:
01708         for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; }
01709         BUILD_TABLE(ALIGNED);
01710         /* rest of aligned header is same as verbatim */
01711 
01712       case LZX_BLOCKTYPE_VERBATIM:
01713         READ_LENGTHS(MAINTREE, 0, 256, fdi_lzx_read_lens);
01714         READ_LENGTHS(MAINTREE, 256, LZX(main_elements), fdi_lzx_read_lens);
01715         BUILD_TABLE(MAINTREE);
01716         if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1;
01717 
01718         READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, fdi_lzx_read_lens);
01719         BUILD_TABLE(LENGTH);
01720         break;
01721 
01722       case LZX_BLOCKTYPE_UNCOMPRESSED:
01723         LZX(intel_started) = 1; /* because we can't assume otherwise */
01724         ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
01725         if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
01726         R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
01727         R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
01728         R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
01729         break;
01730 
01731       default:
01732         return DECR_ILLEGALDATA;
01733       }
01734     }
01735 
01736     /* buffer exhaustion check */
01737     if (inpos > endinp) {
01738       /* it's possible to have a file where the next run is less than
01739        * 16 bits in size. In this case, the READ_HUFFSYM() macro used
01740        * in building the tables will exhaust the buffer, so we should
01741        * allow for this, but not allow those accidentally read bits to
01742        * be used (so we check that there are at least 16 bits
01743        * remaining - in this boundary case they aren't really part of
01744        * the compressed data)
01745        */
01746       if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA;
01747     }
01748 
01749     while ((this_run = LZX(block_remaining)) > 0 && togo > 0) {
01750       if (this_run > togo) this_run = togo;
01751       togo -= this_run;
01752       LZX(block_remaining) -= this_run;
01753 
01754       /* apply 2^x-1 mask */
01755       window_posn &= window_size - 1;
01756       /* runs can't straddle the window wraparound */
01757       if ((window_posn + this_run) > window_size)
01758         return DECR_DATAFORMAT;
01759 
01760       switch (LZX(block_type)) {
01761 
01762       case LZX_BLOCKTYPE_VERBATIM:
01763         while (this_run > 0) {
01764           READ_HUFFSYM(MAINTREE, main_element);
01765 
01766           if (main_element < LZX_NUM_CHARS) {
01767             /* literal: 0 to LZX_NUM_CHARS-1 */
01768             window[window_posn++] = main_element;
01769             this_run--;
01770           }
01771           else {
01772             /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
01773             main_element -= LZX_NUM_CHARS;
01774   
01775             match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
01776             if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
01777               READ_HUFFSYM(LENGTH, length_footer);
01778               match_length += length_footer;
01779             }
01780             match_length += LZX_MIN_MATCH;
01781   
01782             match_offset = main_element >> 3;
01783   
01784             if (match_offset > 2) {
01785               /* not repeated offset */
01786               if (match_offset != 3) {
01787                 extra = CAB(extra_bits)[match_offset];
01788                 READ_BITS(verbatim_bits, extra);
01789                 match_offset = CAB(lzx_position_base)[match_offset] 
01790                                - 2 + verbatim_bits;
01791               }
01792               else {
01793                 match_offset = 1;
01794               }
01795   
01796               /* update repeated offset LRU queue */
01797               R2 = R1; R1 = R0; R0 = match_offset;
01798             }
01799             else if (match_offset == 0) {
01800               match_offset = R0;
01801             }
01802             else if (match_offset == 1) {
01803               match_offset = R1;
01804               R1 = R0; R0 = match_offset;
01805             }
01806             else /* match_offset == 2 */ {
01807               match_offset = R2;
01808               R2 = R0; R0 = match_offset;
01809             }
01810 
01811             rundest = window + window_posn;
01812             this_run -= match_length;
01813 
01814             /* copy any wrapped around source data */
01815             if (window_posn >= match_offset) {
01816               /* no wrap */
01817               runsrc = rundest - match_offset;
01818             } else {
01819               runsrc = rundest + (window_size - match_offset);
01820               copy_length = match_offset - window_posn;
01821               if (copy_length < match_length) {
01822                 match_length -= copy_length;
01823                 window_posn += copy_length;
01824                 while (copy_length-- > 0) *rundest++ = *runsrc++;
01825                 runsrc = window;
01826               }
01827             }
01828             window_posn += match_length;
01829 
01830             /* copy match data - no worries about destination wraps */
01831             while (match_length-- > 0) *rundest++ = *runsrc++;
01832           }
01833         }
01834         break;
01835 
01836       case LZX_BLOCKTYPE_ALIGNED:
01837         while (this_run > 0) {
01838           READ_HUFFSYM(MAINTREE, main_element);
01839   
01840           if (main_element < LZX_NUM_CHARS) {
01841             /* literal: 0 to LZX_NUM_CHARS-1 */
01842             window[window_posn++] = main_element;
01843             this_run--;
01844           }
01845           else {
01846             /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
01847             main_element -= LZX_NUM_CHARS;
01848   
01849             match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
01850             if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
01851               READ_HUFFSYM(LENGTH, length_footer);
01852               match_length += length_footer;
01853             }
01854             match_length += LZX_MIN_MATCH;
01855   
01856             match_offset = main_element >> 3;
01857   
01858             if (match_offset > 2) {
01859               /* not repeated offset */
01860               extra = CAB(extra_bits)[match_offset];
01861               match_offset = CAB(lzx_position_base)[match_offset] - 2;
01862               if (extra > 3) {
01863                 /* verbatim and aligned bits */
01864                 extra -= 3;
01865                 READ_BITS(verbatim_bits, extra);
01866                 match_offset += (verbatim_bits << 3);
01867                 READ_HUFFSYM(ALIGNED, aligned_bits);
01868                 match_offset += aligned_bits;
01869               }
01870               else if (extra == 3) {
01871                 /* aligned bits only */
01872                 READ_HUFFSYM(ALIGNED, aligned_bits);
01873                 match_offset += aligned_bits;
01874               }
01875               else if (extra > 0) { /* extra==1, extra==2 */
01876                 /* verbatim bits only */
01877                 READ_BITS(verbatim_bits, extra);
01878                 match_offset += verbatim_bits;
01879               }
01880               else /* extra == 0 */ {
01881                 /* ??? */
01882                 match_offset = 1;
01883               }
01884   
01885               /* update repeated offset LRU queue */
01886               R2 = R1; R1 = R0; R0 = match_offset;
01887             }
01888             else if (match_offset == 0) {
01889               match_offset = R0;
01890             }
01891             else if (match_offset == 1) {
01892               match_offset = R1;
01893               R1 = R0; R0 = match_offset;
01894             }
01895             else /* match_offset == 2 */ {
01896               match_offset = R2;
01897               R2 = R0; R0 = match_offset;
01898             }
01899 
01900             rundest = window + window_posn;
01901             this_run -= match_length;
01902 
01903             /* copy any wrapped around source data */
01904             if (window_posn >= match_offset) {
01905               /* no wrap */
01906               runsrc = rundest - match_offset;
01907             } else {
01908               runsrc = rundest + (window_size - match_offset);
01909               copy_length = match_offset - window_posn;
01910               if (copy_length < match_length) {
01911                 match_length -= copy_length;
01912                 window_posn += copy_length;
01913                 while (copy_length-- > 0) *rundest++ = *runsrc++;
01914                 runsrc = window;
01915               }
01916             }
01917             window_posn += match_length;
01918 
01919             /* copy match data - no worries about destination wraps */
01920             while (match_length-- > 0) *rundest++ = *runsrc++;
01921           }
01922         }
01923         break;
01924 
01925       case LZX_BLOCKTYPE_UNCOMPRESSED:
01926         if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA;
01927         memcpy(window + window_posn, inpos, (size_t) this_run);
01928         inpos += this_run; window_posn += this_run;
01929         break;
01930 
01931       default:
01932         return DECR_ILLEGALDATA; /* might as well */
01933       }
01934 
01935     }
01936   }
01937 
01938   if (togo != 0) return DECR_ILLEGALDATA;
01939   memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) -
01940     outlen, (size_t) outlen);
01941 
01942   LZX(window_posn) = window_posn;
01943   LZX(R0) = R0;
01944   LZX(R1) = R1;
01945   LZX(R2) = R2;
01946 
01947   /* intel E8 decoding */
01948   if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) {
01949     if (outlen <= 6 || !LZX(intel_started)) {
01950       LZX(intel_curpos) += outlen;
01951     }
01952     else {
01953       cab_UBYTE *data    = CAB(outbuf);
01954       cab_UBYTE *dataend = data + outlen - 10;
01955       cab_LONG curpos    = LZX(intel_curpos);
01956       cab_LONG filesize  = LZX(intel_filesize);
01957       cab_LONG abs_off, rel_off;
01958 
01959       LZX(intel_curpos) = curpos + outlen;
01960 
01961       while (data < dataend) {
01962         if (*data++ != 0xE8) { curpos++; continue; }
01963         abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
01964         if ((abs_off >= -curpos) && (abs_off < filesize)) {
01965           rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
01966           data[0] = (cab_UBYTE) rel_off;
01967           data[1] = (cab_UBYTE) (rel_off >> 8);
01968           data[2] = (cab_UBYTE) (rel_off >> 16);
01969           data[3] = (cab_UBYTE) (rel_off >> 24);
01970         }
01971         data += 4;
01972         curpos += 5;
01973       }
01974     }
01975   }
01976   return DECR_OK;
01977 }
01978 
01979 /**********************************************************
01980  * fdi_decomp (internal)
01981  *
01982  * Decompress the requested number of bytes.  If savemode is zero,
01983  * do not save the output anywhere, just plow through blocks until we
01984  * reach the specified (uncompressed) distance from the starting point,
01985  * and remember the position of the cabfile pointer (and which cabfile)
01986  * after we are done; otherwise, save the data out to CAB(filehf),
01987  * decompressing the requested number of bytes and writing them out.  This
01988  * is also where we jump to additional cabinets in the case of split
01989  * cab's, and provide (some of) the NEXT_CABINET notification semantics.
01990  */
01991 static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state,
01992   char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser)
01993 {
01994   cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset);
01995   cab_UBYTE buf[cfdata_SIZEOF], *data;
01996   cab_UWORD inlen, len, outlen, cando;
01997   cab_ULONG cksum;
01998   cab_LONG err;
01999   fdi_decomp_state *cab = (savemode && CAB(decomp_cab)) ? CAB(decomp_cab) : decomp_state;
02000 
02001   TRACE("(fi == ^%p, savemode == %d, bytes == %d)\n", fi, savemode, bytes);
02002 
02003   while (bytes > 0) {
02004     /* cando = the max number of bytes we can do */
02005     cando = CAB(outlen);
02006     if (cando > bytes) cando = bytes;
02007 
02008     /* if cando != 0 */
02009     if (cando && savemode)
02010       CAB(fdi)->write(CAB(filehf), CAB(outpos), cando);
02011 
02012     CAB(outpos) += cando;
02013     CAB(outlen) -= cando;
02014     bytes -= cando; if (!bytes) break;
02015 
02016     /* we only get here if we emptied the output buffer */
02017 
02018     /* read data header + data */
02019     inlen = outlen = 0;
02020     while (outlen == 0) {
02021       /* read the block header, skip the reserved part */
02022       if (CAB(fdi)->read(cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF)
02023         return DECR_INPUT;
02024 
02025       if (CAB(fdi)->seek(cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1)
02026         return DECR_INPUT;
02027 
02028       /* we shouldn't get blocks over CAB_INPUTMAX in size */
02029       data = CAB(inbuf) + inlen;
02030       len = EndGetI16(buf+cfdata_CompressedSize);
02031       inlen += len;
02032       if (inlen > CAB_INPUTMAX) return DECR_INPUT;
02033       if (CAB(fdi)->read(cab->cabhf, data, len) != len)
02034         return DECR_INPUT;
02035 
02036       /* clear two bytes after read-in data */
02037       data[len+1] = data[len+2] = 0;
02038 
02039       /* perform checksum test on the block (if one is stored) */
02040       cksum = EndGetI32(buf+cfdata_CheckSum);
02041       if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0)))
02042         return DECR_CHECKSUM; /* checksum is wrong */
02043 
02044       outlen = EndGetI16(buf+cfdata_UncompressedSize);
02045 
02046       /* outlen=0 means this block was the last contiguous part
02047          of a split block, continued in the next cabinet */
02048       if (outlen == 0) {
02049         int pathlen, filenamelen, idx, i;
02050         INT_PTR cabhf;
02051         char fullpath[MAX_PATH], userpath[256];
02052         FDINOTIFICATION fdin;
02053         FDICABINETINFO fdici;
02054         char emptystring = '\0';
02055         cab_UBYTE buf2[64];
02056         int success = FALSE;
02057         struct fdi_folder *fol = NULL, *linkfol = NULL; 
02058         struct fdi_file   *file = NULL, *linkfile = NULL;
02059 
02060         tryanothercab:
02061 
02062         /* set up the next decomp_state... */
02063         if (!(cab->next)) {
02064           if (!cab->mii.hasnext) return DECR_INPUT;
02065 
02066           if (!((cab->next = CAB(fdi)->alloc(sizeof(fdi_decomp_state)))))
02067             return DECR_NOMEMORY;
02068         
02069           ZeroMemory(cab->next, sizeof(fdi_decomp_state));
02070 
02071           /* copy pszCabPath to userpath */
02072           ZeroMemory(userpath, 256);
02073           pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
02074           if (pathlen) {
02075             if (pathlen < 256) {
02076               for (i = 0; i <= pathlen; i++)
02077                 userpath[i] = pszCabPath[i];
02078             } /* else we are in a weird place... let's leave it blank and see if the user fixes it */
02079           } 
02080 
02081           /* initial fdintNEXT_CABINET notification */
02082           ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02083           fdin.psz1 = (cab->mii.nextname) ? cab->mii.nextname : &emptystring;
02084           fdin.psz2 = (cab->mii.nextinfo) ? cab->mii.nextinfo : &emptystring;
02085           fdin.psz3 = &userpath[0];
02086           fdin.fdie = FDIERROR_NONE;
02087           fdin.pv = pvUser;
02088 
02089           if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
02090 
02091           do {
02092 
02093             pathlen = strlen(userpath);
02094             filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 0;
02095 
02096             /* slight overestimation here to save CPU cycles in the developer's brain */
02097             if ((pathlen + filenamelen + 3) > MAX_PATH) {
02098               ERR("MAX_PATH exceeded.\n");
02099               return DECR_ILLEGALDATA;
02100             }
02101 
02102             /* paste the path and filename together */
02103             idx = 0;
02104             if (pathlen) {
02105               for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i];
02106               if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
02107             }
02108             if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i];
02109             fullpath[idx] = '\0';
02110         
02111             TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
02112         
02113             /* try to get a handle to the cabfile */
02114             cabhf = CAB(fdi)->open(fullpath, _O_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
02115             if (cabhf == -1) {
02116               /* no file.  allow the user to try again */
02117               fdin.fdie = FDIERROR_CABINET_NOT_FOUND;
02118               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
02119               continue;
02120             }
02121         
02122             if (cabhf == 0) {
02123               ERR("PFDI_OPEN returned zero for %s.\n", fullpath);
02124               fdin.fdie = FDIERROR_CABINET_NOT_FOUND;
02125               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
02126               continue;
02127             }
02128  
02129             /* check if it's really a cabfile. Note that this doesn't implement the bug */
02130             if (!FDI_read_entries(CAB(fdi), cabhf, &fdici, &(cab->next->mii))) {
02131               WARN("FDIIsCabinet failed.\n");
02132               CAB(fdi)->close(cabhf);
02133               fdin.fdie = FDIERROR_NOT_A_CABINET;
02134               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
02135               continue;
02136             }
02137 
02138             if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) {
02139               WARN("Wrong Cabinet.\n");
02140               CAB(fdi)->close(cabhf);
02141               fdin.fdie = FDIERROR_WRONG_CABINET;
02142               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
02143               continue;
02144             }
02145            
02146             break;
02147 
02148           } while (1);
02149           
02150           /* cabinet notification */
02151           ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02152           fdin.setID = fdici.setID;
02153           fdin.iCabinet = fdici.iCabinet;
02154           fdin.pv = pvUser;
02155           fdin.psz1 = (cab->next->mii.nextname) ? cab->next->mii.nextname : &emptystring;
02156           fdin.psz2 = (cab->next->mii.nextinfo) ? cab->next->mii.nextinfo : &emptystring;
02157           fdin.psz3 = pszCabPath;
02158         
02159           if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) return DECR_USERABORT;
02160           
02161           cab->next->setID = fdici.setID;
02162           cab->next->iCabinet = fdici.iCabinet;
02163           cab->next->fdi = CAB(fdi);
02164           cab->next->filehf = CAB(filehf);
02165           cab->next->cabhf = cabhf;
02166           cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */
02167 
02168           cab = cab->next; /* advance to the next cabinet */
02169 
02170           /* read folders */
02171           for (i = 0; i < fdici.cFolders; i++) {
02172             if (CAB(fdi)->read(cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF)
02173               return DECR_INPUT;
02174 
02175             if (cab->mii.folder_resv > 0)
02176               CAB(fdi)->seek(cab->cabhf, cab->mii.folder_resv, SEEK_CUR);
02177 
02178             fol = CAB(fdi)->alloc(sizeof(struct fdi_folder));
02179             if (!fol) {
02180               ERR("out of memory!\n");
02181               return DECR_NOMEMORY;
02182             }
02183             ZeroMemory(fol, sizeof(struct fdi_folder));
02184             if (!(cab->firstfol)) cab->firstfol = fol;
02185         
02186             fol->offset = (cab_off_t) EndGetI32(buf2+cffold_DataOffset);
02187             fol->num_blocks = EndGetI16(buf2+cffold_NumBlocks);
02188             fol->comp_type  = EndGetI16(buf2+cffold_CompType);
02189         
02190             if (linkfol)
02191               linkfol->next = fol; 
02192             linkfol = fol;
02193           }
02194         
02195           /* read files */
02196           for (i = 0; i < fdici.cFiles; i++) {
02197             if (CAB(fdi)->read(cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF)
02198               return DECR_INPUT;
02199 
02200             file = CAB(fdi)->alloc(sizeof(struct fdi_file));
02201             if (!file) {
02202               ERR("out of memory!\n"); 
02203               return DECR_NOMEMORY;
02204             }
02205             ZeroMemory(file, sizeof(struct fdi_file));
02206             if (!(cab->firstfile)) cab->firstfile = file;
02207               
02208             file->length   = EndGetI32(buf2+cffile_UncompressedSize);
02209             file->offset   = EndGetI32(buf2+cffile_FolderOffset);
02210             file->index    = EndGetI16(buf2+cffile_FolderIndex);
02211             file->time     = EndGetI16(buf2+cffile_Time);
02212             file->date     = EndGetI16(buf2+cffile_Date);
02213             file->attribs  = EndGetI16(buf2+cffile_Attribs);
02214             file->filename = FDI_read_string(CAB(fdi), cab->cabhf, fdici.cbCabinet);
02215         
02216             if (!file->filename) return DECR_INPUT;
02217         
02218             if (linkfile)
02219               linkfile->next = file;
02220             linkfile = file;
02221           }
02222         
02223         } else 
02224             cab = cab->next; /* advance to the next cabinet */
02225 
02226         /* iterate files -- if we encounter the continued file, process it --
02227            otherwise, jump to the label above and keep looking */
02228 
02229         for (file = cab->firstfile; (file); file = file->next) {
02230           if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
02231             /* check to ensure a real match */
02232             if (lstrcmpiA(fi->filename, file->filename) == 0) {
02233               success = TRUE;
02234               if (CAB(fdi)->seek(cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1)
02235                 return DECR_INPUT;
02236               break;
02237             }
02238           }
02239         }
02240         if (!success) goto tryanothercab; /* FIXME: shouldn't this trigger
02241                                              "Wrong Cabinet" notification? */
02242       }
02243     }
02244 
02245     /* decompress block */
02246     if ((err = CAB(decompress)(inlen, outlen, decomp_state)))
02247       return err;
02248     CAB(outlen) = outlen;
02249     CAB(outpos) = CAB(outbuf);
02250   }
02251   
02252   CAB(decomp_cab) = cab;
02253   return DECR_OK;
02254 }
02255 
02256 static void free_decompression_temps(FDI_Int *fdi, const struct fdi_folder *fol,
02257   fdi_decomp_state *decomp_state)
02258 {
02259   switch (fol->comp_type & cffoldCOMPTYPE_MASK) {
02260   case cffoldCOMPTYPE_LZX:
02261     if (LZX(window)) {
02262       fdi->free(LZX(window));
02263       LZX(window) = NULL;
02264     }
02265     break;
02266   case cffoldCOMPTYPE_QUANTUM:
02267     if (QTM(window)) {
02268       fdi->free(QTM(window));
02269       QTM(window) = NULL;
02270     }
02271     break;
02272   }
02273 }
02274 
02275 static void free_decompression_mem(FDI_Int *fdi, fdi_decomp_state *decomp_state)
02276 {
02277   struct fdi_folder *fol;
02278   while (decomp_state) {
02279     fdi_decomp_state *prev_fds;
02280 
02281     fdi->close(CAB(cabhf));
02282 
02283     /* free the storage remembered by mii */
02284     if (CAB(mii).nextname) fdi->free(CAB(mii).nextname);
02285     if (CAB(mii).nextinfo) fdi->free(CAB(mii).nextinfo);
02286     if (CAB(mii).prevname) fdi->free(CAB(mii).prevname);
02287     if (CAB(mii).previnfo) fdi->free(CAB(mii).previnfo);
02288 
02289     while (CAB(firstfol)) {
02290       fol = CAB(firstfol);
02291       CAB(firstfol) = CAB(firstfol)->next;
02292       fdi->free(fol);
02293     }
02294     while (CAB(firstfile)) {
02295       struct fdi_file *file = CAB(firstfile);
02296       if (file->filename) fdi->free(file->filename);
02297       CAB(firstfile) = CAB(firstfile)->next;
02298       fdi->free(file);
02299     }
02300     prev_fds = decomp_state;
02301     decomp_state = CAB(next);
02302     fdi->free(prev_fds);
02303   }
02304 }
02305 
02306 /***********************************************************************
02307  *      FDICopy (CABINET.22)
02308  *
02309  * Iterates through the files in the Cabinet file indicated by name and
02310  * file-location.  May chain forward to additional cabinets (typically
02311  * only one) if files which begin in this Cabinet are continued in another
02312  * cabinet.  For each file which is partially contained in this cabinet,
02313  * and partially contained in a prior cabinet, provides fdintPARTIAL_FILE
02314  * notification to the pfnfdin callback.  For each file which begins in
02315  * this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin
02316  * callback, and the file is optionally decompressed and saved to disk.
02317  * Notification is not provided for files which are not at least partially
02318  * contained in the specified cabinet file.
02319  *
02320  * See below for a thorough explanation of the various notification
02321  * callbacks.
02322  *
02323  * PARAMS
02324  *   hfdi       [I] An HFDI from FDICreate
02325  *   pszCabinet [I] C-style string containing the filename of the cabinet
02326  *   pszCabPath [I] C-style string containing the file path of the cabinet
02327  *   flags      [I] "Decoder parameters".  Ignored.  Suggested value: 0.
02328  *   pfnfdin    [I] Pointer to a notification function.  See CALLBACKS below.
02329  *   pfnfdid    [I] Pointer to a decryption function.  Ignored.  Suggested
02330  *                  value: NULL.
02331  *   pvUser     [I] arbitrary void * value which is passed to callbacks.
02332  *
02333  * RETURNS
02334  *   TRUE if successful.
02335  *   FALSE if unsuccessful (error information is provided in the ERF structure
02336  *     associated with the provided decompression handle by FDICreate).
02337  *
02338  * CALLBACKS
02339  *
02340  *   Two pointers to callback functions are provided as parameters to FDICopy:
02341  *   pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT).  These
02342  *   types are as follows:
02343  *
02344  *     typedef INT_PTR (__cdecl *PFNFDINOTIFY)  ( FDINOTIFICATIONTYPE fdint,
02345  *                                               PFDINOTIFICATION  pfdin );
02346  *
02347  *     typedef int     (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid );
02348  *
02349  *   You can create functions of this type using the FNFDINOTIFY() and
02350  *   FNFDIDECRYPT() macros, respectively.  For example:
02351  *
02352  *     FNFDINOTIFY(mycallback) {
02353  *       / * use variables fdint and pfdin to process notification * /
02354  *     }
02355  *
02356  *   The second callback, which could be used for decrypting encrypted data,
02357  *   is not used at all.
02358  *
02359  *   Each notification informs the user of some event which has occurred during
02360  *   decompression of the cabinet file; each notification is also an opportunity
02361  *   for the callee to abort decompression.  The information provided to the
02362  *   callback and the meaning of the callback's return value vary drastically
02363  *   across the various types of notification.  The type of notification is the
02364  *   fdint parameter; all other information is provided to the callback in
02365  *   notification-specific parts of the FDINOTIFICATION structure pointed to by
02366  *   pfdin.  The only part of that structure which is assigned for every callback
02367  *   is the pv element, which contains the arbitrary value which was passed to
02368  *   FDICopy in the pvUser argument (psz1 is also used each time, but its meaning
02369  *   is highly dependent on fdint).
02370  *   
02371  *   If you encounter unknown notifications, you should return zero if you want
02372  *   decompression to continue (or -1 to abort).  All strings used in the
02373  *   callbacks are regular C-style strings.  Detailed descriptions of each
02374  *   notification type follow:
02375  *
02376  *   fdintCABINET_INFO:
02377  * 
02378  *     This is the first notification provided after calling FDICopy, and provides
02379  *     the user with various information about the cabinet.  Note that this is
02380  *     called for each cabinet FDICopy opens, not just the first one.  In the
02381  *     structure pointed to by pfdin, psz1 contains a pointer to the name of the
02382  *     next cabinet file in the set after the one just loaded (if any), psz2
02383  *     contains a pointer to the name or "info" of the next disk, psz3
02384  *     contains a pointer to the file-path of the current cabinet, setID
02385  *     contains an arbitrary constant associated with this set of cabinet files,
02386  *     and iCabinet contains the numerical index of the current cabinet within
02387  *     that set.  Return zero, or -1 to abort.
02388  *
02389  *   fdintPARTIAL_FILE:
02390  *
02391  *     This notification is provided when FDICopy encounters a part of a file
02392  *     contained in this cabinet which is missing its beginning.  Files can be
02393  *     split across cabinets, so this is not necessarily an abnormality; it just
02394  *     means that the file in question begins in another cabinet.  No file
02395  *     corresponding to this notification is extracted from the cabinet.  In the
02396  *     structure pointed to by pfdin, psz1 contains a pointer to the name of the
02397  *     partial file, psz2 contains a pointer to the file name of the cabinet in
02398  *     which this file begins, and psz3 contains a pointer to the disk name or
02399  *     "info" of the cabinet where the file begins. Return zero, or -1 to abort.
02400  *
02401  *   fdintCOPY_FILE:
02402  *
02403  *     This notification is provided when FDICopy encounters a file which starts
02404  *     in the cabinet file, provided to FDICopy in pszCabinet.  (FDICopy will not
02405  *     look for files in cabinets after the first one).  One notification will be
02406  *     sent for each such file, before the file is decompressed.  By returning
02407  *     zero, the callback can instruct FDICopy to skip the file.  In the structure
02408  *     pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains
02409  *     the size of the file (uncompressed), attribs contains the file attributes,
02410  *     and date and time contain the date and time of the file.  attributes, date,
02411  *     and time are of the 16-bit ms-dos variety.  Return -1 to abort decompression
02412  *     for the entire cabinet, 0 to skip just this file but continue scanning the
02413  *     cabinet for more files, or an FDIClose()-compatible file-handle.
02414  *
02415  *   fdintCLOSE_FILE_INFO:
02416  *
02417  *     This notification is important, don't forget to implement it.  This
02418  *     notification indicates that a file has been successfully uncompressed and
02419  *     written to disk.  Upon receipt of this notification, the callee is expected
02420  *     to close the file handle, to set the attributes and date/time of the
02421  *     closed file, and possibly to execute the file.  In the structure pointed to
02422  *     by pfdin, psz1 contains a pointer to the name of the file, hf will be the
02423  *     open file handle (close it), cb contains 1 or zero, indicating respectively
02424  *     that the callee should or should not execute the file, and date, time
02425  *     and attributes will be set as in fdintCOPY_FILE.  Bizarrely, the Cabinet SDK
02426  *     specifies that _A_EXEC will be xor'ed out of attributes!  wine does not do
02427  *     do so.  Return TRUE, or FALSE to abort decompression.
02428  *
02429  *   fdintNEXT_CABINET:
02430  *
02431  *     This notification is called when FDICopy must load in another cabinet.  This
02432  *     can occur when a file's data is "split" across multiple cabinets.  The
02433  *     callee has the opportunity to request that FDICopy look in a different file
02434  *     path for the specified cabinet file, by writing that data into a provided
02435  *     buffer (see below for more information).  This notification will be received
02436  *     more than once per-cabinet in the instance that FDICopy failed to find a
02437  *     valid cabinet at the location specified by the first per-cabinet
02438  *     fdintNEXT_CABINET notification.  In such instances, the fdie element of the
02439  *     structure pointed to by pfdin indicates the error which prevented FDICopy
02440  *     from proceeding successfully.  Return zero to indicate success, or -1 to
02441  *     indicate failure and abort FDICopy.
02442  *
02443  *     Upon receipt of this notification, the structure pointed to by pfdin will
02444  *     contain the following values: psz1 pointing to the name of the cabinet
02445  *     which FDICopy is attempting to open, psz2 pointing to the name ("info") of
02446  *     the next disk, psz3 pointing to the presumed file-location of the cabinet,
02447  *     and fdie containing either FDIERROR_NONE, or one of the following: 
02448  *
02449  *       FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET,
02450  *       FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET,
02451  *       FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and 
02452  *       FDIERROR_WRONG_CABINET.
02453  *
02454  *     The callee may choose to change the path where FDICopy will look for the
02455  *     cabinet after this notification.  To do so, the caller may write the new
02456  *     pathname to the buffer pointed to by psz3, which is 256 characters in
02457  *     length, including the terminating null character, before returning zero.
02458  *
02459  *   fdintENUMERATE:
02460  *
02461  *     Undocumented and unimplemented in wine, this seems to be sent each time
02462  *     a cabinet is opened, along with the fdintCABINET_INFO notification.  It
02463  *     probably has an interface similar to that of fdintCABINET_INFO; maybe this
02464  *     provides information about the current cabinet instead of the next one....
02465  *     this is just a guess, it has not been looked at closely.
02466  *
02467  * INCLUDES
02468  *   fdi.c
02469  */
02470 BOOL __cdecl FDICopy(
02471         HFDI           hfdi,
02472         char          *pszCabinet,
02473         char          *pszCabPath,
02474         int            flags,
02475         PFNFDINOTIFY   pfnfdin,
02476         PFNFDIDECRYPT  pfnfdid,
02477         void          *pvUser)
02478 { 
02479   FDICABINETINFO    fdici;
02480   FDINOTIFICATION   fdin;
02481   INT_PTR           cabhf, filehf = 0;
02482   int               idx;
02483   unsigned int      i;
02484   char              fullpath[MAX_PATH];
02485   size_t            pathlen, filenamelen;
02486   char              emptystring = '\0';
02487   cab_UBYTE         buf[64];
02488   struct fdi_folder *fol = NULL, *linkfol = NULL; 
02489   struct fdi_file   *file = NULL, *linkfile = NULL;
02490   fdi_decomp_state *decomp_state;
02491   FDI_Int *fdi = get_fdi_ptr( hfdi );
02492 
02493   TRACE("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, "
02494         "pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p)\n",
02495         hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser);
02496 
02497   if (!fdi) return FALSE;
02498 
02499   if (!(decomp_state = fdi->alloc(sizeof(fdi_decomp_state))))
02500   {
02501       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02502       return FALSE;
02503   }
02504   ZeroMemory(decomp_state, sizeof(fdi_decomp_state));
02505 
02506   pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
02507   filenamelen = (pszCabinet) ? strlen(pszCabinet) : 0;
02508 
02509   /* slight overestimation here to save CPU cycles in the developer's brain */
02510   if ((pathlen + filenamelen + 3) > MAX_PATH) {
02511     ERR("MAX_PATH exceeded.\n");
02512     fdi->free(decomp_state);
02513     set_error( fdi, FDIERROR_CABINET_NOT_FOUND, ERROR_FILE_NOT_FOUND );
02514     return FALSE;
02515   }
02516 
02517   /* paste the path and filename together */
02518   idx = 0;
02519   if (pathlen) {
02520     for (i = 0; i < pathlen; i++) fullpath[idx++] = pszCabPath[i];
02521   }
02522   if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = pszCabinet[i];
02523   fullpath[idx] = '\0';
02524 
02525   TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
02526 
02527   /* get a handle to the cabfile */
02528   cabhf = fdi->open(fullpath, _O_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
02529   if (cabhf == -1) {
02530     fdi->free(decomp_state);
02531     set_error( fdi, FDIERROR_CABINET_NOT_FOUND, 0 );
02532     SetLastError(ERROR_FILE_NOT_FOUND);
02533     return FALSE;
02534   }
02535 
02536   /* check if it's really a cabfile. Note that this doesn't implement the bug */
02537   if (!FDI_read_entries(fdi, cabhf, &fdici, &(CAB(mii)))) {
02538     ERR("FDIIsCabinet failed: %u.\n", fdi->perf->erfOper);
02539     fdi->free(decomp_state);
02540     fdi->close(cabhf);
02541     return FALSE;
02542   }
02543    
02544   /* cabinet notification */
02545   ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02546   fdin.setID = fdici.setID;
02547   fdin.iCabinet = fdici.iCabinet;
02548   fdin.pv = pvUser;
02549   fdin.psz1 = (CAB(mii).nextname) ? CAB(mii).nextname : &emptystring;
02550   fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring;
02551   fdin.psz3 = pszCabPath;
02552 
02553   if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) {
02554     set_error( fdi, FDIERROR_USER_ABORT, 0 );
02555     goto bail_and_fail;
02556   }
02557 
02558   CAB(setID) = fdici.setID;
02559   CAB(iCabinet) = fdici.iCabinet;
02560   CAB(cabhf) = cabhf;
02561 
02562   /* read folders */
02563   for (i = 0; i < fdici.cFolders; i++) {
02564     if (fdi->read(cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) {
02565       set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02566       goto bail_and_fail;
02567     }
02568 
02569     if (CAB(mii).folder_resv > 0)
02570       fdi->seek(cabhf, CAB(mii).folder_resv, SEEK_CUR);
02571 
02572     fol = fdi->alloc(sizeof(struct fdi_folder));
02573     if (!fol) {
02574       ERR("out of memory!\n");
02575       set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
02576       goto bail_and_fail;
02577     }
02578     ZeroMemory(fol, sizeof(struct fdi_folder));
02579     if (!CAB(firstfol)) CAB(firstfol) = fol;
02580 
02581     fol->offset = (cab_off_t) EndGetI32(buf+cffold_DataOffset);
02582     fol->num_blocks = EndGetI16(buf+cffold_NumBlocks);
02583     fol->comp_type  = EndGetI16(buf+cffold_CompType);
02584 
02585     if (linkfol)
02586       linkfol->next = fol; 
02587     linkfol = fol;
02588   }
02589 
02590   /* read files */
02591   for (i = 0; i < fdici.cFiles; i++) {
02592     if (fdi->read(cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) {
02593       set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02594       goto bail_and_fail;
02595     }
02596 
02597     file = fdi->alloc(sizeof(struct fdi_file));
02598     if (!file) { 
02599       ERR("out of memory!\n"); 
02600       set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
02601       goto bail_and_fail;
02602     }
02603     ZeroMemory(file, sizeof(struct fdi_file));
02604     if (!CAB(firstfile)) CAB(firstfile) = file;
02605       
02606     file->length   = EndGetI32(buf+cffile_UncompressedSize);
02607     file->offset   = EndGetI32(buf+cffile_FolderOffset);
02608     file->index    = EndGetI16(buf+cffile_FolderIndex);
02609     file->time     = EndGetI16(buf+cffile_Time);
02610     file->date     = EndGetI16(buf+cffile_Date);
02611     file->attribs  = EndGetI16(buf+cffile_Attribs);
02612     file->filename = FDI_read_string(fdi, cabhf, fdici.cbCabinet);
02613 
02614     if (!file->filename) {
02615       set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02616       goto bail_and_fail;
02617     }
02618 
02619     if (linkfile)
02620       linkfile->next = file;
02621     linkfile = file;
02622   }
02623 
02624   for (file = CAB(firstfile); (file); file = file->next) {
02625 
02626     /*
02627      * FIXME: This implementation keeps multiple cabinet files open at once
02628      * when encountering a split cabinet.  It is a quirk of this implementation
02629      * that sometimes we decrypt the same block of data more than once, to find
02630      * the right starting point for a file, moving the file-pointer backwards.
02631      * If we kept a cache of certain file-pointer information, we could eliminate
02632      * that behavior... in fact I am not sure that the caching we already have
02633      * is not sufficient.
02634      * 
02635      * The current implementation seems to work fine in straightforward situations
02636      * where all the cabinet files needed for decryption are simultaneously
02637      * available.  But presumably, the API is supposed to support cabinets which
02638      * are split across multiple CDROMS; we may need to change our implementation
02639      * to strictly serialize it's file usage so that it opens only one cabinet
02640      * at a time.  Some experimentation with Windows is needed to figure out the
02641      * precise semantics required.  The relevant code is here and in fdi_decomp().
02642      */
02643 
02644     /* partial-file notification */
02645     if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
02646       /*
02647        * FIXME: Need to create a Cabinet with a single file spanning multiple files
02648        * and perform some tests to figure out the right behavior.  The SDK says
02649        * FDICopy will notify the user of the filename and "disk name" (info) of
02650        * the cabinet where the spanning file /started/.
02651        *
02652        * That would certainly be convenient for the API-user, who could abort,
02653        * everything (or parallelize, if that's allowed (it is in wine)), and call
02654        * FDICopy again with the provided filename, so as to avoid partial file
02655        * notification and successfully unpack.  This task could be quite unpleasant
02656        * from wine's perspective: the information specifying the "start cabinet" for
02657        * a file is associated nowhere with the file header and is not to be found in
02658        * the cabinet header.  We have only the index of the cabinet wherein the folder
02659        * begins, which contains the file.  To find that cabinet, we must consider the
02660        * index of the current cabinet, and chain backwards, cabinet-by-cabinet (for
02661        * each cabinet refers to its "next" and "previous" cabinet only, like a linked
02662        * list).
02663        *
02664        * Bear in mind that, in the spirit of CABINET.DLL, we must assume that any
02665        * cabinet other than the active one might be at another filepath than the
02666        * current one, or on another CDROM. This could get rather dicey, especially
02667        * if we imagine parallelized access to the FDICopy API.
02668        *
02669        * The current implementation punts -- it just returns the previous cabinet and
02670        * it's info from the header of this cabinet.  This provides the right answer in
02671        * 95% of the cases; its worth checking if Microsoft cuts the same corner before
02672        * we "fix" it.
02673        */
02674       ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02675       fdin.pv = pvUser;
02676       fdin.psz1 = (char *)file->filename;
02677       fdin.psz2 = (CAB(mii).prevname) ? CAB(mii).prevname : &emptystring;
02678       fdin.psz3 = (CAB(mii).previnfo) ? CAB(mii).previnfo : &emptystring;
02679 
02680       if (((*pfnfdin)(fdintPARTIAL_FILE, &fdin))) {
02681         set_error( fdi, FDIERROR_USER_ABORT, 0 );
02682         goto bail_and_fail;
02683       }
02684       /* I don't think we are supposed to decompress partial files.  This prevents it. */
02685       file->oppressed = TRUE;
02686     }
02687     if (file->oppressed) {
02688       filehf = 0;
02689     } else {
02690       ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02691       fdin.pv = pvUser;
02692       fdin.psz1 = (char *)file->filename;
02693       fdin.cb = file->length;
02694       fdin.date = file->date;
02695       fdin.time = file->time;
02696       fdin.attribs = file->attribs;
02697       if ((filehf = ((*pfnfdin)(fdintCOPY_FILE, &fdin))) == -1) {
02698         set_error( fdi, FDIERROR_USER_ABORT, 0 );
02699         filehf = 0;
02700         goto bail_and_fail;
02701       }
02702     }
02703 
02704     /* find the folder for this file if necc. */
02705     if (filehf) {
02706       int i2;
02707 
02708       fol = CAB(firstfol);
02709       if ((file->index & cffileCONTINUED_TO_NEXT) == cffileCONTINUED_TO_NEXT) {
02710         /* pick the last folder */
02711         while (fol->next) fol = fol->next;
02712       } else {
02713         for (i2 = 0; (i2 < file->index); i2++)
02714           if (fol->next) /* bug resistance, should always be true */
02715             fol = fol->next;
02716       }
02717     }
02718 
02719     if (filehf) {
02720       cab_UWORD comptype = fol->comp_type;
02721       int ct1 = comptype & cffoldCOMPTYPE_MASK;
02722       int ct2 = CAB(current) ? (CAB(current)->comp_type & cffoldCOMPTYPE_MASK) : 0;
02723       int err = 0;
02724 
02725       TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename));
02726 
02727       /* set up decomp_state */
02728       CAB(fdi) = fdi;
02729       CAB(filehf) = filehf;
02730 
02731       /* Was there a change of folder?  Compression type?  Did we somehow go backwards? */
02732       if ((ct1 != ct2) || (CAB(current) != fol) || (file->offset < CAB(offset))) {
02733 
02734         TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename));
02735 
02736         /* free stuff for the old decompressor */
02737         switch (ct2) {
02738         case cffoldCOMPTYPE_LZX:
02739           if (LZX(window)) {
02740             fdi->free(LZX(window));
02741             LZX(window) = NULL;
02742           }
02743           break;
02744         case cffoldCOMPTYPE_QUANTUM:
02745           if (QTM(window)) {
02746             fdi->free(QTM(window));
02747             QTM(window) = NULL;
02748           }
02749           break;
02750         }
02751 
02752         CAB(decomp_cab) = NULL;
02753         CAB(fdi)->seek(CAB(cabhf), fol->offset, SEEK_SET);
02754         CAB(offset) = 0;
02755         CAB(outlen) = 0;
02756 
02757         /* initialize the new decompressor */
02758         switch (ct1) {
02759         case cffoldCOMPTYPE_NONE:
02760           CAB(decompress) = NONEfdi_decomp;
02761           break;
02762         case cffoldCOMPTYPE_MSZIP:
02763           CAB(decompress) = ZIPfdi_decomp;
02764           break;
02765         case cffoldCOMPTYPE_QUANTUM:
02766           CAB(decompress) = QTMfdi_decomp;
02767           err = QTMfdi_init((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state);
02768           break;
02769         case cffoldCOMPTYPE_LZX:
02770           CAB(decompress) = LZXfdi_decomp;
02771           err = LZXfdi_init((comptype >> 8) & 0x1f, decomp_state);
02772           break;
02773         default:
02774           err = DECR_DATAFORMAT;
02775         }
02776       }
02777 
02778       CAB(current) = fol;
02779 
02780       switch (err) {
02781         case DECR_OK:
02782           break;
02783         case DECR_NOMEMORY:
02784           set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
02785           goto bail_and_fail;
02786         default:
02787           set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02788           goto bail_and_fail;
02789       }
02790 
02791       if (file->offset > CAB(offset)) {
02792         /* decode bytes and send them to /dev/null */
02793         switch (fdi_decomp(file, 0, decomp_state, pszCabPath, pfnfdin, pvUser)) {
02794           case DECR_OK:
02795             break;
02796           case DECR_USERABORT:
02797             set_error( fdi, FDIERROR_USER_ABORT, 0 );
02798             goto bail_and_fail;
02799           case DECR_NOMEMORY:
02800             set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
02801             goto bail_and_fail;
02802           default:
02803             set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02804             goto bail_and_fail;
02805         }
02806         CAB(offset) = file->offset;
02807       }
02808 
02809       /* now do the actual decompression */
02810       err = fdi_decomp(file, 1, decomp_state, pszCabPath, pfnfdin, pvUser);
02811       if (err) CAB(current) = NULL; else CAB(offset) += file->length;
02812 
02813       /* fdintCLOSE_FILE_INFO notification */
02814       ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
02815       fdin.pv = pvUser;
02816       fdin.psz1 = (char *)file->filename;
02817       fdin.hf = filehf;
02818       fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */
02819       fdin.date = file->date;
02820       fdin.time = file->time;
02821       fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */
02822       ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin));
02823       filehf = 0;
02824 
02825       switch (err) {
02826         case DECR_OK:
02827           break;
02828         case DECR_USERABORT:
02829           set_error( fdi, FDIERROR_USER_ABORT, 0 );
02830           goto bail_and_fail;
02831         case DECR_NOMEMORY:
02832           set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
02833           goto bail_and_fail;
02834         default:
02835           set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
02836           goto bail_and_fail;
02837       }
02838     }
02839   }
02840 
02841   if (fol) free_decompression_temps(fdi, fol, decomp_state);
02842   free_decompression_mem(fdi, decomp_state);
02843  
02844   return TRUE;
02845 
02846   bail_and_fail: /* here we free ram before error returns */
02847 
02848   if (fol) free_decompression_temps(fdi, fol, decomp_state);
02849 
02850   if (filehf) fdi->close(filehf);
02851 
02852   free_decompression_mem(fdi, decomp_state);
02853 
02854   return FALSE;
02855 }
02856 
02857 /***********************************************************************
02858  *      FDIDestroy (CABINET.23)
02859  *
02860  * Frees a handle created by FDICreate.  Do /not/ call this in the middle
02861  * of FDICopy.  Only reason for failure would be an invalid handle.
02862  * 
02863  * PARAMS
02864  *   hfdi [I] The HFDI to free
02865  *
02866  * RETURNS
02867  *   TRUE for success
02868  *   FALSE for failure
02869  */
02870 BOOL __cdecl FDIDestroy(HFDI hfdi)
02871 {
02872     FDI_Int *fdi = get_fdi_ptr( hfdi );
02873 
02874     TRACE("(hfdi == ^%p)\n", hfdi);
02875     if (!fdi) return FALSE;
02876     fdi->magic = 0; /* paranoia */
02877     fdi->free(fdi);
02878     return TRUE;
02879 }
02880 
02881 /***********************************************************************
02882  *      FDITruncateCabinet (CABINET.24)
02883  *
02884  * Removes all folders of a cabinet file after and including the
02885  * specified folder number.
02886  * 
02887  * PARAMS
02888  *   hfdi            [I] Handle to the FDI context.
02889  *   pszCabinetName  [I] Filename of the cabinet.
02890  *   iFolderToDelete [I] Index of the first folder to delete.
02891  * 
02892  * RETURNS
02893  *   Success: TRUE.
02894  *   Failure: FALSE.
02895  * 
02896  * NOTES
02897  *   The PFNWRITE function supplied to FDICreate must truncate the
02898  *   file at the current position if the number of bytes to write is 0.
02899  */
02900 BOOL __cdecl FDITruncateCabinet(
02901     HFDI    hfdi,
02902     char   *pszCabinetName,
02903     USHORT  iFolderToDelete)
02904 {
02905   FDI_Int *fdi = get_fdi_ptr( hfdi );
02906 
02907   FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n",
02908     hfdi, debugstr_a(pszCabinetName), iFolderToDelete);
02909 
02910   if (!fdi) return FALSE;
02911 
02912   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
02913   return FALSE;
02914 }

Generated on Tue May 15 04:45:02 2012 for ReactOS by doxygen 1.6.3

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.