1 /*
2 * File Compression Interface
3 *
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 /*
23
24 There is still some work to be done:
25
26 - no real compression yet
27 - unknown behaviour if files>=2GB or cabinet >=4GB
28 - check if the maximum size for a cabinet is too small to store any data
29 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
30 - probably check err
31
32 */
33
34
35
36 #include "config.h"
37
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winternl.h"
46 #include "fci.h"
47 #include "cabinet.h"
48 #include "wine/debug.h"
49
50
51 #ifdef WORDS_BIGENDIAN
52 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
53 #define fci_endian_uword(x) RtlUshortByteSwap(x)
54 #else
55 #define fci_endian_ulong(x) (x)
56 #define fci_endian_uword(x) (x)
57 #endif
58
59
60 #define fci_set_error(A,B,C) do { \
61 p_fci_internal->perf->erfOper = A; \
62 p_fci_internal->perf->erfType = B; \
63 p_fci_internal->perf->fError = C; \
64 if (B) SetLastError(B); } while(0)
65
66
67 typedef struct {
68 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
69 cab_ULONG reserved1;
70 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
71 cab_ULONG reserved2;
72 cab_ULONG coffFiles; /* offset to first CFFILE section */
73 cab_ULONG reserved3;
74 cab_UBYTE versionMinor; /* 3 */
75 cab_UBYTE versionMajor; /* 1 */
76 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
77 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
78 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
79 cab_UWORD setID; /* identification number of all cabinets in a set*/
80 cab_UWORD iCabinet; /* number of the cabinet in a set */
81 /* additional area if "flags" were set*/
82 } CFHEADER; /* minimum 36 bytes */
83
84 typedef struct {
85 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
86 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
87 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
88 /* additional area if reserve flag was set */
89 } CFFOLDER; /* minimum 8 bytes */
90
91 typedef struct {
92 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
93 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
94 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
95 /* for special values see below this structure*/
96 cab_UWORD date; /* last modification date*/
97 cab_UWORD time; /* last modification time*/
98 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
99 /* ... and a C string with the name of the file */
100 } CFFILE; /* 16 bytes + name of file */
101
102
103 typedef struct {
104 cab_ULONG csum; /* checksum of this entry*/
105 cab_UWORD cbData; /* number of compressed bytes */
106 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
107 /* optional reserved area */
108 /* compressed data */
109 } CFDATA;
110
111
112 /***********************************************************************
113 * FCICreate (CABINET.10)
114 *
115 * FCICreate is provided with several callbacks and
116 * returns a handle which can be used to create cabinet files.
117 *
118 * PARAMS
119 * perf [IO] A pointer to an ERF structure. When FCICreate
120 * returns an error condition, error information may
121 * be found here as well as from GetLastError.
122 * pfnfiledest [I] A pointer to a function which is called when a file
123 * is placed. Only useful for subsequent cabinet files.
124 * pfnalloc [I] A pointer to a function which allocates ram. Uses
125 * the same interface as malloc.
126 * pfnfree [I] A pointer to a function which frees ram. Uses the
127 * same interface as free.
128 * pfnopen [I] A pointer to a function which opens a file. Uses
129 * the same interface as _open.
130 * pfnread [I] A pointer to a function which reads from a file into
131 * a caller-provided buffer. Uses the same interface
132 * as _read.
133 * pfnwrite [I] A pointer to a function which writes to a file from
134 * a caller-provided buffer. Uses the same interface
135 * as _write.
136 * pfnclose [I] A pointer to a function which closes a file handle.
137 * Uses the same interface as _close.
138 * pfnseek [I] A pointer to a function which seeks in a file.
139 * Uses the same interface as _lseek.
140 * pfndelete [I] A pointer to a function which deletes a file.
141 * pfnfcigtf [I] A pointer to a function which gets the name of a
142 * temporary file.
143 * pccab [I] A pointer to an initialized CCAB structure.
144 * pv [I] A pointer to an application-defined notification
145 * function which will be passed to other FCI functions
146 * as a parameter.
147 *
148 * RETURNS
149 * On success, returns an FCI handle of type HFCI.
150 * On failure, the NULL file handle is returned. Error
151 * info can be retrieved from perf.
152 *
153 * INCLUDES
154 * fci.h
155 *
156 */
157 HFCI __cdecl FCICreate(
158 PERF perf,
159 PFNFCIFILEPLACED pfnfiledest,
160 PFNFCIALLOC pfnalloc,
161 PFNFCIFREE pfnfree,
162 PFNFCIOPEN pfnopen,
163 PFNFCIREAD pfnread,
164 PFNFCIWRITE pfnwrite,
165 PFNFCICLOSE pfnclose,
166 PFNFCISEEK pfnseek,
167 PFNFCIDELETE pfndelete,
168 PFNFCIGETTEMPFILE pfnfcigtf,
169 PCCAB pccab,
170 void *pv)
171 {
172 HFCI hfci;
173 int err;
174 PFCI_Int p_fci_internal;
175
176 if (!perf) {
177 SetLastError(ERROR_BAD_ARGUMENTS);
178 return NULL;
179 }
180 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
181 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
182 (!pfnfcigtf) || (!pccab)) {
183 perf->erfOper = FCIERR_NONE;
184 perf->erfType = ERROR_BAD_ARGUMENTS;
185 perf->fError = TRUE;
186
187 SetLastError(ERROR_BAD_ARGUMENTS);
188 return NULL;
189 }
190
191 if (!((hfci = (*pfnalloc)(sizeof(FCI_Int))))) {
192 perf->erfOper = FCIERR_ALLOC_FAIL;
193 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
194 perf->fError = TRUE;
195
196 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
197 return NULL;
198 }
199
200 p_fci_internal=((PFCI_Int)(hfci));
201 p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC;
202 p_fci_internal->perf = perf;
203 p_fci_internal->pfnfiledest = pfnfiledest;
204 p_fci_internal->pfnalloc = pfnalloc;
205 p_fci_internal->pfnfree = pfnfree;
206 p_fci_internal->pfnopen = pfnopen;
207 p_fci_internal->pfnread = pfnread;
208 p_fci_internal->pfnwrite = pfnwrite;
209 p_fci_internal->pfnclose = pfnclose;
210 p_fci_internal->pfnseek = pfnseek;
211 p_fci_internal->pfndelete = pfndelete;
212 p_fci_internal->pfnfcigtf = pfnfcigtf;
213 p_fci_internal->pccab = pccab;
214 p_fci_internal->fPrevCab = FALSE;
215 p_fci_internal->fNextCab = FALSE;
216 p_fci_internal->fSplitFolder = FALSE;
217 p_fci_internal->fGetNextCabInVain = FALSE;
218 p_fci_internal->pv = pv;
219 p_fci_internal->data_in = NULL;
220 p_fci_internal->cdata_in = 0;
221 p_fci_internal->data_out = NULL;
222 p_fci_internal->cCompressedBytesInFolder = 0;
223 p_fci_internal->cFolders = 0;
224 p_fci_internal->cFiles = 0;
225 p_fci_internal->cDataBlocks = 0;
226 p_fci_internal->sizeFileCFDATA1 = 0;
227 p_fci_internal->sizeFileCFFILE1 = 0;
228 p_fci_internal->sizeFileCFDATA2 = 0;
229 p_fci_internal->sizeFileCFFILE2 = 0;
230 p_fci_internal->sizeFileCFFOLDER = 0;
231 p_fci_internal->sizeFileCFFOLDER = 0;
232 p_fci_internal->fNewPrevious = FALSE;
233 p_fci_internal->estimatedCabinetSize = 0;
234 p_fci_internal->statusFolderTotal = 0;
235
236 memset(&p_fci_internal->oldCCAB, 0, sizeof(CCAB));
237 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
238 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
239
240 /* CFDATA */
241 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1,
242 CB_MAX_FILENAME)) {
243 fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE );
244 return FALSE;
245 }
246 /* safety */
247 if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {
248 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
249 return FALSE;
250 }
251
252 p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci,
253 p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv);
254 if(p_fci_internal->handleCFDATA1==0){
255 fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE );
256 return FALSE;
257 }
258 /* TODO error checking of err */
259
260 /* array of all CFFILE in a folder */
261 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1,
262 CB_MAX_FILENAME)) {
263 fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE );
264 return FALSE;
265 }
266 /* safety */
267 if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {
268 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
269 return FALSE;
270 }
271 p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci,
272 p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv);
273 if(p_fci_internal->handleCFFILE1==0){
274 fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE );
275 return FALSE;
276 }
277 /* TODO error checking of err */
278
279 /* CFDATA with checksum and ready to be copied into cabinet */
280 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2,
281 CB_MAX_FILENAME)) {
282 fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE);
283 return FALSE;
284 }
285 /* safety */
286 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
287 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
288 return FALSE;
289 }
290 p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
291 p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv);
292 if(p_fci_internal->handleCFDATA2==0){
293 fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE );
294 return FALSE;
295 }
296 /* TODO error checking of err */
297
298 /* array of all CFFILE in a folder, ready to be copied into cabinet */
299 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
300 CB_MAX_FILENAME)) {
301 fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE );
302 return FALSE;
303 }
304 /* safety */
305 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
306 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
307 return FALSE;
308 }
309 p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
310 p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv);
311 if(p_fci_internal->handleCFFILE2==0){
312 fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE );
313 return FALSE;
314 }
315 /* TODO error checking of err */
316
317 /* array of all CFFILE in a folder, ready to be copied into cabinet */
318 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,
319 CB_MAX_FILENAME)) {
320 fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE );
321 return FALSE;
322 }
323 /* safety */
324 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
325 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
326 return FALSE;
327 }
328 p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
329 p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv);
330 if(p_fci_internal->handleCFFOLDER==0) {
331 fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE);
332 return FALSE;
333 }
334
335 /* TODO close and delete new files when return FALSE */
336 /* TODO error checking of err */
337
338 return hfci;
339 } /* end of FCICreate */
340
341
342
343
344
345
346 static BOOL fci_flush_data_block (HFCI hfci, int* err,
347 PFNFCISTATUS pfnfcis) {
348
349 /* attention no hfci checks!!! */
350 /* attention no checks if there is data available!!! */
351 CFDATA data;
352 CFDATA* cfdata=&data;
353 char* reserved;
354 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
355 UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
356 UINT i;
357
358 /* TODO compress the data of p_fci_internal->data_in */
359 /* and write it to p_fci_internal->data_out */
360 memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
361 p_fci_internal->cdata_in /* number of bytes to copy */);
362
363 cfdata->csum=0; /* checksum has to be set later */
364 /* TODO set realsize of compressed data */
365 cfdata->cbData = p_fci_internal->cdata_in;
366 cfdata->cbUncomp = p_fci_internal->cdata_in;
367
368 /* write cfdata to p_fci_internal->handleCFDATA1 */
369 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
370 cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
371 != sizeof(*cfdata) ) {
372 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
373 return FALSE;
374 }
375 /* TODO error handling of err */
376
377 p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);
378
379 /* add optional reserved area */
380
381 /* This allocation and freeing at each CFData block is a bit */
382 /* inefficient, but it's harder to forget about freeing the buffer :-). */
383 /* Reserved areas are used seldom besides that... */
384 if (cbReserveCFData!=0) {
385 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) {
386 fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE );
387 return FALSE;
388 }
389 for(i=0;i<cbReserveCFData;) {
390 reserved[i++]='\0';
391 }
392 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
393 reserved, /* memory buffer */
394 cbReserveCFData, /* number of bytes to copy */
395 err, p_fci_internal->pv) != cbReserveCFData ) {
396 PFCI_FREE(hfci, reserved);
397 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
398 return FALSE;
399 }
400 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
401
402 p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;
403 PFCI_FREE(hfci, reserved);
404 }
405
406 /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
407 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
408 p_fci_internal->data_out, /* memory buffer */
409 cfdata->cbData, /* number of bytes to copy */
410 err, p_fci_internal->pv) != cfdata->cbData) {
411 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
412 return FALSE;
413 }
414 /* TODO error handling of err */
415
416 p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;
417
418 /* reset the offset */
419 p_fci_internal->cdata_in = 0;
420 p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
421
422 /* report status with pfnfcis about uncompressed and compressed file data */
423 if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
424 p_fci_internal->pv) == -1) {
425 fci_set_error( FCIERR_USER_ABORT, 0, TRUE );
426 return FALSE;
427 }
428
429 ++(p_fci_internal->cDataBlocks);
430
431 return TRUE;
432 } /* end of fci_flush_data_block */
433
434
435
436
437
438 static cab_ULONG fci_get_checksum(const void *pv, UINT cb, CHECKSUM seed)
439 {
440 cab_ULONG csum;
441 cab_ULONG ul;
442 int cUlong;
443 const BYTE *pb;
444
445 csum = seed;
446 cUlong = cb / 4;
447 pb = pv;
448
449 while (cUlong-- > 0) {
450 ul = *pb++;
451 ul |= (((cab_ULONG)(*pb++)) << 8);
452 ul |= (((cab_ULONG)(*pb++)) << 16);
453 ul |= (((cab_ULONG)(*pb++)) << 24);
454
455 csum ^= ul;
456 }
457
458 ul = 0;
459 switch (cb % 4) {
460 case 3:
461 ul |= (((ULONG)(*pb++)) << 16);
462 case 2:
463 ul |= (((ULONG)(*pb++)) << 8);
464 case 1:
465 ul |= *pb++;
466 default:
467 break;
468 }
469 csum ^= ul;
470
471 return csum;
472 } /* end of fci_get_checksum */
473
474
475
476 static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData,
477 PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,
478 cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)
479 {
480 cab_ULONG read_result;
481 CFDATA* pcfdata=(CFDATA*)buffer;
482 BOOL split_block=FALSE;
483 cab_UWORD savedUncomp=0;
484 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
485
486 *payload=0;
487
488 /* while not all CFDATAs have been copied do */
489 while(!FALSE) {
490 if( p_fci_internal->fNextCab ) {
491 if( split_block ) {
492 /* internal error should never happen */
493 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
494 return FALSE;
495 }
496 }
497 /* REUSE the variable read_result */
498 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
499 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
500 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
501 read_result=4;
502 } else {
503 read_result=0;
504 }
505 if (p_fci_internal->fPrevCab) {
506 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
507 strlen(p_fci_internal->szPrevDisk)+1;
508 }
509 /* No more CFDATA fits into the cabinet under construction */
510 /* So don't try to store more data into it */
511 if( p_fci_internal->fNextCab &&
512 (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +
513 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
514 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
515 sizeof(CFHEADER) +
516 read_result +
517 p_fci_internal->oldCCAB.cbReserveCFHeader +
518 sizeof(CFFOLDER) +
519 p_fci_internal->oldCCAB.cbReserveCFFolder +
520 strlen(p_fci_internal->pccab->szCab)+1 +
521 strlen(p_fci_internal->pccab->szDisk)+1
522 )) {
523 /* This may never be run for the first time the while loop is entered.
524 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
525 split_block=TRUE; /* In this case split_block is abused to store */
526 /* the complete data block into the next cabinet and not into the */
527 /* current one. Originally split_block is the indicator that a */
528 /* data block has been split across different cabinets. */
529 } else {
530
531 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
532 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/
533 buffer, /* memory buffer */
534 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
535 err, p_fci_internal->pv);
536 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
537 if (read_result==0) break; /* ALL DATA has been copied */
538 /* read error */
539 fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE );
540 return FALSE;
541 }
542 /* TODO error handling of err */
543
544 /* REUSE buffer p_fci_internal->data_out !!! */
545 /* read data from p_fci_internal->handleCFDATA1 to */
546 /* p_fci_internal->data_out */
547 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
548 p_fci_internal->data_out /* memory buffer */,
549 pcfdata->cbData /* number of bytes to copy */,
550 err, p_fci_internal->pv) != pcfdata->cbData ) {
551 /* read error */
552 fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE );
553 return FALSE;
554 }
555 /* TODO error handling of err */
556
557 /* if cabinet size is too large */
558
559 /* REUSE the variable read_result */
560 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
561 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
562 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
563 read_result=4;
564 } else {
565 read_result=0;
566 }
567 if (p_fci_internal->fPrevCab) {
568 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
569 strlen(p_fci_internal->szPrevDisk)+1;
570 }
571
572 /* Is cabinet with new CFDATA too large? Then data block has to be split */
573 if( p_fci_internal->fNextCab &&
574 (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +
575 pcfdata->cbData +
576 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
577 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
578 sizeof(CFHEADER) +
579 read_result +
580 p_fci_internal->oldCCAB.cbReserveCFHeader +
581 sizeof(CFFOLDER) + /* size of new CFFolder entry */
582 p_fci_internal->oldCCAB.cbReserveCFFolder +
583 strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */
584 strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */
585 )) {
586 /* REUSE read_result to save the size of the compressed data */
587 read_result=pcfdata->cbData;
588 /* Modify the size of the compressed data to store only a part of the */
589 /* data block into the current cabinet. This is done to prevent */
590 /* that the maximum cabinet size will be exceeded. The remainder */
591 /* will be stored into the next following cabinet. */
592
593 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
594 /* Substract everything except the size of the block of data */
595 /* to get it's actual size */
596 pcfdata->cbData = p_fci_internal->oldCCAB.cb - (
597 sizeof(CFDATA) + cbReserveCFData +
598 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
599 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
600 sizeof(CFHEADER) +
601 p_fci_internal->oldCCAB.cbReserveCFHeader +
602 sizeof(CFFOLDER) + /* set size of new CFFolder entry */
603 p_fci_internal->oldCCAB.cbReserveCFFolder );
604 /* substract the size of special header fields */
605 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
606 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
607 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
608 pcfdata->cbData-=4;
609 }
610 if (p_fci_internal->fPrevCab) {
611 pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +
612 strlen(p_fci_internal->szPrevDisk)+1;
613 }
614 pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +
615 strlen(p_fci_internal->pccab->szDisk)+1;
616
617 savedUncomp = pcfdata->cbUncomp;
618 pcfdata->cbUncomp = 0; /* on split blocks of data this is zero */
619
620 /* if split_block==TRUE then the above while loop won't */
621 /* be executed again */
622 split_block=TRUE; /* split_block is the indicator that */
623 /* a data block has been split across */
624 /* different cabinets.*/
625 }
626
627 /* This should never happen !!! */
628 if (pcfdata->cbData==0) {
629 /* set error */
630 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
631 return FALSE;
632 }
633
634 /* set little endian */
635 pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
636 pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
637
638 /* get checksum and write to cfdata.csum */
639 pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
640 sizeof(CFDATA)+cbReserveCFData -
641 sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
642 pcfdata->cbData, 0 ) );
643
644 /* set little endian */
645 pcfdata->csum=fci_endian_ulong(pcfdata->csum);
646
647 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
648 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
649 buffer, /* memory buffer */
650 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
651 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
652 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
653 return FALSE;
654 }
655 /* TODO error handling of err */
656
657 p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;
658
659 /* reset little endian */
660 pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
661 pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
662 pcfdata->csum=fci_endian_ulong(pcfdata->csum);
663
664 /* write compressed data into p_fci_internal->handleCFDATA2 */
665 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
666 p_fci_internal->data_out, /* memory buffer */
667 pcfdata->cbData, /* number of bytes to copy */
668 err, p_fci_internal->pv) != pcfdata->cbData) {
669 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
670 return FALSE;
671 }
672 /* TODO error handling of err */
673
674 p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;
675 ++(p_fci_internal->cDataBlocks);
676 p_fci_internal->statusFolderCopied += pcfdata->cbData;
677 (*payload)+=pcfdata->cbUncomp;
678 /* if cabinet size too large and data has been split */
679 /* write the remainder of the data block to the new CFDATA1 file */
680 if( split_block ) { /* This does not include the */
681 /* abused one (just search for "abused" )*/
682 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
683 if (p_fci_internal->fNextCab==FALSE ) {
684 /* internal error */
685 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
686 return FALSE;
687 }
688
689 /* set cbData to the size of the remainder of the data block */
690 pcfdata->cbData = read_result - pcfdata->cbData;
691 /*recover former value of cfdata.cbData; read_result will be the offset*/
692 read_result -= pcfdata->cbData;
693 pcfdata->cbUncomp = savedUncomp;
694
695 /* reset checksum, it will be computed later */
696 pcfdata->csum=0;
697
698 /* write cfdata WITHOUT checksum to handleCFDATA1new */
699 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
700 buffer, /* memory buffer */
701 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
702 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
703 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
704 return FALSE;
705 }
706 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
707
708 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
709
710 /* write compressed data into handleCFDATA1new */
711 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
712 p_fci_internal->data_out + read_result, /* memory buffer + offset */
713 /* to last part of split data */
714 pcfdata->cbData, /* number of bytes to copy */
715 err, p_fci_internal->pv) != pcfdata->cbData) {
716 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
717 return FALSE;
718 }
719 /* TODO error handling of err */
720
721 p_fci_internal->statusFolderCopied += pcfdata->cbData;
722
723 *psizeFileCFDATA1new += pcfdata->cbData;
724 /* the two blocks of the split data block have been written */
725 /* don't reset split_data yet, because it is still needed see below */
726 }
727
728 /* report status with pfnfcis about copied size of folder */
729 if( (*pfnfcis)(statusFolder,
730 p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
731 p_fci_internal->statusFolderTotal, /* total folder size */
732 p_fci_internal->pv) == -1) {
733 fci_set_error( FCIERR_USER_ABORT, 0, TRUE );
734 return FALSE;
735 }
736 }
737
738 /* if cabinet size too large */
739 /* write the remaining data blocks to the new CFDATA1 file */
740 if ( split_block ) { /* This does include the */
741 /* abused one (just search for "abused" )*/
742 if (p_fci_internal->fNextCab==FALSE ) {
743 /* internal error */
744 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
745 return FALSE;
746 }
747 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
748 while(!FALSE) {
749 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
750 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */
751 buffer, /* memory buffer */
752 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
753 err, p_fci_internal->pv);
754 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
755 if (read_result==0) break; /* ALL DATA has been copied */
756 /* read error */
757 fci_set_error(FCIERR_NONE, ERROR_READ_FAULT, TRUE );
758 return FALSE;
759 }
760 /* TODO error handling of err */
761
762 /* REUSE buffer p_fci_internal->data_out !!! */
763 /* read data from p_fci_internal->handleCFDATA1 to */
764 /* p_fci_internal->data_out */
765 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
766 p_fci_internal->data_out /* memory buffer */,
767 pcfdata->cbData /* number of bytes to copy */,
768 err, p_fci_internal->pv) != pcfdata->cbData ) {
769 /* read error */
770 fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE);
771 return FALSE;
772 }
773 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
774
775 /* write cfdata with checksum to handleCFDATA1new */
776 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
777 buffer, /* memory buffer */
778 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
779 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
780 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
781 return FALSE;
782 }
783 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
784
785 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
786
787 /* write compressed data into handleCFDATA1new */
788 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
789 p_fci_internal->data_out, /* memory buffer */
790 pcfdata->cbData, /* number of bytes to copy */
791 err, p_fci_internal->pv) != pcfdata->cbData) {
792 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
793 return FALSE;
794 }
795 /* TODO error handling of err */
796
797 *psizeFileCFDATA1new += pcfdata->cbData;
798 p_fci_internal->statusFolderCopied += pcfdata->cbData;
799
800 /* report status with pfnfcis about copied size of folder */
801 if( (*pfnfcis)(statusFolder,
802 p_fci_internal->statusFolderCopied,/*cfdata.cbData(+previous ones)*/
803 p_fci_internal->statusFolderTotal, /* total folder size */
804 p_fci_internal->pv) == -1) {
805 fci_set_error( FCIERR_USER_ABORT, 0, TRUE );
806 return FALSE;
807 }
808
809 } /* end of WHILE */
810 break; /* jump out of the next while loop */
811 } /* end of if( split_data ) */
812 } /* end of WHILE */
813 return TRUE;
814 } /* end of fci_flushfolder_copy_cfdata */
815
816
817
818
819
820 static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder,
821 cab_ULONG sizeFileCFDATA2old)
822 {
823 CFFOLDER cffolder;
824 UINT i;
825 char* reserved;
826 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
827
828 /* absolute offset cannot be set yet, because the size of cabinet header, */
829 /* the number of CFFOLDERs and the number of CFFILEs may change. */
830 /* Instead the size of all previous data blocks will be stored and */
831 /* the remainder of the offset will be added when the cabinet will be */
832 /* flushed to disk. */
833 /* This is exactly the way the original CABINET.DLL works!!! */
834 cffolder.coffCabStart=sizeFileCFDATA2old;
835
836 /* set the number of this folder's CFDATA sections */
837 cffolder.cCFData=p_fci_internal->cDataBlocks;
838 /* TODO set compression type */
839 cffolder.typeCompress = tcompTYPE_NONE;
840
841 /* write cffolder to p_fci_internal->handleCFFOLDER */
842 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
843 &cffolder, /* memory buffer */
844 sizeof(cffolder), /* number of bytes to copy */
845 err, p_fci_internal->pv) != sizeof(cffolder) ) {
846 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
847 return FALSE;
848 }
849 /* TODO error handling of err */
850
851 p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);
852
853 /* add optional reserved area */
854 if (cbReserveCFFolder!=0) {
855 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) {
856 fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE );
857 return FALSE;
858 }
859 for(i=0;i<cbReserveCFFolder;) {
860 reserved[i++]='\0';
861 }
862 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
863 reserved, /* memory buffer */
864 cbReserveCFFolder, /* number of bytes to copy */
865 err, p_fci_internal->pv) != cbReserveCFFolder ) {
866 PFCI_FREE(hfci, reserved);
867 fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE );
868 return FALSE;
869 }
870 /* TODO error handling of err */
871
872 p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;
873
874 PFCI_FREE(hfci, reserved);
875 }
876 return TRUE;
877 } /* end of fci_flushfolder_copy_cffolder */
878
879
880
881
882
883 static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new,
884 cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)
885 {
886 CFFILE cffile;
887 cab_ULONG read_result;
888 cab_ULONG seek=0;
889 cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;
890 BOOL may_be_prev=TRUE;
891 cab_ULONG cbFileRemainer=0;
892 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
893 /* set seek of p_fci_internal->handleCFFILE1 to 0 */
894 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err,
895 p_fci_internal->pv) !=0 ) {
896 /* wrong return value */
897 fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE );
898 return FALSE;
899 }
900 /* TODO error handling of err */
901
902 /* while not all CFFILE structures have been copied do */
903 while(!FALSE) {
904 /* REUSE the variable read_result */
905 /* read data from p_fci_internal->handleCFFILE1 to cffile */
906 read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */,
907 &cffile, /* memory buffer */
908 sizeof(cffile), /* number of bytes to copy */
909 err, p_fci_internal->pv);
910 if( read_result != sizeof(cffile) ) {
911 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
912 /* read error */
913 fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE );
914 return FALSE;
915 }
916 /* TODO error handling of err */
917
918 /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
919 /* position. I don't know why so I'll just omit it */
920
921 /* read the filename from p_fci_internal->handleCFFILE1 */
922 /* REUSE the variable read_result AGAIN */
923 /* REUSE the memory buffer PFCI(hfci)->data_out */
924 if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/,
925 p_fci_internal->data_out, /* memory buffer */
926 CB_MAX_FILENAME, /* number of bytes to copy */
927 err, p_fci_internal->pv) <2) {
928 /* read error */
929 fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE );
930 return FALSE;
931 }
932 /* TODO maybe other checks of read_result */
933 /* TODO error handling of err */
934
935 /* safety */
936 if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {
937 /* set error code internal error */
938 fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE );
939 return FALSE;
940 }
941
942 seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;
943
944 /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
945 /* i.e. seek to the next CFFILE area */
946 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,
947 seek, /* seek position*/
948 SEEK_SET ,err,
949 p_fci_internal->pv)
950 != seek) {
951 /* wrong return value */
952 fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE );
953 return FALSE;
954 }
955 /* TODO error handling of err */
956
957 /* fnfilfnfildest: placed file on cabinet */
958 if (p_fci_internal->fNextCab ||
959 p_fci_internal->fGetNextCabInVain) {
960 PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB),
961 p_fci_internal->data_out, /* the file name*/
962 cffile.cbFile, /* file size */
963 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
964 p_fci_internal->pv
965 );
966 } else {
967 PFCI_FILEPLACED( hfci, p_fci_internal->pccab,
968 p_fci_internal->data_out, /* the file name*/
969 cffile.cbFile, /* file size */
970 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
971 p_fci_internal->pv
972 );
973 }
974
975 /* Check special iFolder values */
976 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
977 p_fci_internal->fPrevCab==FALSE ) {
978 /* THIS MAY NEVER HAPPEN */
979 /* set error code */
980 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
981 return FALSE;
982 }
983 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
984 cffile.iFolder==cffileCONTINUED_TO_NEXT ) {
985 /* THIS MAY NEVER HAPPEN */
986 /* set error code */
987 fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE );
988 return FALSE;
989 }
990 if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
991 may_be_prev=FALSE;
992 }
993 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {
994 /* THIS MAY NEVER HAPPEN */