Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfdi.cGo 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
1.6.3
|