08e71f1270b50c982fb03aca7b4beb593b92a290
[reactos.git] / reactos / lib / cabinet / fci.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23
24 There is still some work to be done:
25
26 - currently no support for big-endian machines
27 - the ERF error structure aren't used on error
28 - no real compression yet
29 - unknown behaviour if files>4GB or cabinet >4GB
30 - incorrect status information
31 - check if the maximum size for a cabinet is too small to store any data
32 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
33
34 */
35
36
37
38 #include "config.h"
39
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winerror.h"
47 #include "fci.h"
48 #include "cabinet.h"
49
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
53
54 typedef struct {
55 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
56 cab_ULONG reserved1;
57 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
58 cab_ULONG reserved2;
59 cab_ULONG coffFiles; /* offset to first CFFILE section */
60 cab_ULONG reserved3;
61 cab_UBYTE versionMinor; /* 3 */
62 cab_UBYTE versionMajor; /* 1 */
63 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
64 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
65 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved setions*/
66 cab_UWORD setID; /* identification number of all cabinets in a set*/
67 cab_UWORD iCabinet; /* number of the cabinet in a set */
68 /* additional area if "flags" were set*/
69 } CFHEADER; /* minimum 36 bytes */
70
71 typedef struct {
72 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
73 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
74 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
75 /* additional area if reserve flag was set */
76 } CFFOLDER; /* minumum 8 bytes */
77
78 typedef struct {
79 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
80 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
81 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
82 /* for special values see below this structure*/
83 cab_UWORD date; /* last modification date*/
84 cab_UWORD time; /* last modification time*/
85 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
86 /* ... and a C string with the name of the file */
87 } CFFILE; /* 16 bytes + name of file */
88
89
90 typedef struct {
91 cab_ULONG csum; /* checksum of this entry*/
92 cab_UWORD cbData; /* number of compressed bytes */
93 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
94 /* optional reserved area */
95 /* compressed data */
96 } CFDATA;
97
98
99 /***********************************************************************
100 * FCICreate (CABINET.10)
101 *
102 * FCICreate is provided with several callbacks and
103 * returns a handle which can be used to create cabinet files.
104 *
105 * PARAMS
106 * perf [IO] A pointer to an ERF structure. When FCICreate
107 * returns an error condition, error information may
108 * be found here as well as from GetLastError.
109 * pfnfiledest [I] A pointer to a function which is called when a file
110 * is placed. Only useful for subsequent cabinet files.
111 * pfnalloc [I] A pointer to a function which allocates ram. Uses
112 * the same interface as malloc.
113 * pfnfree [I] A pointer to a function which frees ram. Uses the
114 * same interface as free.
115 * pfnopen [I] A pointer to a function which opens a file. Uses
116 * the same interface as _open.
117 * pfnread [I] A pointer to a function which reads from a file into
118 * a caller-provided buffer. Uses the same interface
119 * as _read.
120 * pfnwrite [I] A pointer to a function which writes to a file from
121 * a caller-provided buffer. Uses the same interface
122 * as _write.
123 * pfnclose [I] A pointer to a function which closes a file handle.
124 * Uses the same interface as _close.
125 * pfnseek [I] A pointer to a function which seeks in a file.
126 * Uses the same interface as _lseek.
127 * pfndelete [I] A pointer to a function which deletes a file.
128 * pfnfcigtf [I] A pointer to a function which gets the name of a
129 * temporary file.
130 * pccab [I] A pointer to an initialized CCAB structure.
131 * pv [I] A pointer to an application-defined notification
132 * function which will be passed to other FCI functions
133 * as a parameter.
134 *
135 * RETURNS
136 * On success, returns an FCI handle of type HFCI.
137 * On failure, the NULL file handle is returned. Error
138 * info can be retrieved from perf.
139 *
140 * INCLUDES
141 * fci.h
142 *
143 */
144 HFCI __cdecl FCICreate(
145 PERF perf,
146 PFNFCIFILEPLACED pfnfiledest,
147 PFNFCIALLOC pfnalloc,
148 PFNFCIFREE pfnfree,
149 PFNFCIOPEN pfnopen,
150 PFNFCIREAD pfnread,
151 PFNFCIWRITE pfnwrite,
152 PFNFCICLOSE pfnclose,
153 PFNFCISEEK pfnseek,
154 PFNFCIDELETE pfndelete,
155 PFNFCIGETTEMPFILE pfnfcigtf,
156 PCCAB pccab,
157 void *pv)
158 {
159 HFCI hfci;
160 int err;
161 PFCI_Int p_fci_internal;
162
163 if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
164 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
165 (!pfnfcigtf) || (!pccab)) {
166 perf->erfOper = FCIERR_NONE;
167 perf->erfType = ERROR_BAD_ARGUMENTS;
168 perf->fError = TRUE;
169
170 SetLastError(ERROR_BAD_ARGUMENTS);
171 return NULL;
172 }
173
174 if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) {
175 perf->erfOper = FCIERR_ALLOC_FAIL;
176 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
177 perf->fError = TRUE;
178
179 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
180 return NULL;
181 }
182
183 p_fci_internal=((PFCI_Int)(hfci));
184 p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC;
185 p_fci_internal->perf = perf;
186 p_fci_internal->pfnfiledest = pfnfiledest;
187 p_fci_internal->pfnalloc = pfnalloc;
188 p_fci_internal->pfnfree = pfnfree;
189 p_fci_internal->pfnopen = pfnopen;
190 p_fci_internal->pfnread = pfnread;
191 p_fci_internal->pfnwrite = pfnwrite;
192 p_fci_internal->pfnclose = pfnclose;
193 p_fci_internal->pfnseek = pfnseek;
194 p_fci_internal->pfndelete = pfndelete;
195 p_fci_internal->pfnfcigtf = pfnfcigtf;
196 p_fci_internal->pccab = pccab;
197 p_fci_internal->fPrevCab = FALSE;
198 p_fci_internal->fNextCab = FALSE;
199 p_fci_internal->fSplitFolder = FALSE;
200 p_fci_internal->fGetNextCabInVain = FALSE;
201 p_fci_internal->pv = pv;
202 p_fci_internal->data_in = NULL;
203 p_fci_internal->cdata_in = 0;
204 p_fci_internal->data_out = NULL;
205 p_fci_internal->cCompressedBytesInFolder = 0;
206 p_fci_internal->cFolders = 0;
207 p_fci_internal->cFiles = 0;
208 p_fci_internal->cDataBlocks = 0;
209 p_fci_internal->sizeFileCFDATA1 = 0;
210 p_fci_internal->sizeFileCFFILE1 = 0;
211 p_fci_internal->sizeFileCFDATA2 = 0;
212 p_fci_internal->sizeFileCFFILE2 = 0;
213 p_fci_internal->sizeFileCFFOLDER = 0;
214 p_fci_internal->sizeFileCFFOLDER = 0;
215 p_fci_internal->fNewPrevious = FALSE;
216
217 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
218 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
219
220 /* CFDATA */
221 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1,
222 CB_MAX_FILENAME)) {
223 /* TODO error handling */
224 return FALSE;
225 }
226 /* safety */
227 if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {
228 /* TODO set error code */
229 return FALSE;
230 }
231
232 p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci,
233 p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv);
234 /* TODO check handle */
235 /* TODO error checking of err */
236
237 /* array of all CFFILE in a folder */
238 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1,
239 CB_MAX_FILENAME)) {
240 /* TODO error handling */
241 return FALSE;
242 }
243 /* safety */
244 if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {
245 /* TODO set error code */
246 return FALSE;
247 }
248 p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci,
249 p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv);
250 /* TODO check handle */
251 /* TODO error checking of err */
252
253 /* CFDATA with checksum and ready to be copied into cabinet */
254 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2,
255 CB_MAX_FILENAME)) {
256 /* TODO error handling */
257 return FALSE;
258 }
259 /* safety */
260 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
261 /* TODO set error code */
262 return FALSE;
263 }
264 p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
265 p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv);
266 /* TODO check handle */
267 /* TODO error checking of err */
268
269 /* array of all CFFILE in a folder, ready to be copied into cabinet */
270 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
271 CB_MAX_FILENAME)) {
272 /* TODO error handling */
273 return FALSE;
274 }
275 /* safety */
276 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
277 /* TODO set error code */
278 return FALSE;
279 }
280 p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
281 p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv);
282 /* TODO check handle */
283 /* TODO error checking of err */
284
285 /* array of all CFFILE in a folder, ready to be copied into cabinet */
286 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,
287 CB_MAX_FILENAME)) {
288 /* TODO error handling */
289 return FALSE;
290 }
291 /* safety */
292 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
293 /* TODO set error code */
294 return FALSE;
295 }
296 p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
297 p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv);
298
299
300 /* TODO close and delete new files when return FALSE */
301
302 /* TODO check handle */
303 /* TODO error checking of err */
304
305 return hfci;
306 } /* end of FCICreate */
307
308
309
310
311
312
313 static BOOL fci_flush_data_block (HFCI hfci, int* err,
314 PFNFCISTATUS pfnfcis) {
315
316 /* attention no hfci checks!!! */
317 /* attention no checks if there is data available!!! */
318 CFDATA data;
319 CFDATA* cfdata=&data;
320 char* reserved;
321 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
322 UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
323 UINT i;
324
325 /* TODO compress the data of p_fci_internal->data_in */
326 /* and write it to p_fci_internal->data_out */
327 memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
328 p_fci_internal->cdata_in /* number of bytes to copy */);
329
330 cfdata->csum=0; /* checksum has to be set later */
331 /* TODO set realsize of compressed data */
332 cfdata->cbData = p_fci_internal->cdata_in;
333 cfdata->cbUncomp = p_fci_internal->cdata_in;
334
335 /* write cfdata to p_fci_internal->handleCFDATA1 */
336 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
337 cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
338 != sizeof(*cfdata) ) {
339 /* TODO write error */
340 return FALSE;
341 }
342 /* TODO error handling of err */
343
344 p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);
345
346 /* add optional reserved area */
347
348 /* This allocation and freeing at each CFData block is a bit */
349 /* inefficent, but it's harder to forget about freeing the buffer :-). */
350 /* Reserved areas are used seldom besides that... */
351 if (cbReserveCFData!=0) {
352 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) {
353 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
354 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
355 p_fci_internal->perf->fError = TRUE;
356 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
357 return FALSE;
358 }
359 for(i=0;i<cbReserveCFData;) {
360 reserved[i++]='\0';
361 }
362 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
363 reserved, /* memory buffer */
364 cbReserveCFData, /* number of bytes to copy */
365 err, p_fci_internal->pv) != cbReserveCFData ) {
366 PFCI_FREE(hfci, reserved);
367 /* TODO write error */
368 return FALSE;
369 }
370 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
371
372 p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;
373 PFCI_FREE(hfci, reserved);
374 }
375
376 /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
377 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
378 p_fci_internal->data_out, /* memory buffer */
379 cfdata->cbData, /* number of bytes to copy */
380 err, p_fci_internal->pv) != cfdata->cbData) {
381 /* TODO write error */
382 return FALSE;
383 }
384 /* TODO error handling of err */
385
386 p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;
387
388 /* reset the offset */
389 p_fci_internal->cdata_in = 0;
390 p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
391
392 /* report status with pfnfcis about uncompressed and compressed file data */
393 if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
394 p_fci_internal->pv) == -1) {
395 /* TODO set error code and abort */
396 return FALSE;
397 }
398
399 ++(p_fci_internal->cDataBlocks);
400
401 return TRUE;
402 } /* end of fci_flush_data_block */
403
404
405
406
407
408 static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed)
409 {
410 cab_ULONG csum;
411 cab_ULONG ul;
412 int cUlong;
413 BYTE *pb;
414
415 csum = seed;
416 cUlong = cb / 4;
417 pb = pv;
418
419 while (cUlong-- > 0) {
420 ul = *pb++;
421 ul |= (((cab_ULONG)(*pb++)) << 8);
422 ul |= (((cab_ULONG)(*pb++)) << 16);
423 ul |= (((cab_ULONG)(*pb++)) << 24);
424
425 csum ^= ul;
426 }
427
428 ul = 0;
429 switch (cb % 4) {
430 case 3:
431 ul |= (((ULONG)(*pb++)) << 16);
432 case 2:
433 ul |= (((ULONG)(*pb++)) << 8);
434 case 1:
435 ul |= *pb++;
436 default:
437 break;
438 }
439 csum ^= ul;
440
441 return csum;
442 } /* end of fci_get_checksum */
443
444
445
446
447
448 static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData,
449 PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,
450 cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)
451 {
452 cab_ULONG read_result;
453 CFDATA* pcfdata=(CFDATA*)buffer;
454 BOOL split_block=FALSE;
455 cab_UWORD savedUncomp=0;
456 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
457
458 *payload=0;
459
460 /* while not all CFDATAs have been copied do */
461 while(!FALSE) {
462 if( p_fci_internal->fNextCab ) {
463 if( split_block ) {
464 /* TODO internal error should never happen */
465 return FALSE;
466 }
467 }
468 /* REUSE the variable read_result */
469 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
470 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
471 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
472 read_result=4;
473 } else {
474 read_result=0;
475 }
476 if (p_fci_internal->fPrevCab) {
477 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
478 strlen(p_fci_internal->szPrevDisk)+1;
479 }
480 /* No more CFDATA fits into the cabinet under construction */
481 /* So don't try to store more data into it */
482 if( p_fci_internal->fNextCab &&
483 (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +
484 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
485 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
486 sizeof(CFHEADER) +
487 read_result +
488 p_fci_internal->oldCCAB.cbReserveCFHeader +
489 sizeof(CFFOLDER) +
490 p_fci_internal->oldCCAB.cbReserveCFFolder +
491 strlen(p_fci_internal->pccab->szCab)+1 +
492 strlen(p_fci_internal->pccab->szDisk)+1
493 )) {
494 /* This may never be run for the first time the while loop is entered.
495 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
496 split_block=TRUE; /* In this case split_block is abused to store */
497 /* the complete data block into the next cabinet and not into the */
498 /* current one. Originally split_block is the indicator that a */
499 /* data block has been splitted across different cabinets. */
500 } else {
501
502 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
503 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/
504 buffer, /* memory buffer */
505 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
506 err, p_fci_internal->pv);
507 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
508 if (read_result==0) break; /* ALL DATA has been copied */
509 /* TODO read error */
510 return FALSE;
511 }
512 /* TODO error handling of err */
513
514 /* REUSE buffer p_fci_internal->data_out !!! */
515 /* read data from p_fci_internal->handleCFDATA1 to */
516 /* p_fci_internal->data_out */
517 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
518 p_fci_internal->data_out /* memory buffer */,
519 pcfdata->cbData /* number of bytes to copy */,
520 err, p_fci_internal->pv) != pcfdata->cbData ) {
521 /* TODO read error */
522 return FALSE;
523 }
524 /* TODO error handling of err */
525
526 /* if cabinet size is too large */
527
528 /* REUSE the variable read_result */
529 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
530 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
531 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
532 read_result=4;
533 } else {
534 read_result=0;
535 }
536 if (p_fci_internal->fPrevCab) {
537 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
538 strlen(p_fci_internal->szPrevDisk)+1;
539 }
540
541 /* Is cabinet with new CFDATA too large? Then data block has to be split */
542 if( p_fci_internal->fNextCab &&
543 (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +
544 pcfdata->cbData +
545 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
546 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
547 sizeof(CFHEADER) +
548 read_result +
549 p_fci_internal->oldCCAB.cbReserveCFHeader +
550 sizeof(CFFOLDER) + /* size of new CFFolder entry */
551 p_fci_internal->oldCCAB.cbReserveCFFolder +
552 strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */
553 strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */
554 )) {
555 /* REUSE read_result to save the size of the compressed data */
556 read_result=pcfdata->cbData;
557 /* Modify the size of the compressed data to store only a part of the */
558 /* data block into the current cabinet. This is done to prevent */
559 /* that the maximum cabinet size will be exceeded. The remainer */
560 /* will be stored into the next following cabinet. */
561
562 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
563 /* Substract everything except the size of the block of data */
564 /* to get it's actual size */
565 pcfdata->cbData = p_fci_internal->oldCCAB.cb - (
566 sizeof(CFDATA) + cbReserveCFData +
567 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
568 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
569 sizeof(CFHEADER) +
570 p_fci_internal->oldCCAB.cbReserveCFHeader +
571 sizeof(CFFOLDER) + /* set size of new CFFolder entry */
572 p_fci_internal->oldCCAB.cbReserveCFFolder );
573 /* substract the size of special header fields */
574 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
575 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
576 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
577 pcfdata->cbData-=4;
578 }
579 if (p_fci_internal->fPrevCab) {
580 pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +
581 strlen(p_fci_internal->szPrevDisk)+1;
582 }
583 pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +
584 strlen(p_fci_internal->pccab->szDisk)+1;
585
586 savedUncomp = pcfdata->cbUncomp;
587 pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */
588
589 /* if split_block==TRUE then the above while loop won't */
590 /* be executed again */
591 split_block=TRUE; /* split_block is the indicator that */
592 /* a data block has been splitted across */
593 /* diffentent cabinets.*/
594 }
595
596 /* This should never happen !!! */
597 if (pcfdata->cbData==0) {
598 /* TODO set error */
599 return FALSE;
600 }
601
602 /* get checksum and write to cfdata.csum */
603 pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
604 sizeof(CFDATA)+cbReserveCFData -
605 sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
606 pcfdata->cbData, 0 ) );
607
608 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
609 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
610 buffer, /* memory buffer */
611 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
612 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
613 /* TODO write error */
614 return FALSE;
615 }
616 /* TODO error handling of err */
617
618 p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;
619
620 /* write compressed data into p_fci_internal->handleCFDATA2 */
621 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
622 p_fci_internal->data_out, /* memory buffer */
623 pcfdata->cbData, /* number of bytes to copy */
624 err, p_fci_internal->pv) != pcfdata->cbData) {
625 /* TODO write error */
626 return FALSE;
627 }
628 /* TODO error handling of err */
629
630 p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;
631 ++(p_fci_internal->cDataBlocks);
632 p_fci_internal->statusFolderCopied += pcfdata->cbData;
633 (*payload)+=pcfdata->cbUncomp;
634 /* if cabinet size too large and data has been split */
635 /* write the remainer of the data block to the new CFDATA1 file */
636 if( split_block ) { /* This does not include the */
637 /* abused one (just search for "abused" )*/
638 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
639 if (p_fci_internal->fNextCab==FALSE ) {
640 /* TODO internal error */
641 return FALSE;
642 }
643
644 /* set cbData the size of the remainer of the data block */
645 pcfdata->cbData = read_result - pcfdata->cbData;
646 /*recover former value of cfdata.cbData; read_result will be the offset*/
647 read_result -= pcfdata->cbData;
648 pcfdata->cbUncomp = savedUncomp;
649
650 /* reset checksum, it will be computed later */
651 pcfdata->csum=0;
652 /* write cfdata WITHOUT checksum to handleCFDATA1new */
653 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
654 buffer, /* memory buffer */
655 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
656 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
657 /* TODO write error */
658 return FALSE;
659 }
660 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
661
662 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
663
664 /* write compressed data into handleCFDATA1new */
665 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
666 p_fci_internal->data_out + read_result, /* memory buffer + offset */
667 /* to last part of split data */
668 pcfdata->cbData, /* number of bytes to copy */
669 err, p_fci_internal->pv) != pcfdata->cbData) {
670 /* TODO write error */
671 return FALSE;
672 }
673 /* TODO error handling of err */
674
675 p_fci_internal->statusFolderCopied += pcfdata->cbData;
676
677 *psizeFileCFDATA1new += pcfdata->cbData;
678 /* the two blocks of the split data block have been written */
679 /* dont reset split_data yet, because it is still needed see below */
680 }
681
682 /* report status with pfnfcis about copied size of folder */
683 if( (*pfnfcis)(statusFolder,
684 p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
685 p_fci_internal->statusFolderTotal, /* total folder size */
686 p_fci_internal->pv) == -1) {
687 /* TODO set error code and abort */
688 return FALSE;
689 }
690 }
691
692 /* if cabinet size too large */
693 /* write the remaining data blocks to the new CFDATA1 file */
694 if ( split_block ) { /* This does include the */
695 /* abused one (just search for "abused" )*/
696 if (p_fci_internal->fNextCab==FALSE ) {
697 /* TODO internal error */
698 return FALSE;
699 }
700 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
701 while(!FALSE) {
702 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
703 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */
704 buffer, /* memory buffer */
705 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
706 err, p_fci_internal->pv);
707 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
708 if (read_result==0) break; /* ALL DATA has been copied */
709 /* TODO read error */
710 return FALSE;
711 }
712 /* TODO error handling of err */
713
714 /* REUSE buffer p_fci_internal->data_out !!! */
715 /* read data from p_fci_internal->handleCFDATA1 to */
716 /* p_fci_internal->data_out */
717 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
718 p_fci_internal->data_out /* memory buffer */,
719 pcfdata->cbData /* number of bytes to copy */,
720 err, p_fci_internal->pv) != pcfdata->cbData ) {
721 /* TODO read error */
722 return FALSE;
723 }
724 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
725
726 /* write cfdata with checksum to handleCFDATA1new */
727 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
728 buffer, /* memory buffer */
729 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
730 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
731 /* TODO write error */
732 return FALSE;
733 }
734 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
735
736 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
737
738 /* write compressed data into handleCFDATA1new */
739 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
740 p_fci_internal->data_out, /* memory buffer */
741 pcfdata->cbData, /* number of bytes to copy */
742 err, p_fci_internal->pv) != pcfdata->cbData) {
743 /* TODO write error */
744 return FALSE;
745 }
746 /* TODO error handling of err */
747
748 *psizeFileCFDATA1new += pcfdata->cbData;
749 p_fci_internal->statusFolderCopied += pcfdata->cbData;
750
751 /* report status with pfnfcis about copied size of folder */
752 if( (*pfnfcis)(statusFolder,
753 p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/
754 p_fci_internal->statusFolderTotal, /* total folder size */
755 p_fci_internal->pv) == -1) {
756 /* TODO set error code and abort */
757 return FALSE;
758 }
759
760 } /* end of WHILE */
761 break; /* jump out of the next while loop */
762 } /* end of if( split_data ) */
763 } /* end of WHILE */
764 return TRUE;
765 } /* end of fci_flushfolder_copy_cfdata */
766
767
768
769
770
771 static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder,
772 cab_ULONG sizeFileCFDATA2old)
773 {
774 CFFOLDER cffolder;
775 UINT i;
776 char* reserved;
777 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
778
779 /* absolute offset cannot be set yet, because the size of cabinet header, */
780 /* the number of CFFOLDERs and the number of CFFILEs may change. */
781 /* Instead the size of all previous data blocks will be stored and */
782 /* the remainer of the offset will be added when the cabinet will be */
783 /* flushed to disk. */
784 /* This is exactly the way the original CABINET.DLL works!!! */
785 cffolder.coffCabStart=sizeFileCFDATA2old;
786
787 /* set the number of this folder's CFDATA sections */
788 cffolder.cCFData=p_fci_internal->cDataBlocks;
789 /* TODO set compression type */
790 cffolder.typeCompress = tcompTYPE_NONE;
791
792 /* write cffolder to p_fci_internal->handleCFFOLDER */
793 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
794 &cffolder, /* memory buffer */
795 sizeof(cffolder), /* number of bytes to copy */
796 err, p_fci_internal->pv) != sizeof(cffolder) ) {
797 /* TODO write error */
798 return FALSE;
799 }
800 /* TODO error handling of err */
801
802 p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);
803
804 /* add optional reserved area */
805 if (cbReserveCFFolder!=0) {
806 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) {
807 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
808 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
809 p_fci_internal->perf->fError = TRUE;
810 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
811 return FALSE;
812 }
813 for(i=0;i<cbReserveCFFolder;) {
814 reserved[i++]='\0';
815 }
816 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
817 reserved, /* memory buffer */
818 cbReserveCFFolder, /* number of bytes to copy */
819 err, p_fci_internal->pv) != cbReserveCFFolder ) {
820 PFCI_FREE(hfci, reserved);
821 /* TODO write error */
822 return FALSE;
823 }
824 /* TODO error handling of err */
825
826 p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;
827
828 PFCI_FREE(hfci, reserved);
829 }
830 return TRUE;
831 } /* end of fci_flushfolder_copy_cffolder */
832
833
834
835
836
837 static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new,
838 cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)
839 {
840 CFFILE cffile;
841 cab_ULONG read_result;
842 cab_ULONG seek=0;
843 cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;
844 BOOL may_be_prev=TRUE;
845 cab_ULONG cbFileRemainer=0;
846 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
847 /* set seek of p_fci_internal->handleCFFILE1 to 0 */
848 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err,
849 p_fci_internal->pv) !=0 ) {
850 /* TODO wrong return value */
851 }
852 /* TODO error handling of err */
853
854 /* while not all CFFILE structures have been copied do */
855 while(!FALSE) {
856 /* REUSE the variable read_result */
857 /* read data from p_fci_internal->handleCFFILE1 to cffile */
858 read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */,
859 &cffile, /* memory buffer */
860 sizeof(cffile), /* number of bytes to copy */
861 err, p_fci_internal->pv);
862 if( read_result != sizeof(cffile) ) {
863 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
864 /* TODO read error */
865 return FALSE;
866 }
867 /* TODO error handling of err */
868
869 /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
870 /* position. I don't know why so I'll just omit it */
871
872 /* read the filename from p_fci_internal->handleCFFILE1 */
873 /* REUSE the variable read_result AGAIN */
874 /* REUSE the memory buffer PFCI(hfci)->data_out */
875 if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/,
876 p_fci_internal->data_out, /* memory buffer */
877 CB_MAX_FILENAME, /* number of bytes to copy */
878 err, p_fci_internal->pv) <2) {
879 /* TODO read error */
880 return FALSE;
881 }
882 /* TODO maybe other checks of read_result */
883 /* TODO error handling of err */
884
885 /* safety */
886 if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {
887 /* TODO set error code internal error */
888 return FALSE;
889 }
890
891 seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;
892
893 /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
894 /* i.e. seek to the next CFFILE area */
895 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,
896 seek, /* seek position*/
897 SEEK_SET ,err,
898 p_fci_internal->pv)
899 != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) {
900 /* TODO wrong return value */
901 }
902 /* TODO error handling of err */
903
904 /* fnfilfnfildest: placed file on cabinet */
905 if (p_fci_internal->fNextCab ||
906 p_fci_internal->fGetNextCabInVain) {
907 PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB),
908 p_fci_internal->data_out, /* the file name*/
909 cffile.cbFile, /* file size */
910 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
911 p_fci_internal->pv
912 );
913 } else {
914 PFCI_FILEPLACED( hfci, p_fci_internal->pccab,
915 p_fci_internal->data_out, /* the file name*/
916 cffile.cbFile, /* file size */
917 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
918 p_fci_internal->pv
919 );
920 }
921
922 /* Check special iFolder values */
923 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
924 p_fci_internal->fPrevCab==FALSE ) {
925 /* THIS MAY NEVER HAPPEN */
926 /* TODO set error code */
927 return FALSE;
928 }
929 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
930 cffile.iFolder==cffileCONTINUED_TO_NEXT ) {
931 /* THIS MAY NEVER HAPPEN */
932 /* TODO set error code */
933 return FALSE;
934 }
935 if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
936 may_be_prev=FALSE;
937 }
938 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {
939 /* THIS MAY NEVER HAPPEN */
940 /* TODO set error code */
941 return FALSE;
942 }
943 if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
944 may_be_prev=FALSE;
945 }
946
947 sizeOfFilesPrev=sizeOfFiles;
948 /* Set complete size of all processed files */
949 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
950 p_fci_internal->cbFileRemainer!=0
951 ) {
952 sizeOfFiles+=p_fci_internal->cbFileRemainer;
953 p_fci_internal->cbFileRemainer=0;
954 } else {
955 sizeOfFiles+=cffile.cbFile;
956 }
957
958 /* Check if spanned file fits into this cabinet folder */
959 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) {
960 cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT;
961 } else
962
963 /* Check if file doesn't fit into this cabinet folder */
964 if( sizeOfFiles>payload ) {
965 cffile.iFolder=cffileCONTINUED_TO_NEXT;
966 }
967
968 /* write cffile to p_fci_internal->handleCFFILE2 */
969 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
970 &cffile, /* memory buffer */
971 sizeof(cffile), /* number of bytes to copy */
972 err, p_fci_internal->pv) != sizeof(cffile) ) {
973 /* TODO write error */
974 return FALSE;
975 }
976 /* TODO error handling of err */
977
978 p_fci_internal->sizeFileCFFILE2 += sizeof(cffile);
979
980 /* write file name to p_fci_internal->handleCFFILE2 */
981 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
982 p_fci_internal->data_out, /* memory buffer */
983 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
984 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
985 /* TODO write error */
986 return FALSE;
987 }
988 /* TODO error handling of err */
989
990 p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1;
991
992 /* cFiles is used to count all files of a cabinet */
993 ++(p_fci_internal->cFiles);
994
995 /* This is only true for files which will be written into the */
996 /* next cabinet of the spanning folder */
997 if( sizeOfFiles>payload ) {
998
999 /* Files which data will be partially written into the current cabinet */
1000 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
1001 cffile.iFolder==cffileCONTINUED_TO_NEXT
1002 ) {
1003 if( sizeOfFilesPrev<=payload ) {
1004 /* The size of the uncompressed, data of a spanning file in a */
1005 /* spanning data */
1006 cbFileRemainer=sizeOfFiles-payload;
1007 }
1008 cffile.iFolder=cffileCONTINUED_FROM_PREV;
1009 } else {
1010 cffile.iFolder=0;
1011 }
1012
1013 /* write cffile into handleCFFILE1new */
1014 if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1015 &cffile, /* memory buffer */
1016 sizeof(cffile), /* number of bytes to copy */
1017 err, p_fci_internal->pv) != sizeof(cffile) ) {
1018 /* TODO write error */
1019 return FALSE;
1020 }
1021 /* TODO error handling of err */
1022
1023 *psizeFileCFFILE1new += sizeof(cffile);
1024 /* write name of file into handleCFFILE1new */
1025 if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1026 p_fci_internal->data_out, /* memory buffer */
1027 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1028 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1029 /* TODO write error */
1030 return FALSE;
1031 }
1032 /* TODO error handling of err */
1033
1034 *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1;
1035 }
1036
1037 } /* END OF while */
1038 p_fci_internal->cbFileRemainer=cbFileRemainer;
1039 return TRUE;
1040 } /* end of fci_flushfolder_copy_cffile */
1041
1042
1043
1044
1045 static BOOL fci_flush_folder(
1046 HFCI hfci,
1047 BOOL fGetNextCab,
1048 PFNFCIGETNEXTCABINET pfnfcignc,
1049 PFNFCISTATUS pfnfcis)
1050 {
1051 int err;
1052 int handleCFDATA1new; /* handle for new temp file */
1053 char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1054 int handleCFFILE1new; /* handle for new temp file */
1055 char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1056 UINT cbReserveCFData, cbReserveCFFolder;
1057 char* reserved;
1058 cab_ULONG sizeFileCFDATA1new=0;
1059 cab_ULONG sizeFileCFFILE1new=0;
1060 cab_ULONG sizeFileCFDATA2old;
1061 cab_ULONG payload;
1062 cab_ULONG read_result;
1063 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1064
1065 /* test hfci */
1066 if (!REALLY_IS_FCI(hfci)) {
1067 SetLastError(ERROR_INVALID_HANDLE);
1068 return FALSE;
1069 }
1070
1071 if ((!pfnfcignc) || (!pfnfcis)) {
1072 p_fci_internal->perf->erfOper = FCIERR_NONE;
1073 p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
1074 p_fci_internal->perf->fError = TRUE;
1075
1076 SetLastError(ERROR_BAD_ARGUMENTS);
1077 return FALSE;
1078 }
1079
1080 if( p_fci_internal->fGetNextCabInVain &&
1081 p_fci_internal->fNextCab ){
1082 /* TODO internal error */
1083 return FALSE;
1084 }
1085
1086 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1087 /* this function will return TRUE */
1088 if( p_fci_internal->sizeFileCFFILE1 == 0 ) {
1089 if ( p_fci_internal->sizeFileCFDATA1 != 0 ) {
1090 /* TODO error handling */
1091 return FALSE;
1092 }
1093 return TRUE;
1094 }
1095
1096 if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1097 /* TODO error handling */
1098 return FALSE;
1099 }
1100
1101 /* FCIFlushFolder has already been called... */
1102 if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) {
1103 if (p_fci_internal->sizeFileCFFILE2==0) {
1104 /* TODO set error code */
1105 return FALSE;
1106 }
1107 return TRUE;
1108 }
1109
1110 /* TODO check what will happen when return FALSE later */
1111 /* and p_fci_internal->fSplitFolder is set to FALSE */
1112 p_fci_internal->fSplitFolder=FALSE;
1113
1114
1115 if( p_fci_internal->fGetNextCabInVain ||
1116 p_fci_internal->fNextCab ){
1117 cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1118 cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder;
1119 } else {
1120 cbReserveCFData = p_fci_internal->pccab->cbReserveCFData;
1121 cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder;
1122 }
1123
1124 /* START of COPY */
1125 /* if there is data in p_fci_internal->data_in */
1126 if (p_fci_internal->cdata_in!=0) {
1127
1128 if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
1129
1130 }
1131 /* reset to get the number of data blocks of this folder which are */
1132 /* actually in this cabinet ( at least partially ) */
1133 p_fci_internal->cDataBlocks=0;
1134
1135 if ( p_fci_internal->fNextCab ||
1136 p_fci_internal->fGetNextCabInVain ) {
1137 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+
1138 p_fci_internal->oldCCAB.cbReserveCFFolder;
1139 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1140 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1141 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1142 read_result+=4;
1143 }
1144 } else {
1145 read_result= p_fci_internal->pccab->cbReserveCFHeader+
1146 p_fci_internal->pccab->cbReserveCFFolder;
1147 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1148 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1149 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1150 read_result+=4;
1151 }
1152 }
1153 if (p_fci_internal->fPrevCab) {
1154 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1155 strlen(p_fci_internal->szPrevDisk)+1;
1156 }
1157 if (p_fci_internal->fNextCab) {
1158 read_result+=strlen(p_fci_internal->pccab->szCab)+1 +
1159 strlen(p_fci_internal->pccab->szDisk)+1;
1160 }
1161
1162 p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+
1163 sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+
1164 p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+
1165 p_fci_internal->sizeFileCFDATA1;
1166 p_fci_internal->statusFolderCopied = 0;
1167
1168 /* report status with pfnfcis about copied size of folder */
1169 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1170 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1171 p_fci_internal->pv) == -1) {
1172 /* TODO set error code and abort */
1173 return FALSE;
1174 }
1175
1176 /* get a new temp file */
1177 if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) {
1178 /* TODO error handling */
1179 return FALSE;
1180 }
1181 /* safety */
1182 if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) {
1183 /* TODO set error code */
1184 return FALSE;
1185 }
1186 handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err,
1187 p_fci_internal->pv);
1188
1189 /* get a new temp file */
1190 if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) {
1191 /* TODO error handling */
1192 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1193 /* TODO error handling of err */
1194 return FALSE;
1195 }
1196 /* safety */
1197 if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) {
1198 /* TODO set error code */
1199 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1200 /* TODO error handling of err */
1201 return FALSE;
1202 }
1203 handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err,
1204 p_fci_internal->pv);
1205
1206 /* USE the variable read_result */
1207 if ( p_fci_internal->fNextCab ||
1208 p_fci_internal->fGetNextCabInVain ) {
1209 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader;
1210 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1211 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1212 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1213 read_result+=4;
1214 }
1215 } else {
1216 read_result= p_fci_internal->pccab->cbReserveCFHeader;
1217 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1218 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1219 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1220 read_result+=4;
1221 }
1222 }
1223 if (p_fci_internal->fPrevCab) {
1224 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1225 strlen(p_fci_internal->szPrevDisk)+1;
1226 }
1227 read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 +
1228 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER;
1229
1230 if(p_fci_internal->sizeFileCFFILE1!=0) {
1231 read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder;
1232 }
1233
1234 /* Check if multiple cabinets have to be created. */
1235
1236 /* Might be too much data for the maximum allowed cabinet size.*/
1237 /* When any further data will be added later, it might not */
1238 /* be possible to flush the cabinet, because there might */
1239 /* not be enough space to store the name of the following */
1240 /* cabinet and name of the corresponding disk. */
1241 /* So take care of this and get the name of the next cabinet */
1242 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1243 p_fci_internal->fNextCab==FALSE &&
1244 (
1245 (
1246 p_fci_internal->pccab->cb < read_result +
1247 p_fci_internal->sizeFileCFDATA1 +
1248 p_fci_internal->sizeFileCFFILE1 +
1249 CB_MAX_CABINET_NAME + /* next cabinet name */
1250 CB_MAX_DISK_NAME /* next disk name */
1251 ) || fGetNextCab
1252 )
1253 ) {
1254 /* save CCAB */
1255 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
1256 /* increment cabinet index */
1257 ++(p_fci_internal->pccab->iCab);
1258 /* get name of next cabinet */
1259 if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
1260 p_fci_internal->pv)) {
1261 /* TODO error handling */
1262 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1263 /* TODO error handling of err */
1264 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1265 /* TODO error handling of err */
1266 return FALSE;
1267 }
1268
1269 /* Skip a few lines of code. This is catched by the next if. */
1270 p_fci_internal->fGetNextCabInVain=TRUE;
1271 }
1272
1273 /* too much data for cabinet */
1274 if( (p_fci_internal->fGetNextCabInVain ||
1275 p_fci_internal->fNextCab ) &&
1276 (
1277 (
1278 p_fci_internal->oldCCAB.cb < read_result +
1279 p_fci_internal->sizeFileCFDATA1 +
1280 p_fci_internal->sizeFileCFFILE1 +
1281 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1282 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1283 ) || fGetNextCab
1284 )
1285 ) {
1286 p_fci_internal->fGetNextCabInVain=FALSE;
1287 p_fci_internal->fNextCab=TRUE;
1288
1289 /* return FALSE if there is not enough space left*/
1290 /* this should never happen */
1291 if (p_fci_internal->oldCCAB.cb <=
1292 p_fci_internal->sizeFileCFFILE1 +
1293 read_result +
1294 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1295 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1296 ) {
1297
1298 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1299 /* TODO error handling of err */
1300 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1301 /* TODO error handling of err */
1302
1303 /* close and delete p_fci_internal->handleCFFILE1 */
1304 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1305 /* TODO error handling of err */
1306 PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1307 /* TODO error handling of err */
1308
1309 return FALSE;
1310 }
1311
1312 /* the folder will be split across cabinets */
1313 p_fci_internal->fSplitFolder=TRUE;
1314
1315 } else {
1316 /* this should never happen */
1317 if (p_fci_internal->fNextCab) {
1318 /* TODO internal error */
1319 return FALSE;
1320 }
1321 }
1322
1323 /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1324 if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err,
1325 p_fci_internal->pv) !=0 ) {
1326 /* TODO wrong return value */
1327 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1328 /* TODO error handling of err */
1329 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1330 /* TODO error handling of err */
1331 return FALSE;
1332 }
1333 /* TODO error handling of err */
1334
1335 /* save size of file CFDATA2 - required for the folder's offset to data */
1336 sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2;
1337
1338 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) {
1339 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1340 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1341 p_fci_internal->perf->fError = TRUE;
1342 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1343 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1344 /* TODO error handling of err */
1345 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1346 /* TODO error handling of err */
1347 return FALSE;
1348 }
1349
1350 if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err,
1351 handleCFDATA1new, &sizeFileCFDATA1new, &payload
1352 )) {
1353 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1354 /* TODO error handling of err */
1355 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1356 /* TODO error handling of err */
1357 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1358 /* TODO error handling of err */
1359 PFCI_FREE(hfci,reserved);
1360 return FALSE;
1361 }
1362
1363 PFCI_FREE(hfci,reserved);
1364
1365 if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder,
1366 sizeFileCFDATA2old )) {
1367 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1368 /* TODO error handling of err */
1369 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1370 /* TODO error handling of err */
1371 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1372 /* TODO error handling of err */
1373 return FALSE;
1374 }
1375
1376 if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new,
1377 &sizeFileCFFILE1new, payload)) {
1378 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1379 /* TODO error handling of err */
1380 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1381 /* TODO error handling of err */
1382 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1383 /* TODO error handling of err */
1384 PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1385 /* TODO error handling of err */
1386 return FALSE;
1387 }
1388
1389 /* close and delete p_fci_internal->handleCFDATA1 */
1390 PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
1391 /* TODO error handling of err */
1392 PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv);
1393 /* TODO error handling of err */
1394
1395 /* put new CFDATA1 into hfci */
1396 memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new,
1397 CB_MAX_FILENAME);
1398
1399 /* put CFDATA1 file handle */
1400 PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new;
1401 /* set file size */
1402 PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new;
1403
1404 /* close and delete PFCI_INT(hfci)->handleCFFILE1 */
1405 PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv);
1406 /* TODO error handling of err */
1407 PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv);
1408 /* TODO error handling of err */
1409
1410 /* put new CFFILE1 into hfci */
1411 memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new,
1412 CB_MAX_FILENAME);
1413
1414 /* put CFFILE1 file handle */
1415 p_fci_internal->handleCFFILE1 = handleCFFILE1new;
1416 /* set file size */
1417 p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new;
1418
1419 ++(p_fci_internal->cFolders);
1420
1421 /* reset CFFolder specific information */
1422 p_fci_internal->cDataBlocks=0;
1423 p_fci_internal->cCompressedBytesInFolder=0;
1424
1425 return TRUE;
1426 } /* end of fci_flush_folder */
1427
1428
1429
1430
1431 static BOOL fci_flush_cabinet(
1432 HFCI hfci,
1433 BOOL fGetNextCab,
1434 PFNFCIGETNEXTCABINET pfnfcignc,
1435 PFNFCISTATUS pfnfcis)
1436 {
1437 int err;
1438 CFHEADER cfheader;
1439 struct {
1440 cab_UWORD cbCFHeader;
1441 cab_UBYTE cbCFFolder;
1442 cab_UBYTE cbCFData;
1443 } cfreserved;
1444 CFFOLDER cffolder;
1445 cab_ULONG read_result;
1446 int handleCABINET; /* file handle for cabinet */
1447 char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */
1448 UINT cbReserveCFHeader, cbReserveCFFolder, i;
1449 char* reserved;
1450 BOOL returntrue=FALSE;
1451 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1452
1453 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1454
1455 /* when FCIFlushCabinet was or FCIAddFile wasn't called */
1456 if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) {
1457 returntrue=TRUE;
1458 }
1459
1460 if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){
1461 /* TODO set error */
1462 return FALSE;
1463 }
1464
1465 if(returntrue) return TRUE;
1466
1467 if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) {
1468 /* TODO internal error */
1469 return FALSE;
1470 }
1471
1472 if( p_fci_internal->fNextCab ||
1473 p_fci_internal->fGetNextCabInVain ) {
1474 cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder;
1475 cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader;
1476 /* safety */
1477 if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH ||
1478 strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) {
1479 /* TODO set error */
1480 return FALSE;
1481 }
1482 /* get the full name of the cabinet */
1483 memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath,
1484 CB_MAX_CAB_PATH);
1485 memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1486 p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME);
1487 } else {
1488 cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder;
1489 cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader;
1490 /* safety */
1491 if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH ||
1492 strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) {
1493 /* TODO set error */
1494 return FALSE;
1495 }
1496 /* get the full name of the cabinet */
1497 memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath,
1498 CB_MAX_CAB_PATH);
1499 memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1500 p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME);
1501 }
1502
1503 /* create the cabinet */
1504 handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET,
1505 33538, 384, &err, p_fci_internal->pv );
1506 /* TODO check handle */
1507 /* TODO error checking of err */
1508
1509 memcpy(cfheader.signature,"!CAB",4);
1510 cfheader.reserved1=0;
1511 cfheader.cbCabinet= /* size of the cabinet file in bytes */
1512 sizeof(CFHEADER) +
1513 p_fci_internal->sizeFileCFFOLDER +
1514 p_fci_internal->sizeFileCFFILE2 +
1515 p_fci_internal->sizeFileCFDATA2;
1516
1517 if (p_fci_internal->fPrevCab) {
1518 cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 +
1519 strlen(p_fci_internal->szPrevDisk)+1;
1520 }
1521 if (p_fci_internal->fNextCab) {
1522 cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 +
1523 strlen(p_fci_internal->pccab->szDisk)+1;
1524 }
1525 if( p_fci_internal->fNextCab ||
1526 p_fci_internal->fGetNextCabInVain ) {
1527 cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1528 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1529 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1530 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1531 cfheader.cbCabinet+=4;
1532 }
1533 } else {
1534 cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader;
1535 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1536 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1537 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1538 cfheader.cbCabinet+=4;
1539 }
1540 }
1541
1542 cfheader.reserved2=0;
1543 cfheader.coffFiles= /* offset to first CFFILE section */
1544 cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 -
1545 p_fci_internal->sizeFileCFDATA2;
1546
1547 cfheader.reserved3=0;
1548 cfheader.versionMinor=3;
1549 cfheader.versionMajor=1;
1550 /* number of CFFOLDER entries in the cabinet */
1551 cfheader.cFolders=p_fci_internal->cFolders;
1552 /* number of CFFILE entries in the cabinet */
1553 cfheader.cFiles=p_fci_internal->cFiles;
1554 cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved setions */
1555
1556 if( p_fci_internal->fPrevCab ) {
1557 cfheader.flags = cfheadPREV_CABINET;
1558 }
1559
1560 if( p_fci_internal->fNextCab ) {
1561 cfheader.flags |= cfheadNEXT_CABINET;
1562 }
1563
1564 if( p_fci_internal->fNextCab ||
1565 p_fci_internal->fGetNextCabInVain ) {
1566 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1567 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1568 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1569 cfheader.flags |= cfheadRESERVE_PRESENT;
1570 }
1571 cfheader.setID = p_fci_internal->oldCCAB.setID;
1572 cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1;
1573 } else {
1574 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1575 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1576 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1577 cfheader.flags |= cfheadRESERVE_PRESENT;
1578 }
1579 cfheader.setID = p_fci_internal->pccab->setID;
1580 cfheader.iCabinet = p_fci_internal->pccab->iCab-1;
1581 }
1582
1583 /* write CFHEADER into cabinet file */
1584 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1585 &cfheader, /* memory buffer */
1586 sizeof(cfheader), /* number of bytes to copy */
1587 &err, p_fci_internal->pv) != sizeof(cfheader) ) {
1588 /* TODO write error */
1589 return FALSE;
1590 }
1591 /* TODO error handling of err */
1592
1593 if( cfheader.flags & cfheadRESERVE_PRESENT ) {
1594 /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1595 cfreserved.cbCFHeader = cbReserveCFHeader;
1596 cfreserved.cbCFFolder = cbReserveCFFolder;
1597 if( p_fci_internal->fNextCab ||
1598 p_fci_internal->fGetNextCabInVain ) {
1599 cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1600 } else {
1601 cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData;
1602 }
1603 /* write reserved info into cabinet file */
1604 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1605 &cfreserved, /* memory buffer */
1606 sizeof(cfreserved), /* number of bytes to copy */
1607 &err, p_fci_internal->pv) != sizeof(cfreserved) ) {
1608 /* TODO write error */
1609 return FALSE;
1610 }
1611 /* TODO error handling of err */
1612 }
1613
1614 /* add optional reserved area */
1615 if (cbReserveCFHeader!=0) {
1616 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) {
1617 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1618 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1619 p_fci_internal->perf->fError = TRUE;
1620 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1621 return FALSE;
1622 }
1623 for(i=0;i<cbReserveCFHeader;) {
1624 reserved[i++]='\0';
1625 }
1626 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1627 reserved, /* memory buffer */
1628 cbReserveCFHeader, /* number of bytes to copy */
1629 &err, p_fci_internal->pv) != cbReserveCFHeader ) {
1630 PFCI_FREE(hfci, reserved);
1631 /* TODO write error */
1632 return FALSE;
1633 }
1634 /* TODO error handling of err */
1635 PFCI_FREE(hfci, reserved);
1636 }
1637
1638 if( cfheader.flags & cfheadPREV_CABINET ) {
1639 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1640 p_fci_internal->szPrevCab, /* memory buffer */
1641 strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */
1642 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) {
1643 /* TODO write error */
1644 return FALSE;
1645 }
1646 /* TODO error handling of err */
1647
1648 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1649 p_fci_internal->szPrevDisk, /* memory buffer */
1650 strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */
1651 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) {
1652 /* TODO write error */
1653 return FALSE;
1654 }
1655 /* TODO error handling of err */
1656 }
1657
1658 if( cfheader.flags & cfheadNEXT_CABINET ) {
1659 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1660 p_fci_internal->pccab->szCab, /* memory buffer */
1661 strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */
1662 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) {
1663 /* TODO write error */
1664 return FALSE;
1665 }
1666 /* TODO error handling of err */
1667
1668 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1669 p_fci_internal->pccab->szDisk, /* memory buffer */
1670 strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */
1671 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) {
1672 /* TODO write error */
1673 return FALSE;
1674 }
1675 /* TODO error handling of err */
1676 }
1677
1678 /* set seek of p_fci_internal->handleCFFOLDER to 0 */
1679 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER,
1680 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1681 /* TODO wrong return value */
1682 }
1683 /* TODO error handling of err */
1684
1685 /* while not all CFFOLDER structures have been copied into the cabinet do */
1686 while(!FALSE) {
1687 /* use the variable read_result */
1688 /* read cffolder of p_fci_internal->handleCFFOLDER */
1689 read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */
1690 &cffolder, /* memory buffer */
1691 sizeof(cffolder), /* number of bytes to copy */
1692 &err, p_fci_internal->pv);
1693 if( read_result != sizeof(cffolder) ) {
1694 if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/
1695 /* TODO read error */
1696 return FALSE;
1697 }
1698 /* TODO error handling of err */
1699
1700 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1701 cffolder.coffCabStart +=
1702 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
1703 sizeof(CFHEADER);
1704 if( p_fci_internal->fNextCab ||
1705 p_fci_internal->fGetNextCabInVain ) {
1706 cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1707 } else {
1708 cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader;
1709 }
1710
1711 if (p_fci_internal->fPrevCab) {
1712 cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 +
1713 strlen(p_fci_internal->szPrevDisk)+1;
1714 }
1715
1716 if (p_fci_internal->fNextCab) {
1717 cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 +
1718 strlen(p_fci_internal->oldCCAB.szDisk)+1;
1719 }
1720
1721 if( p_fci_internal->fNextCab ||
1722 p_fci_internal->fGetNextCabInVain ) {
1723 cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader;
1724 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1725 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1726 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1727 cffolder.coffCabStart += 4;
1728 }
1729 } else {
1730 cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader;
1731 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1732 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1733 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1734 cffolder.coffCabStart += 4;
1735 }
1736 }
1737
1738 /* write cffolder to cabinet file */
1739 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1740 &cffolder, /* memory buffer */
1741 sizeof(cffolder), /* number of bytes to copy */
1742 &err, p_fci_internal->pv) != sizeof(cffolder) ) {
1743 /* TODO write error */
1744 return FALSE;
1745 }
1746 /* TODO error handling of err */
1747
1748 /* add optional reserved area */
1749
1750 /* This allocation and freeing at each CFFolder block is a bit */
1751 /* inefficent, but it's harder to forget about freeing the buffer :-). */
1752 /* Reserved areas are used seldom besides that... */
1753 if (cbReserveCFFolder!=0) {
1754 if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) {
1755 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1756 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1757 p_fci_internal->perf->fError = TRUE;
1758 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1759 return FALSE;
1760 }
1761
1762 if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
1763 reserved, /* memory buffer */
1764 cbReserveCFFolder, /* number of bytes to copy */
1765 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1766 PFCI_FREE(hfci, reserved);
1767 /* TODO read error */
1768 return FALSE;
1769 }
1770 /* TODO error handling of err */
1771
1772 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1773 reserved, /* memory buffer */
1774 cbReserveCFFolder, /* number of bytes to copy */
1775 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1776 PFCI_FREE(hfci, reserved);
1777 /* TODO read error */
1778 return FALSE;
1779 }
1780 /* TODO error handling of err */
1781
1782 PFCI_FREE(hfci, reserved);
1783 }
1784
1785 } /* END OF while */
1786
1787 /* set seek of p_fci_internal->handleCFFILE2 to 0 */
1788 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2,
1789 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1790 /* TODO wrong return value */
1791 }
1792 /* TODO error handling of err */
1793
1794 /* while not all CFFILE structures have been copied to the cabinet do */
1795 while(!FALSE) {
1796 /* REUSE the variable read_result */
1797 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1798 /* read a block from p_fci_internal->handleCFFILE2 */
1799 read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */,
1800 p_fci_internal->data_out, /* memory buffer */
1801 32768, /* number of bytes to copy */
1802 &err, p_fci_internal->pv);
1803 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
1804 /* TODO error handling of err */
1805
1806 /* write the block to the cabinet file */
1807 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1808 p_fci_internal->data_out, /* memory buffer */
1809 read_result, /* number of bytes to copy */
1810 &err, p_fci_internal->pv) != read_result ) {
1811 /* TODO write error */
1812 return FALSE;
1813 }
1814 /* TODO error handling of err */
1815
1816 if (p_fci_internal->fSplitFolder==FALSE) {
1817 p_fci_internal->statusFolderCopied = 0;
1818 p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+
1819 p_fci_internal->sizeFileCFFILE2;
1820 }
1821 p_fci_internal->statusFolderCopied += read_result;
1822
1823 /* TODO is this correct */
1824 /* report status with pfnfcis about copied size of folder */
1825 if( (*pfnfcis)(statusFolder,
1826 p_fci_internal->statusFolderCopied, /* length of copied blocks */
1827 p_fci_internal->statusFolderTotal, /* total size of folder */
1828 p_fci_internal->pv) == -1) {
1829 /* TODO set error code and abort */
1830 return FALSE;
1831 }
1832
1833 } /* END OF while */
1834
1835 /* set seek of p_fci_internal->handleCFDATA2 to 0 */
1836 if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2,
1837 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1838 /* TODO wrong return value */
1839 return FALSE;
1840 }
1841 /* TODO error handling of err */
1842
1843 /* reset the number of folders for the next cabinet */
1844 p_fci_internal->cFolders=0;
1845 /* reset the number of files for the next cabinet */
1846 p_fci_internal->cFiles=0;
1847
1848 /* while not all CFDATA structures have been copied to the cabinet do */
1849 while(!FALSE) {
1850 /* REUSE the variable read_result AGAIN */
1851 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1852 /* read a block from p_fci_internal->handleCFDATA2 */
1853 read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */,
1854 p_fci_internal->data_out, /* memory buffer */
1855 32768, /* number of bytes to copy */
1856 &err, p_fci_internal->pv);
1857 if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */
1858 /* TODO error handling of err */
1859
1860 /* write the block to the cabinet file */
1861 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1862 p_fci_internal->data_out, /* memory buffer */
1863 read_result, /* number of bytes to copy */
1864 &err, p_fci_internal->pv) != read_result ) {
1865 /* TODO write error */
1866 return FALSE;
1867 }
1868 /* TODO error handling of err */
1869
1870 p_fci_internal->statusFolderCopied += read_result;
1871 /* report status with pfnfcis about copied size of folder */
1872 if( (*pfnfcis)(statusFolder,
1873 p_fci_internal->statusFolderCopied, /* length of copied blocks */
1874 p_fci_internal->statusFolderTotal, /* total size of folder */
1875 p_fci_internal->pv) == -1) {
1876 /* TODO set error code and abort */
1877 return FALSE;
1878 }
1879 } /* END OF while */
1880
1881 /* set seek of the cabinet file to 0 */
1882 if( PFCI_SEEK(hfci, handleCABINET,
1883 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1884 /* TODO wrong return value */
1885 }
1886 /* TODO error handling of err */
1887
1888 /* write the signature "MSCF" into the cabinet file */
1889 memcpy( cfheader.signature, "MSCF", 4 );
1890 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1891 &cfheader, /* memory buffer */
1892 4, /* number of bytes to copy */
1893 &err, p_fci_internal->pv) != 4 ) {
1894 /* TODO write error */
1895 return FALSE;
1896 }
1897 /* TODO error handling of err */
1898
1899 /* close the cabinet file */
1900 PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv);
1901 /* TODO error handling of err */
1902
1903
1904 /* COPIED FROM FCIDestroy */
1905
1906 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
1907 /* TODO error handling of err */
1908 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
1909 p_fci_internal->pv);
1910 /* TODO error handling of err */
1911 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
1912 /* TODO error handling of err */
1913 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
1914 p_fci_internal->pv);
1915 /* TODO error handling of err */
1916 PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
1917 /* TODO error handling of err */
1918 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
1919 p_fci_internal->pv);
1920 /* TODO error handling of err */
1921
1922 /* END OF copied from FCIDestroy */
1923
1924 /* get 3 temporary files and open them */
1925 /* write names and handles to hfci */
1926
1927
1928 p_fci_internal->sizeFileCFDATA2 = 0;
1929 p_fci_internal->sizeFileCFFILE2 = 0;
1930 p_fci_internal->sizeFileCFFOLDER = 0;
1931
1932 /* COPIED FROM FCICreate */
1933
1934 /* CFDATA with checksum and ready to be copied into cabinet */
1935 if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2,
1936 CB_MAX_FILENAME)) {
1937 /* TODO error handling */
1938 return FALSE;
1939 }
1940 /* safety */
1941 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
1942 /* TODO set error code */
1943 return FALSE;
1944 }
1945 p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
1946 p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv);
1947 /* TODO check handle */
1948 /* TODO error checking of err */
1949
1950 /* array of all CFFILE in a folder, ready to be copied into cabinet */
1951 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
1952 CB_MAX_FILENAME)) {
1953 /* TODO error handling */
1954 return FALSE;
1955 }
1956 /* safety */
1957 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
1958 /* TODO set error code */
1959 return FALSE;
1960 }
1961 p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
1962 p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv);
1963 /* TODO check handle */
1964 /* TODO error checking of err */
1965
1966 /* array of all CFFILE in a folder, ready to be copied into cabinet */
1967 if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) {
1968 /* TODO error handling */
1969 return FALSE;
1970 }
1971 /* safety */
1972 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
1973 /* TODO set error code */
1974 return FALSE;
1975 }
1976 p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
1977 p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv);
1978 /* TODO check handle */
1979 /* TODO error checking of err */
1980
1981 /* END OF copied from FCICreate */
1982
1983
1984 /* TODO close and delete new files when return FALSE */
1985
1986
1987 /* report status with pfnfcis about copied size of folder */
1988 if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */
1989 cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) {
1990 /* TODO set error code and abort */
1991 return FALSE;
1992 }
1993
1994 p_fci_internal->fPrevCab=TRUE;
1995 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1996 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1997
1998 if (p_fci_internal->fNextCab) {
1999 p_fci_internal->fNextCab=FALSE;
2000
2001 if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) {
2002 /* THIS CAN NEVER HAPPEN */
2003 /* TODO set error code */
2004 return FALSE;
2005 }
2006
2007 /* COPIED FROM FCIAddFile and modified */
2008
2009 /* REUSE the variable read_result */
2010 if (p_fci_internal->fGetNextCabInVain) {
2011 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader;
2012 if(p_fci_internal->sizeFileCFFILE1!=0) {
2013 read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder;
2014 }
2015 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2016 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2017 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2018 read_result+=4;
2019 }
2020 } else {
2021 read_result=p_fci_internal->pccab->cbReserveCFHeader;
2022 if(p_fci_internal->sizeFileCFFILE1!=0) {
2023 read_result+=p_fci_internal->pccab->cbReserveCFFolder;
2024 }
2025 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2026 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2027 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2028 read_result+=4;
2029 }
2030 }
2031 if ( p_fci_internal->fPrevCab ) {
2032 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2033 strlen(p_fci_internal->szPrevDisk)+1;
2034 }
2035 read_result+= p_fci_internal->sizeFileCFDATA1 +
2036 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2037 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2038 sizeof(CFHEADER) +
2039 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2040
2041 if( p_fci_internal->fNewPrevious ) {
2042 memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab,
2043 CB_MAX_CABINET_NAME);
2044 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk,
2045 CB_MAX_DISK_NAME);
2046 p_fci_internal->fNewPrevious=FALSE;
2047 }
2048
2049 /* too much data for the maximum size of a cabinet */
2050 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2051 p_fci_internal->pccab->cb < read_result ) {
2052 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2053 }
2054
2055 /* Might be too much data for the maximum size of a cabinet.*/
2056 /* When any further data will be added later, it might not */
2057 /* be possible to flush the cabinet, because there might */
2058 /* not be enough space to store the name of the following */
2059 /* cabinet and name of the corresponding disk. */
2060 /* So take care of this and get the name of the next cabinet */
2061 if (p_fci_internal->fGetNextCabInVain==FALSE && (
2062 p_fci_internal->pccab->cb < read_result +
2063 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2064 )) {
2065 /* save CCAB */
2066 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2067 /* increment cabinet index */
2068 ++(p_fci_internal->pccab->iCab);
2069 /* get name of next cabinet */
2070 if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
2071 p_fci_internal->pv)) {
2072 /* TODO error handling */
2073 return FALSE;
2074 }
2075 /* Skip a few lines of code. This is catched by the next if. */
2076 p_fci_internal->fGetNextCabInVain=TRUE;
2077 }
2078
2079 /* too much data for cabinet */
2080 if (p_fci_internal->fGetNextCabInVain && (
2081 p_fci_internal->oldCCAB.cb < read_result +
2082 strlen(p_fci_internal->oldCCAB.szCab)+1+
2083 strlen(p_fci_internal->oldCCAB.szDisk)+1
2084 )) {
2085 p_fci_internal->fGetNextCabInVain=FALSE;
2086 p_fci_internal->fNextCab=TRUE;
2087 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2088 }
2089
2090 /* if the FolderThreshold has been reached flush the folder automatically */
2091 if( p_fci_internal->fGetNextCabInVain ) {
2092 if( p_fci_internal->cCompressedBytesInFolder >=
2093 p_fci_internal->oldCCAB.cbFolderThresh) {
2094 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2095 }
2096 } else {
2097 if( p_fci_internal->cCompressedBytesInFolder >=
2098 p_fci_internal->pccab->cbFolderThresh) {
2099 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2100 }
2101 }
2102
2103 /* END OF COPIED FROM FCIAddFile and modified */
2104
2105 if( p_fci_internal->sizeFileCFFILE1>0 ) {
2106 if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE;
2107 p_fci_internal->fNewPrevious=TRUE;
2108 }
2109 } else {
2110 p_fci_internal->fNewPrevious=FALSE;
2111 if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) {
2112 /* THIS MAY NEVER HAPPEN */
2113 /* TODO set error structures */
2114 return FALSE;
2115 }
2116 }
2117
2118 return TRUE;
2119 } /* end of fci_flush_cabinet */
2120
2121
2122
2123
2124
2125 /***********************************************************************
2126 * FCIAddFile (CABINET.11)
2127 *
2128 * FCIAddFile adds a file to the to be created cabinet file
2129 *
2130 * PARAMS
2131 * hfci [I] An HFCI from FCICreate
2132 * pszSourceFile [I] A pointer to a C string which contains the name and
2133 * location of the file which will be added to the cabinet
2134 * pszFileName [I] A pointer to a C string which contains the name under
2135 * which the file will be stored in the cabinet
2136 * fExecute [I] A boolean value which indicates if the file should be
2137 * executed after extraction of self extracting
2138 * executables
2139 * pfnfcignc [I] A pointer to a function which gets information about
2140 * the next cabinet
2141 * pfnfcis [IO] A pointer to a function which will report status
2142 * information about the compression process
2143 * pfnfcioi [I] A pointer to a function which reports file attributes
2144 * and time and date information
2145 * typeCompress [I] Compression type
2146 *
2147 * RETURNS
2148 * On success, returns TRUE
2149 * On failure, returns FALSE
2150 *
2151 * INCLUDES
2152 * fci.h
2153 *
2154 */
2155 BOOL __cdecl FCIAddFile(
2156 HFCI hfci,
2157 char *pszSourceFile,
2158 char *pszFileName,
2159 BOOL fExecute,
2160 PFNFCIGETNEXTCABINET pfnfcignc,
2161 PFNFCISTATUS pfnfcis,
2162 PFNFCIGETOPENINFO pfnfcigoi,
2163 TCOMP typeCompress)
2164 {
2165 int err;
2166 CFFILE cffile;
2167 cab_ULONG read_result;
2168 int file_handle;
2169 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2170
2171 /* test hfci */
2172 if (!REALLY_IS_FCI(hfci)) {
2173 SetLastError(ERROR_INVALID_HANDLE);
2174 return FALSE;
2175 }
2176
2177 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
2178 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
2179 p_fci_internal->perf->erfOper = FCIERR_NONE;
2180 p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
2181 p_fci_internal->perf->fError = TRUE;
2182
2183 SetLastError(ERROR_BAD_ARGUMENTS);
2184 return FALSE;
2185 }
2186
2187 /* TODO check if pszSourceFile??? */
2188
2189 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
2190 /* TODO internal error */
2191 return FALSE;
2192 }
2193
2194 if(p_fci_internal->fNextCab) {
2195 /* TODO internal error */
2196 return FALSE;
2197 }
2198
2199 cffile.cbFile=0; /* size of the to be added file*/
2200 /* offset of the uncompressed file in the folder */
2201 cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in;
2202 /* number of folder in the cabinet or special 0=first */
2203 cffile.iFolder = p_fci_internal->cFolders;
2204
2205 /* allocation of memory */
2206 if (p_fci_internal->data_in==NULL) {
2207 if (p_fci_internal->cdata_in!=0) {
2208 /* TODO error handling */
2209 return FALSE;
2210 }
2211 if (p_fci_internal->data_out!=NULL) {
2212 /* TODO error handling */
2213 return FALSE;
2214 }
2215 if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) {
2216 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2217 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2218 p_fci_internal->perf->fError = TRUE;
2219 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2220 return FALSE;
2221 }
2222 if (p_fci_internal->data_out==NULL) {
2223 if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){
2224 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2225 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2226 p_fci_internal->perf->fError = TRUE;
2227 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2228 return FALSE;
2229 }
2230 }
2231 }
2232
2233 if (p_fci_internal->data_out==NULL) {
2234 PFCI_FREE(hfci,p_fci_internal->data_in);
2235 /* TODO error handling */
2236 return FALSE;
2237 }
2238
2239 /* get information about the file */
2240 file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time),
2241 &(cffile.attribs), &err, p_fci_internal->pv);
2242 /* TODO check file_handle */
2243 /* TODO error handling of err */
2244
2245 if (fExecute) { cffile.attribs |= _A_EXEC; }
2246
2247 /* REUSE the variable read_result */
2248 if (p_fci_internal->fGetNextCabInVain) {
2249 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2250 p_fci_internal->oldCCAB.cbReserveCFFolder;
2251 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2252 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2253 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2254 read_result+=4;
2255 }
2256 } else {
2257 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2258 p_fci_internal->pccab->cbReserveCFFolder;
2259 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2260 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2261 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2262 read_result+=4;
2263 }
2264 }
2265 if ( p_fci_internal->fPrevCab ) {
2266 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2267 strlen(p_fci_internal->szPrevDisk)+1;
2268 }
2269 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2270 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2271 strlen(p_fci_internal->pccab->szDisk)+1;
2272 }
2273
2274 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
2275 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2276 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2277 sizeof(CFHEADER) +
2278 sizeof(CFFOLDER); /* size of new CFFolder entry */
2279
2280 /* Might be too much data for the maximum size of a cabinet.*/
2281 /* When any further data will be added later, it might not */
2282 /* be possible to flush the cabinet, because there might */
2283 /* not be enough space to store the name of the following */
2284 /* cabinet and name of the corresponding disk. */
2285 /* So take care of this and get the name of the next cabinet */
2286 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2287 p_fci_internal->fNextCab==FALSE &&
2288 ( p_fci_internal->pccab->cb < read_result +
2289 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2290 )
2291 ) {
2292 /* save CCAB */
2293 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2294 /* increment cabinet index */
2295 ++(p_fci_internal->pccab->iCab);
2296 /* get name of next cabinet */
2297 if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2298 p_fci_internal->pv)) {
2299 /* TODO error handling */
2300 return FALSE;
2301 }
2302 /* Skip a few lines of code. This is catched by the next if. */
2303 p_fci_internal->fGetNextCabInVain=TRUE;
2304 }
2305
2306 if( p_fci_internal->fGetNextCabInVain &&
2307 p_fci_internal->fNextCab
2308 ) {
2309 /* THIS CAN NEVER HAPPEN */
2310 /* TODO set error code*/
2311 return FALSE;
2312 }
2313
2314 /* too much data for cabinet */
2315 if( p_fci_internal->fGetNextCabInVain &&
2316 (
2317 p_fci_internal->oldCCAB.cb < read_result +
2318 strlen(p_fci_internal->pccab->szCab)+1+
2319 strlen(p_fci_internal->pccab->szDisk)+1
2320 )) {
2321 p_fci_internal->fGetNextCabInVain=FALSE;
2322 p_fci_internal->fNextCab=TRUE;
2323 if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE;
2324 }
2325
2326 if( p_fci_internal->fNextCab ) {
2327 /* THIS MAY NEVER HAPPEN */
2328 /* TODO set error code*/
2329 return FALSE;
2330 }
2331
2332 /* read the contents of the file blockwize*/
2333 while (!FALSE) {
2334 if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
2335 /* TODO internal error */
2336 return FALSE;
2337 }
2338
2339 read_result = PFCI_READ(hfci, file_handle /* file handle */,
2340 (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
2341 (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
2342 &err, p_fci_internal->pv);
2343 /* TODO error handling of err */
2344
2345 if( read_result==0 ) break;
2346
2347 /* increment the block size */
2348 p_fci_internal->cdata_in += read_result;
2349
2350 /* increment the file size */
2351 cffile.cbFile += read_result;
2352
2353
2354 if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
2355 /* TODO report internal error */
2356 return FALSE;
2357 }
2358 /* write a whole block */
2359 if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
2360
2361 if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
2362 }
2363 }
2364
2365 /* close the file from FCIAddFile */
2366 PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv);
2367 /* TODO error handling of err */
2368
2369 /* write cffile to p_fci_internal->handleCFFILE1 */
2370 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2371 &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) {
2372 /* TODO write error */
2373 return FALSE;
2374 }
2375 /* TODO error handling of err */
2376
2377 p_fci_internal->sizeFileCFFILE1 += sizeof(cffile);
2378
2379 /* append the name of file*/
2380 if (strlen(pszFileName)>=CB_MAX_FILENAME) {
2381 /* IMPOSSIBLE */
2382 /* TODO set error code */
2383 return FALSE;
2384 }
2385 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2386 pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv)
2387 != strlen(pszFileName)+1 ) {
2388 /* TODO write error */
2389 return FALSE;
2390 }
2391 /* TODO error handling of err */
2392
2393 p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1;
2394
2395 /* REUSE the variable read_result */
2396 if (p_fci_internal->fGetNextCabInVain ||
2397 p_fci_internal->fNextCab
2398 ) {
2399 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2400 p_fci_internal->oldCCAB.cbReserveCFFolder;
2401 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2402 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2403 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2404 read_result+=4;
2405 }
2406 } else {
2407 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2408 p_fci_internal->pccab->cbReserveCFFolder;
2409 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2410 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2411 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2412 read_result+=4;
2413 }
2414 }
2415 if ( p_fci_internal->fPrevCab ) {
2416 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2417 strlen(p_fci_internal->szPrevDisk)+1;
2418 }
2419 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2420 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2421 strlen(p_fci_internal->pccab->szDisk)+1;
2422 }
2423 read_result+= p_fci_internal->sizeFileCFDATA1 +
2424 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2425 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2426 sizeof(CFHEADER) +
2427 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2428
2429 /* too much data for the maximum size of a cabinet */
2430 /* (ignoring the unflushed data block) */
2431 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2432 p_fci_internal->fNextCab==FALSE && /* this is always the case */
2433 p_fci_internal->pccab->cb < read_result ) {
2434 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2435 }
2436
2437 /* Might be too much data for the maximum size of a cabinet.*/
2438 /* When any further data will be added later, it might not */
2439 /* be possible to flush the cabinet, because there might */
2440 /* not be enough space to store the name of the following */
2441 /* cabinet and name of the corresponding disk. */
2442 /* So take care of this and get the name of the next cabinet */
2443 /* (ignoring the unflushed data block) */
2444 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2445 p_fci_internal->fNextCab==FALSE &&
2446 ( p_fci_internal->pccab->cb < read_result +
2447 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2448 )
2449 ) {
2450 /* save CCAB */
2451 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2452 /* increment cabinet index */
2453 ++(p_fci_internal->pccab->iCab);
2454 /* get name of next cabinet */
2455 if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2456 p_fci_internal->pv)) {
2457 /* TODO error handling */
2458 return FALSE;
2459 }
2460 /* Skip a few lines of code. This is catched by the next if. */
2461 p_fci_internal->fGetNextCabInVain=TRUE;
2462 }
2463
2464 if( p_fci_internal->fGetNextCabInVain &&
2465 p_fci_internal->fNextCab
2466 ) {
2467 /* THIS CAN NEVER HAPPEN */
2468 /* TODO set error code*/
2469 return FALSE;
2470 }
2471
2472 /* too much data for cabinet */
2473 if( (p_fci_internal->fGetNextCabInVain ||
2474 p_fci_internal->fNextCab) && (
2475 p_fci_internal->oldCCAB.cb < read_result +
2476 strlen(p_fci_internal->pccab->szCab)+1+
2477 strlen(p_fci_internal->pccab->szDisk)+1
2478 )) {
2479
2480 p_fci_internal->fGetNextCabInVain=FALSE;
2481 p_fci_internal->fNextCab=TRUE;
2482 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2483 }
2484
2485 if( p_fci_internal->fNextCab ) {
2486 /* THIS MAY NEVER HAPPEN */
2487 /* TODO set error code*/
2488 return FALSE;
2489 }
2490
2491 /* if the FolderThreshold has been reached flush the folder automatically */
2492 if( p_fci_internal->fGetNextCabInVain ) {
2493 if( p_fci_internal->cCompressedBytesInFolder >=
2494 p_fci_internal->oldCCAB.cbFolderThresh) {
2495 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2496 }
2497 } else {
2498 if( p_fci_internal->cCompressedBytesInFolder >=
2499 p_fci_internal->pccab->cbFolderThresh) {
2500 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2501 }
2502 }
2503
2504 return TRUE;
2505 } /* end of FCIAddFile */
2506
2507
2508
2509
2510
2511 /***********************************************************************
2512 * FCIFlushFolder (CABINET.12)
2513 *
2514 * FCIFlushFolder completes the CFFolder structure under construction.
2515 *
2516 * All further data which is added by FCIAddFile will be associateed to
2517 * the next CFFolder structure.
2518 *
2519 * FCIFlushFolder will be called by FCIAddFile automatically if the
2520 * threshold (stored in the member cbFolderThresh of the CCAB structure
2521 * pccab passed to FCICreate) is exceeded.
2522 *
2523 * FCIFlushFolder will be called by FCIFlushFolder automatically before
2524 * any data will be written into the cabinet file.
2525 *
2526 * PARAMS
2527 * hfci [I] An HFCI from FCICreate
2528 * pfnfcignc [I] A pointer to a function which gets information about
2529 * the next cabinet
2530 * pfnfcis [IO] A pointer to a function which will report status
2531 * information about the compression process
2532 *
2533 * RETURNS
2534 * On success, returns TRUE
2535 * On failure, returns FALSE
2536 *
2537 * INCLUDES
2538 * fci.h
2539 *
2540 */
2541 BOOL __cdecl FCIFlushFolder(
2542 HFCI hfci,
2543 PFNFCIGETNEXTCABINET pfnfcignc,
2544 PFNFCISTATUS pfnfcis)
2545 {
2546 return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis);
2547 } /* end of FCIFlushFolder */
2548
2549
2550
2551 /***********************************************************************
2552 * FCIFlushCabinet (CABINET.13)
2553 *
2554 * FCIFlushCabinet stores the data which has been added by FCIAddFile
2555 * into the cabinet file. If the maximum cabinet size (stored in the
2556 * member cb of the CCAB structure pccab passed to FCICreate) has been
2557 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2558 * The remaining data still has to be flushed manually by calling
2559 * FCIFlushCabinet.
2560 *
2561 * After FCIFlushCabinet has been called (manually) FCIAddFile must
2562 * NOT be called again. Then hfci has to be released by FCIDestroy.
2563 *
2564 * PARAMS
2565 * hfci [I] An HFCI from FCICreate
2566 * fGetNextCab [I] Whether you want to add additional files to a
2567 * cabinet set (TRUE) or whether you want to
2568 * finalize it (FALSE)
2569 * pfnfcignc [I] A pointer to a function which gets information about
2570 * the next cabinet
2571 * pfnfcis [IO] A pointer to a function which will report status
2572 * information about the compression process
2573 *
2574 * RETURNS
2575 * On success, returns TRUE
2576 * On failure, returns FALSE
2577 *
2578 * INCLUDES
2579 * fci.h
2580 *
2581 */
2582 BOOL __cdecl FCIFlushCabinet(
2583 HFCI hfci,
2584 BOOL fGetNextCab,
2585 PFNFCIGETNEXTCABINET pfnfcignc,
2586 PFNFCISTATUS pfnfcis)
2587 {
2588 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2589
2590 if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2591
2592 while( p_fci_internal->sizeFileCFFILE1>0 ||
2593 p_fci_internal->sizeFileCFFILE2>0 ) {
2594 if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2595 }
2596
2597 return TRUE;
2598 } /* end of FCIFlushCabinet */
2599
2600
2601 /***********************************************************************
2602 * FCIDestroy (CABINET.14)
2603 *
2604 * Frees a handle created by FCICreate.
2605 * Only reason for failure would be an invalid handle.
2606 *
2607 * PARAMS
2608 * hfci [I] The HFCI to free
2609 *
2610 * RETURNS
2611 * TRUE for success
2612 * FALSE for failure
2613 */
2614 BOOL __cdecl FCIDestroy(HFCI hfci)
2615 {
2616 int err;
2617 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2618 if (REALLY_IS_FCI(hfci)) {
2619
2620 /* before hfci can be removed all temporary files must be closed */
2621 /* and deleted */
2622 p_fci_internal->FCI_Intmagic = 0;
2623
2624 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
2625 /* TODO error handling of err */
2626 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err,
2627 p_fci_internal->pv);
2628 /* TODO error handling of err */
2629 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);
2630 /* TODO error handling of err */
2631 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err,
2632 p_fci_internal->pv);
2633 /* TODO error handling of err */
2634 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2635 /* TODO error handling of err */
2636 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
2637 p_fci_internal->pv);
2638 /* TODO error handling of err */
2639 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2640 /* TODO error handling of err */
2641 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
2642 p_fci_internal->pv);
2643 /* TODO error handling of err */
2644 PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2645 /* TODO error handling of err */
2646 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
2647 p_fci_internal->pv);
2648 /* TODO error handling of err */
2649
2650 /* data in and out buffers have to be removed */
2651 if (p_fci_internal->data_in!=NULL)
2652 PFCI_FREE(hfci, p_fci_internal->data_in);
2653 if (p_fci_internal->data_out!=NULL)
2654 PFCI_FREE(hfci, p_fci_internal->data_out);
2655
2656 /* hfci can now be removed */
2657 PFCI_FREE(hfci, hfci);
2658 return TRUE;
2659 } else {
2660 SetLastError(ERROR_INVALID_HANDLE);
2661 return FALSE;
2662 }
2663
2664 } /* end of FCIDestroy */