Support for big-endian systems.
[wine/multimedia.git] / dlls / cabinet / fci.c
blob39121aad0886320cc80747d551459cfee2fe5557
1 /*
2 * File Compression Interface
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
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.
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.
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
24 There is still some work to be done:
26 - the ERF error structure aren't used on error
27 - no real compression yet
28 - unknown behaviour if files>4GB or cabinet >4GB
29 - incorrect status information
30 - check if the maximum size for a cabinet is too small to store any data
31 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
37 #include "config.h"
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winerror.h"
46 #include "winternl.h"
47 #include "fci.h"
48 #include "cabinet.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
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 */
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 */
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 */
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;
99 /***********************************************************************
100 * FCICreate (CABINET.10)
102 * FCICreate is provided with several callbacks and
103 * returns a handle which can be used to create cabinet files.
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.
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.
140 * INCLUDES
141 * fci.h
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)
159 HFCI hfci;
160 int err;
161 PFCI_Int p_fci_internal;
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;
170 SetLastError(ERROR_BAD_ARGUMENTS);
171 return NULL;
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;
179 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
180 return NULL;
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;
217 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
218 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
220 /* CFDATA */
221 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1,
222 CB_MAX_FILENAME)) {
223 /* TODO error handling */
224 return FALSE;
226 /* safety */
227 if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {
228 /* TODO set error code */
229 return FALSE;
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 */
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;
243 /* safety */
244 if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {
245 /* TODO set error code */
246 return FALSE;
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 */
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;
259 /* safety */
260 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
261 /* TODO set error code */
262 return FALSE;
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 */
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;
275 /* safety */
276 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
277 /* TODO set error code */
278 return FALSE;
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 */
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;
291 /* safety */
292 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
293 /* TODO set error code */
294 return FALSE;
296 p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
297 p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv);
300 /* TODO close and delete new files when return FALSE */
302 /* TODO check handle */
303 /* TODO error checking of err */
305 return hfci;
306 } /* end of FCICreate */
313 static BOOL fci_flush_data_block (HFCI hfci, int* err,
314 PFNFCISTATUS pfnfcis) {
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;
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 */);
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;
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;
342 /* TODO error handling of err */
344 p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);
346 /* add optional reserved area */
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;
359 for(i=0;i<cbReserveCFData;) {
360 reserved[i++]='\0';
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;
370 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
372 p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;
373 PFCI_FREE(hfci, reserved);
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;
384 /* TODO error handling of err */
386 p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;
388 /* reset the offset */
389 p_fci_internal->cdata_in = 0;
390 p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
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;
399 ++(p_fci_internal->cDataBlocks);
401 return TRUE;
402 } /* end of fci_flush_data_block */
408 static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed)
410 cab_ULONG csum;
411 cab_ULONG ul;
412 int cUlong;
413 BYTE *pb;
415 csum = seed;
416 cUlong = cb / 4;
417 pb = pv;
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);
425 csum ^= ul;
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;
439 csum ^= ul;
441 return csum;
442 } /* end of fci_get_checksum */
445 static inline cab_ULONG fci_set_little_endian_ulong( cab_ULONG i )
447 #ifdef WORDS_BIGENDIAN
448 return RtlUlongByteSwap( i );
449 #else
450 return i;
451 #endif
454 static inline cab_ULONG fci_get_little_endian_ulong( cab_ULONG i )
456 #ifdef WORDS_BIGENDIAN
457 return RtlUlongByteSwap( i );
458 #else
459 return i;
460 #endif
463 static inline cab_UWORD fci_set_little_endian_uword( cab_UWORD i )
465 #ifdef WORDS_BIGENDIAN
466 return RtlUshortByteSwap( i );
467 #else
468 return i;
469 #endif
472 static inline cab_UWORD fci_get_little_endian_uword( cab_UWORD i )
474 #ifdef WORDS_BIGENDIAN
475 return RtlUshortByteSwap( i );
476 #else
477 return i;
478 #endif
482 static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData,
483 PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,
484 cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)
486 cab_ULONG read_result;
487 CFDATA* pcfdata=(CFDATA*)buffer;
488 BOOL split_block=FALSE;
489 cab_UWORD savedUncomp=0;
490 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
492 *payload=0;
494 /* while not all CFDATAs have been copied do */
495 while(!FALSE) {
496 if( p_fci_internal->fNextCab ) {
497 if( split_block ) {
498 /* TODO internal error should never happen */
499 return FALSE;
502 /* REUSE the variable read_result */
503 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
504 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
505 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
506 read_result=4;
507 } else {
508 read_result=0;
510 if (p_fci_internal->fPrevCab) {
511 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
512 strlen(p_fci_internal->szPrevDisk)+1;
514 /* No more CFDATA fits into the cabinet under construction */
515 /* So don't try to store more data into it */
516 if( p_fci_internal->fNextCab &&
517 (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +
518 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
519 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
520 sizeof(CFHEADER) +
521 read_result +
522 p_fci_internal->oldCCAB.cbReserveCFHeader +
523 sizeof(CFFOLDER) +
524 p_fci_internal->oldCCAB.cbReserveCFFolder +
525 strlen(p_fci_internal->pccab->szCab)+1 +
526 strlen(p_fci_internal->pccab->szDisk)+1
527 )) {
528 /* This may never be run for the first time the while loop is entered.
529 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
530 split_block=TRUE; /* In this case split_block is abused to store */
531 /* the complete data block into the next cabinet and not into the */
532 /* current one. Originally split_block is the indicator that a */
533 /* data block has been splitted across different cabinets. */
534 } else {
536 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
537 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/
538 buffer, /* memory buffer */
539 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
540 err, p_fci_internal->pv);
541 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
542 if (read_result==0) break; /* ALL DATA has been copied */
543 /* TODO read error */
544 return FALSE;
546 /* TODO error handling of err */
548 /* REUSE buffer p_fci_internal->data_out !!! */
549 /* read data from p_fci_internal->handleCFDATA1 to */
550 /* p_fci_internal->data_out */
551 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
552 p_fci_internal->data_out /* memory buffer */,
553 pcfdata->cbData /* number of bytes to copy */,
554 err, p_fci_internal->pv) != pcfdata->cbData ) {
555 /* TODO read error */
556 return FALSE;
558 /* TODO error handling of err */
560 /* if cabinet size is too large */
562 /* REUSE the variable read_result */
563 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
564 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
565 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
566 read_result=4;
567 } else {
568 read_result=0;
570 if (p_fci_internal->fPrevCab) {
571 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
572 strlen(p_fci_internal->szPrevDisk)+1;
575 /* Is cabinet with new CFDATA too large? Then data block has to be split */
576 if( p_fci_internal->fNextCab &&
577 (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +
578 pcfdata->cbData +
579 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
580 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
581 sizeof(CFHEADER) +
582 read_result +
583 p_fci_internal->oldCCAB.cbReserveCFHeader +
584 sizeof(CFFOLDER) + /* size of new CFFolder entry */
585 p_fci_internal->oldCCAB.cbReserveCFFolder +
586 strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */
587 strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */
588 )) {
589 /* REUSE read_result to save the size of the compressed data */
590 read_result=pcfdata->cbData;
591 /* Modify the size of the compressed data to store only a part of the */
592 /* data block into the current cabinet. This is done to prevent */
593 /* that the maximum cabinet size will be exceeded. The remainer */
594 /* will be stored into the next following cabinet. */
596 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
597 /* Substract everything except the size of the block of data */
598 /* to get it's actual size */
599 pcfdata->cbData = p_fci_internal->oldCCAB.cb - (
600 sizeof(CFDATA) + cbReserveCFData +
601 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
602 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
603 sizeof(CFHEADER) +
604 p_fci_internal->oldCCAB.cbReserveCFHeader +
605 sizeof(CFFOLDER) + /* set size of new CFFolder entry */
606 p_fci_internal->oldCCAB.cbReserveCFFolder );
607 /* substract the size of special header fields */
608 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
609 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
610 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
611 pcfdata->cbData-=4;
613 if (p_fci_internal->fPrevCab) {
614 pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +
615 strlen(p_fci_internal->szPrevDisk)+1;
617 pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +
618 strlen(p_fci_internal->pccab->szDisk)+1;
620 savedUncomp = pcfdata->cbUncomp;
621 pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */
623 /* if split_block==TRUE then the above while loop won't */
624 /* be executed again */
625 split_block=TRUE; /* split_block is the indicator that */
626 /* a data block has been splitted across */
627 /* diffentent cabinets.*/
630 /* This should never happen !!! */
631 if (pcfdata->cbData==0) {
632 /* TODO set error */
633 return FALSE;
636 /* set little endian */
637 pcfdata->cbData=fci_set_little_endian_uword(pcfdata->cbData);
638 pcfdata->cbUncomp=fci_set_little_endian_uword(pcfdata->cbUncomp);
640 /* get checksum and write to cfdata.csum */
641 pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
642 sizeof(CFDATA)+cbReserveCFData -
643 sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
644 pcfdata->cbData, 0 ) );
646 /* set little endian */
647 pcfdata->csum=fci_set_little_endian_ulong(pcfdata->csum);
649 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
650 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
651 buffer, /* memory buffer */
652 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
653 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
654 /* TODO write error */
655 return FALSE;
657 /* TODO error handling of err */
659 p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;
661 /* reset little endian */
662 pcfdata->cbData=fci_get_little_endian_uword(pcfdata->cbData);
663 pcfdata->cbUncomp=fci_get_little_endian_uword(pcfdata->cbUncomp);
664 pcfdata->csum=fci_get_little_endian_ulong(pcfdata->csum);
666 /* write compressed data into p_fci_internal->handleCFDATA2 */
667 if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
668 p_fci_internal->data_out, /* memory buffer */
669 pcfdata->cbData, /* number of bytes to copy */
670 err, p_fci_internal->pv) != pcfdata->cbData) {
671 /* TODO write error */
672 return FALSE;
674 /* TODO error handling of err */
676 p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;
677 ++(p_fci_internal->cDataBlocks);
678 p_fci_internal->statusFolderCopied += pcfdata->cbData;
679 (*payload)+=pcfdata->cbUncomp;
680 /* if cabinet size too large and data has been split */
681 /* write the remainer of the data block to the new CFDATA1 file */
682 if( split_block ) { /* This does not include the */
683 /* abused one (just search for "abused" )*/
684 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
685 if (p_fci_internal->fNextCab==FALSE ) {
686 /* TODO internal error */
687 return FALSE;
690 /* set cbData the size of the remainer of the data block */
691 pcfdata->cbData = read_result - pcfdata->cbData;
692 /*recover former value of cfdata.cbData; read_result will be the offset*/
693 read_result -= pcfdata->cbData;
694 pcfdata->cbUncomp = savedUncomp;
696 /* reset checksum, it will be computed later */
697 pcfdata->csum=0;
699 /* write cfdata WITHOUT checksum to handleCFDATA1new */
700 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
701 buffer, /* memory buffer */
702 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
703 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
704 /* TODO write error */
705 return FALSE;
707 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
709 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
711 /* write compressed data into handleCFDATA1new */
712 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
713 p_fci_internal->data_out + read_result, /* memory buffer + offset */
714 /* to last part of split data */
715 pcfdata->cbData, /* number of bytes to copy */
716 err, p_fci_internal->pv) != pcfdata->cbData) {
717 /* TODO write error */
718 return FALSE;
720 /* TODO error handling of err */
722 p_fci_internal->statusFolderCopied += pcfdata->cbData;
724 *psizeFileCFDATA1new += pcfdata->cbData;
725 /* the two blocks of the split data block have been written */
726 /* dont reset split_data yet, because it is still needed see below */
729 /* report status with pfnfcis about copied size of folder */
730 if( (*pfnfcis)(statusFolder,
731 p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
732 p_fci_internal->statusFolderTotal, /* total folder size */
733 p_fci_internal->pv) == -1) {
734 /* TODO set error code and abort */
735 return FALSE;
739 /* if cabinet size too large */
740 /* write the remaining data blocks to the new CFDATA1 file */
741 if ( split_block ) { /* This does include the */
742 /* abused one (just search for "abused" )*/
743 if (p_fci_internal->fNextCab==FALSE ) {
744 /* TODO internal error */
745 return FALSE;
747 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
748 while(!FALSE) {
749 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
750 read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */
751 buffer, /* memory buffer */
752 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
753 err, p_fci_internal->pv);
754 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
755 if (read_result==0) break; /* ALL DATA has been copied */
756 /* TODO read error */
757 return FALSE;
759 /* TODO error handling of err */
761 /* REUSE buffer p_fci_internal->data_out !!! */
762 /* read data from p_fci_internal->handleCFDATA1 to */
763 /* p_fci_internal->data_out */
764 if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
765 p_fci_internal->data_out /* memory buffer */,
766 pcfdata->cbData /* number of bytes to copy */,
767 err, p_fci_internal->pv) != pcfdata->cbData ) {
768 /* TODO read error */
769 return FALSE;
771 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
773 /* write cfdata with checksum to handleCFDATA1new */
774 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
775 buffer, /* memory buffer */
776 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
777 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
778 /* TODO write error */
779 return FALSE;
781 /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */
783 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
785 /* write compressed data into handleCFDATA1new */
786 if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
787 p_fci_internal->data_out, /* memory buffer */
788 pcfdata->cbData, /* number of bytes to copy */
789 err, p_fci_internal->pv) != pcfdata->cbData) {
790 /* TODO write error */
791 return FALSE;
793 /* TODO error handling of err */
795 *psizeFileCFDATA1new += pcfdata->cbData;
796 p_fci_internal->statusFolderCopied += pcfdata->cbData;
798 /* report status with pfnfcis about copied size of folder */
799 if( (*pfnfcis)(statusFolder,
800 p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/
801 p_fci_internal->statusFolderTotal, /* total folder size */
802 p_fci_internal->pv) == -1) {
803 /* TODO set error code and abort */
804 return FALSE;
807 } /* end of WHILE */
808 break; /* jump out of the next while loop */
809 } /* end of if( split_data ) */
810 } /* end of WHILE */
811 return TRUE;
812 } /* end of fci_flushfolder_copy_cfdata */
818 static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder,
819 cab_ULONG sizeFileCFDATA2old)
821 CFFOLDER cffolder;
822 UINT i;
823 char* reserved;
824 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
826 /* absolute offset cannot be set yet, because the size of cabinet header, */
827 /* the number of CFFOLDERs and the number of CFFILEs may change. */
828 /* Instead the size of all previous data blocks will be stored and */
829 /* the remainer of the offset will be added when the cabinet will be */
830 /* flushed to disk. */
831 /* This is exactly the way the original CABINET.DLL works!!! */
832 cffolder.coffCabStart=sizeFileCFDATA2old;
834 /* set the number of this folder's CFDATA sections */
835 cffolder.cCFData=p_fci_internal->cDataBlocks;
836 /* TODO set compression type */
837 cffolder.typeCompress = tcompTYPE_NONE;
839 /* write cffolder to p_fci_internal->handleCFFOLDER */
840 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
841 &cffolder, /* memory buffer */
842 sizeof(cffolder), /* number of bytes to copy */
843 err, p_fci_internal->pv) != sizeof(cffolder) ) {
844 /* TODO write error */
845 return FALSE;
847 /* TODO error handling of err */
849 p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);
851 /* add optional reserved area */
852 if (cbReserveCFFolder!=0) {
853 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) {
854 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
855 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
856 p_fci_internal->perf->fError = TRUE;
857 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
858 return FALSE;
860 for(i=0;i<cbReserveCFFolder;) {
861 reserved[i++]='\0';
863 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
864 reserved, /* memory buffer */
865 cbReserveCFFolder, /* number of bytes to copy */
866 err, p_fci_internal->pv) != cbReserveCFFolder ) {
867 PFCI_FREE(hfci, reserved);
868 /* TODO write error */
869 return FALSE;
871 /* TODO error handling of err */
873 p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;
875 PFCI_FREE(hfci, reserved);
877 return TRUE;
878 } /* end of fci_flushfolder_copy_cffolder */
884 static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new,
885 cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)
887 CFFILE cffile;
888 cab_ULONG read_result;
889 cab_ULONG seek=0;
890 cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;
891 BOOL may_be_prev=TRUE;
892 cab_ULONG cbFileRemainer=0;
893 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
894 /* set seek of p_fci_internal->handleCFFILE1 to 0 */
895 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err,
896 p_fci_internal->pv) !=0 ) {
897 /* TODO wrong return value */
899 /* TODO error handling of err */
901 /* while not all CFFILE structures have been copied do */
902 while(!FALSE) {
903 /* REUSE the variable read_result */
904 /* read data from p_fci_internal->handleCFFILE1 to cffile */
905 read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */,
906 &cffile, /* memory buffer */
907 sizeof(cffile), /* number of bytes to copy */
908 err, p_fci_internal->pv);
909 if( read_result != sizeof(cffile) ) {
910 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
911 /* TODO read error */
912 return FALSE;
914 /* TODO error handling of err */
916 /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
917 /* position. I don't know why so I'll just omit it */
919 /* read the filename from p_fci_internal->handleCFFILE1 */
920 /* REUSE the variable read_result AGAIN */
921 /* REUSE the memory buffer PFCI(hfci)->data_out */
922 if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/,
923 p_fci_internal->data_out, /* memory buffer */
924 CB_MAX_FILENAME, /* number of bytes to copy */
925 err, p_fci_internal->pv) <2) {
926 /* TODO read error */
927 return FALSE;
929 /* TODO maybe other checks of read_result */
930 /* TODO error handling of err */
932 /* safety */
933 if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {
934 /* TODO set error code internal error */
935 return FALSE;
938 seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;
940 /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
941 /* i.e. seek to the next CFFILE area */
942 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,
943 seek, /* seek position*/
944 SEEK_SET ,err,
945 p_fci_internal->pv)
946 != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) {
947 /* TODO wrong return value */
949 /* TODO error handling of err */
951 /* fnfilfnfildest: placed file on cabinet */
952 if (p_fci_internal->fNextCab ||
953 p_fci_internal->fGetNextCabInVain) {
954 PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB),
955 p_fci_internal->data_out, /* the file name*/
956 cffile.cbFile, /* file size */
957 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
958 p_fci_internal->pv
960 } else {
961 PFCI_FILEPLACED( hfci, p_fci_internal->pccab,
962 p_fci_internal->data_out, /* the file name*/
963 cffile.cbFile, /* file size */
964 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
965 p_fci_internal->pv
969 /* Check special iFolder values */
970 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
971 p_fci_internal->fPrevCab==FALSE ) {
972 /* THIS MAY NEVER HAPPEN */
973 /* TODO set error code */
974 return FALSE;
976 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
977 cffile.iFolder==cffileCONTINUED_TO_NEXT ) {
978 /* THIS MAY NEVER HAPPEN */
979 /* TODO set error code */
980 return FALSE;
982 if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
983 may_be_prev=FALSE;
985 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {
986 /* THIS MAY NEVER HAPPEN */
987 /* TODO set error code */
988 return FALSE;
990 if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
991 may_be_prev=FALSE;
994 sizeOfFilesPrev=sizeOfFiles;
995 /* Set complete size of all processed files */
996 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
997 p_fci_internal->cbFileRemainer!=0
999 sizeOfFiles+=p_fci_internal->cbFileRemainer;
1000 p_fci_internal->cbFileRemainer=0;
1001 } else {
1002 sizeOfFiles+=cffile.cbFile;
1005 /* Check if spanned file fits into this cabinet folder */
1006 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) {
1007 cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT;
1008 } else
1010 /* Check if file doesn't fit into this cabinet folder */
1011 if( sizeOfFiles>payload ) {
1012 cffile.iFolder=cffileCONTINUED_TO_NEXT;
1015 /* set little endian */
1016 cffile.cbFile=fci_set_little_endian_ulong(cffile.cbFile);
1017 cffile.uoffFolderStart=fci_set_little_endian_ulong(cffile.uoffFolderStart);
1018 cffile.iFolder=fci_set_little_endian_uword(cffile.iFolder);
1019 cffile.date=fci_set_little_endian_uword(cffile.date);
1020 cffile.time=fci_set_little_endian_uword(cffile.time);
1021 cffile.attribs=fci_set_little_endian_uword(cffile.attribs);
1023 /* write cffile to p_fci_internal->handleCFFILE2 */
1024 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
1025 &cffile, /* memory buffer */
1026 sizeof(cffile), /* number of bytes to copy */
1027 err, p_fci_internal->pv) != sizeof(cffile) ) {
1028 /* TODO write error */
1029 return FALSE;
1031 /* TODO error handling of err */
1033 p_fci_internal->sizeFileCFFILE2 += sizeof(cffile);
1035 /* reset little endian */
1036 cffile.cbFile=fci_get_little_endian_ulong(cffile.cbFile);
1037 cffile.uoffFolderStart=fci_get_little_endian_ulong(cffile.uoffFolderStart);
1038 cffile.iFolder=fci_get_little_endian_uword(cffile.iFolder);
1039 cffile.date=fci_get_little_endian_uword(cffile.date);
1040 cffile.time=fci_get_little_endian_uword(cffile.time);
1041 cffile.attribs=fci_get_little_endian_uword(cffile.attribs);
1043 /* write file name to p_fci_internal->handleCFFILE2 */
1044 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
1045 p_fci_internal->data_out, /* memory buffer */
1046 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1047 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1048 /* TODO write error */
1049 return FALSE;
1051 /* TODO error handling of err */
1053 p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1;
1055 /* cFiles is used to count all files of a cabinet */
1056 ++(p_fci_internal->cFiles);
1058 /* This is only true for files which will be written into the */
1059 /* next cabinet of the spanning folder */
1060 if( sizeOfFiles>payload ) {
1062 /* Files which data will be partially written into the current cabinet */
1063 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
1064 cffile.iFolder==cffileCONTINUED_TO_NEXT
1066 if( sizeOfFilesPrev<=payload ) {
1067 /* The size of the uncompressed, data of a spanning file in a */
1068 /* spanning data */
1069 cbFileRemainer=sizeOfFiles-payload;
1071 cffile.iFolder=cffileCONTINUED_FROM_PREV;
1072 } else {
1073 cffile.iFolder=0;
1076 /* write cffile into handleCFFILE1new */
1077 if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1078 &cffile, /* memory buffer */
1079 sizeof(cffile), /* number of bytes to copy */
1080 err, p_fci_internal->pv) != sizeof(cffile) ) {
1081 /* TODO write error */
1082 return FALSE;
1084 /* TODO error handling of err */
1086 *psizeFileCFFILE1new += sizeof(cffile);
1087 /* write name of file into handleCFFILE1new */
1088 if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1089 p_fci_internal->data_out, /* memory buffer */
1090 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1091 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1092 /* TODO write error */
1093 return FALSE;
1095 /* TODO error handling of err */
1097 *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1;
1100 } /* END OF while */
1101 p_fci_internal->cbFileRemainer=cbFileRemainer;
1102 return TRUE;
1103 } /* end of fci_flushfolder_copy_cffile */
1108 static BOOL fci_flush_folder(
1109 HFCI hfci,
1110 BOOL fGetNextCab,
1111 PFNFCIGETNEXTCABINET pfnfcignc,
1112 PFNFCISTATUS pfnfcis)
1114 int err;
1115 int handleCFDATA1new; /* handle for new temp file */
1116 char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1117 int handleCFFILE1new; /* handle for new temp file */
1118 char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1119 UINT cbReserveCFData, cbReserveCFFolder;
1120 char* reserved;
1121 cab_ULONG sizeFileCFDATA1new=0;
1122 cab_ULONG sizeFileCFFILE1new=0;
1123 cab_ULONG sizeFileCFDATA2old;
1124 cab_ULONG payload;
1125 cab_ULONG read_result;
1126 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1128 /* test hfci */
1129 if (!REALLY_IS_FCI(hfci)) {
1130 SetLastError(ERROR_INVALID_HANDLE);
1131 return FALSE;
1134 if ((!pfnfcignc) || (!pfnfcis)) {
1135 p_fci_internal->perf->erfOper = FCIERR_NONE;
1136 p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
1137 p_fci_internal->perf->fError = TRUE;
1139 SetLastError(ERROR_BAD_ARGUMENTS);
1140 return FALSE;
1143 if( p_fci_internal->fGetNextCabInVain &&
1144 p_fci_internal->fNextCab ){
1145 /* TODO internal error */
1146 return FALSE;
1149 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1150 /* this function will return TRUE */
1151 if( p_fci_internal->sizeFileCFFILE1 == 0 ) {
1152 if ( p_fci_internal->sizeFileCFDATA1 != 0 ) {
1153 /* TODO error handling */
1154 return FALSE;
1156 return TRUE;
1159 if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1160 /* TODO error handling */
1161 return FALSE;
1164 /* FCIFlushFolder has already been called... */
1165 if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) {
1166 if (p_fci_internal->sizeFileCFFILE2==0) {
1167 /* TODO set error code */
1168 return FALSE;
1170 return TRUE;
1173 /* TODO check what will happen when return FALSE later */
1174 /* and p_fci_internal->fSplitFolder is set to FALSE */
1175 p_fci_internal->fSplitFolder=FALSE;
1178 if( p_fci_internal->fGetNextCabInVain ||
1179 p_fci_internal->fNextCab ){
1180 cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1181 cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder;
1182 } else {
1183 cbReserveCFData = p_fci_internal->pccab->cbReserveCFData;
1184 cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder;
1187 /* START of COPY */
1188 /* if there is data in p_fci_internal->data_in */
1189 if (p_fci_internal->cdata_in!=0) {
1191 if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
1194 /* reset to get the number of data blocks of this folder which are */
1195 /* actually in this cabinet ( at least partially ) */
1196 p_fci_internal->cDataBlocks=0;
1198 if ( p_fci_internal->fNextCab ||
1199 p_fci_internal->fGetNextCabInVain ) {
1200 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+
1201 p_fci_internal->oldCCAB.cbReserveCFFolder;
1202 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1203 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1204 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1205 read_result+=4;
1207 } else {
1208 read_result= p_fci_internal->pccab->cbReserveCFHeader+
1209 p_fci_internal->pccab->cbReserveCFFolder;
1210 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1211 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1212 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1213 read_result+=4;
1216 if (p_fci_internal->fPrevCab) {
1217 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1218 strlen(p_fci_internal->szPrevDisk)+1;
1220 if (p_fci_internal->fNextCab) {
1221 read_result+=strlen(p_fci_internal->pccab->szCab)+1 +
1222 strlen(p_fci_internal->pccab->szDisk)+1;
1225 p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+
1226 sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+
1227 p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+
1228 p_fci_internal->sizeFileCFDATA1;
1229 p_fci_internal->statusFolderCopied = 0;
1231 /* report status with pfnfcis about copied size of folder */
1232 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1233 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1234 p_fci_internal->pv) == -1) {
1235 /* TODO set error code and abort */
1236 return FALSE;
1239 /* get a new temp file */
1240 if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) {
1241 /* TODO error handling */
1242 return FALSE;
1244 /* safety */
1245 if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) {
1246 /* TODO set error code */
1247 return FALSE;
1249 handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err,
1250 p_fci_internal->pv);
1252 /* get a new temp file */
1253 if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) {
1254 /* TODO error handling */
1255 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1256 /* TODO error handling of err */
1257 return FALSE;
1259 /* safety */
1260 if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) {
1261 /* TODO set error code */
1262 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1263 /* TODO error handling of err */
1264 return FALSE;
1266 handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err,
1267 p_fci_internal->pv);
1269 /* USE the variable read_result */
1270 if ( p_fci_internal->fNextCab ||
1271 p_fci_internal->fGetNextCabInVain ) {
1272 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader;
1273 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1274 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1275 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1276 read_result+=4;
1278 } else {
1279 read_result= p_fci_internal->pccab->cbReserveCFHeader;
1280 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1281 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1282 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1283 read_result+=4;
1286 if (p_fci_internal->fPrevCab) {
1287 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1288 strlen(p_fci_internal->szPrevDisk)+1;
1290 read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 +
1291 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER;
1293 if(p_fci_internal->sizeFileCFFILE1!=0) {
1294 read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder;
1297 /* Check if multiple cabinets have to be created. */
1299 /* Might be too much data for the maximum allowed cabinet size.*/
1300 /* When any further data will be added later, it might not */
1301 /* be possible to flush the cabinet, because there might */
1302 /* not be enough space to store the name of the following */
1303 /* cabinet and name of the corresponding disk. */
1304 /* So take care of this and get the name of the next cabinet */
1305 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1306 p_fci_internal->fNextCab==FALSE &&
1309 p_fci_internal->pccab->cb < read_result +
1310 p_fci_internal->sizeFileCFDATA1 +
1311 p_fci_internal->sizeFileCFFILE1 +
1312 CB_MAX_CABINET_NAME + /* next cabinet name */
1313 CB_MAX_DISK_NAME /* next disk name */
1314 ) || fGetNextCab
1317 /* save CCAB */
1318 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
1319 /* increment cabinet index */
1320 ++(p_fci_internal->pccab->iCab);
1321 /* get name of next cabinet */
1322 if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
1323 p_fci_internal->pv)) {
1324 /* TODO error handling */
1325 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1326 /* TODO error handling of err */
1327 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1328 /* TODO error handling of err */
1329 return FALSE;
1332 /* Skip a few lines of code. This is catched by the next if. */
1333 p_fci_internal->fGetNextCabInVain=TRUE;
1336 /* too much data for cabinet */
1337 if( (p_fci_internal->fGetNextCabInVain ||
1338 p_fci_internal->fNextCab ) &&
1341 p_fci_internal->oldCCAB.cb < read_result +
1342 p_fci_internal->sizeFileCFDATA1 +
1343 p_fci_internal->sizeFileCFFILE1 +
1344 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1345 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1346 ) || fGetNextCab
1349 p_fci_internal->fGetNextCabInVain=FALSE;
1350 p_fci_internal->fNextCab=TRUE;
1352 /* return FALSE if there is not enough space left*/
1353 /* this should never happen */
1354 if (p_fci_internal->oldCCAB.cb <=
1355 p_fci_internal->sizeFileCFFILE1 +
1356 read_result +
1357 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1358 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1361 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1362 /* TODO error handling of err */
1363 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1364 /* TODO error handling of err */
1366 /* close and delete p_fci_internal->handleCFFILE1 */
1367 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1368 /* TODO error handling of err */
1369 PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1370 /* TODO error handling of err */
1372 return FALSE;
1375 /* the folder will be split across cabinets */
1376 p_fci_internal->fSplitFolder=TRUE;
1378 } else {
1379 /* this should never happen */
1380 if (p_fci_internal->fNextCab) {
1381 /* TODO internal error */
1382 return FALSE;
1386 /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1387 if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err,
1388 p_fci_internal->pv) !=0 ) {
1389 /* TODO wrong return value */
1390 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1391 /* TODO error handling of err */
1392 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1393 /* TODO error handling of err */
1394 return FALSE;
1396 /* TODO error handling of err */
1398 /* save size of file CFDATA2 - required for the folder's offset to data */
1399 sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2;
1401 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) {
1402 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1403 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1404 p_fci_internal->perf->fError = TRUE;
1405 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1406 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1407 /* TODO error handling of err */
1408 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1409 /* TODO error handling of err */
1410 return FALSE;
1413 if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err,
1414 handleCFDATA1new, &sizeFileCFDATA1new, &payload
1415 )) {
1416 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1417 /* TODO error handling of err */
1418 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1419 /* TODO error handling of err */
1420 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1421 /* TODO error handling of err */
1422 PFCI_FREE(hfci,reserved);
1423 return FALSE;
1426 PFCI_FREE(hfci,reserved);
1428 if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder,
1429 sizeFileCFDATA2old )) {
1430 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1431 /* TODO error handling of err */
1432 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1433 /* TODO error handling of err */
1434 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1435 /* TODO error handling of err */
1436 return FALSE;
1439 if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new,
1440 &sizeFileCFFILE1new, payload)) {
1441 PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1442 /* TODO error handling of err */
1443 PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1444 /* TODO error handling of err */
1445 PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1446 /* TODO error handling of err */
1447 PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1448 /* TODO error handling of err */
1449 return FALSE;
1452 /* close and delete p_fci_internal->handleCFDATA1 */
1453 PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
1454 /* TODO error handling of err */
1455 PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv);
1456 /* TODO error handling of err */
1458 /* put new CFDATA1 into hfci */
1459 memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new,
1460 CB_MAX_FILENAME);
1462 /* put CFDATA1 file handle */
1463 PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new;
1464 /* set file size */
1465 PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new;
1467 /* close and delete PFCI_INT(hfci)->handleCFFILE1 */
1468 PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv);
1469 /* TODO error handling of err */
1470 PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv);
1471 /* TODO error handling of err */
1473 /* put new CFFILE1 into hfci */
1474 memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new,
1475 CB_MAX_FILENAME);
1477 /* put CFFILE1 file handle */
1478 p_fci_internal->handleCFFILE1 = handleCFFILE1new;
1479 /* set file size */
1480 p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new;
1482 ++(p_fci_internal->cFolders);
1484 /* reset CFFolder specific information */
1485 p_fci_internal->cDataBlocks=0;
1486 p_fci_internal->cCompressedBytesInFolder=0;
1488 return TRUE;
1489 } /* end of fci_flush_folder */
1494 static BOOL fci_flush_cabinet(
1495 HFCI hfci,
1496 BOOL fGetNextCab,
1497 PFNFCIGETNEXTCABINET pfnfcignc,
1498 PFNFCISTATUS pfnfcis)
1500 int err;
1501 CFHEADER cfheader;
1502 struct {
1503 cab_UWORD cbCFHeader;
1504 cab_UBYTE cbCFFolder;
1505 cab_UBYTE cbCFData;
1506 } cfreserved;
1507 CFFOLDER cffolder;
1508 cab_ULONG read_result;
1509 int handleCABINET; /* file handle for cabinet */
1510 char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */
1511 UINT cbReserveCFHeader, cbReserveCFFolder, i;
1512 char* reserved;
1513 BOOL returntrue=FALSE;
1514 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1516 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1518 /* when FCIFlushCabinet was or FCIAddFile wasn't called */
1519 if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) {
1520 returntrue=TRUE;
1523 if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){
1524 /* TODO set error */
1525 return FALSE;
1528 if(returntrue) return TRUE;
1530 if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) {
1531 /* TODO internal error */
1532 return FALSE;
1535 if( p_fci_internal->fNextCab ||
1536 p_fci_internal->fGetNextCabInVain ) {
1537 cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder;
1538 cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader;
1539 /* safety */
1540 if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH ||
1541 strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) {
1542 /* TODO set error */
1543 return FALSE;
1545 /* get the full name of the cabinet */
1546 memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath,
1547 CB_MAX_CAB_PATH);
1548 memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1549 p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME);
1550 } else {
1551 cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder;
1552 cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader;
1553 /* safety */
1554 if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH ||
1555 strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) {
1556 /* TODO set error */
1557 return FALSE;
1559 /* get the full name of the cabinet */
1560 memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath,
1561 CB_MAX_CAB_PATH);
1562 memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1563 p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME);
1566 /* create the cabinet */
1567 handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET,
1568 33538, 384, &err, p_fci_internal->pv );
1569 /* TODO check handle */
1570 /* TODO error checking of err */
1572 memcpy(cfheader.signature,"!CAB",4);
1573 cfheader.reserved1=0;
1574 cfheader.cbCabinet= /* size of the cabinet file in bytes */
1575 sizeof(CFHEADER) +
1576 p_fci_internal->sizeFileCFFOLDER +
1577 p_fci_internal->sizeFileCFFILE2 +
1578 p_fci_internal->sizeFileCFDATA2;
1580 if (p_fci_internal->fPrevCab) {
1581 cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 +
1582 strlen(p_fci_internal->szPrevDisk)+1;
1584 if (p_fci_internal->fNextCab) {
1585 cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 +
1586 strlen(p_fci_internal->pccab->szDisk)+1;
1588 if( p_fci_internal->fNextCab ||
1589 p_fci_internal->fGetNextCabInVain ) {
1590 cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1591 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1592 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1593 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1594 cfheader.cbCabinet+=4;
1596 } else {
1597 cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader;
1598 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1599 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1600 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1601 cfheader.cbCabinet+=4;
1605 cfheader.reserved2=0;
1606 cfheader.coffFiles= /* offset to first CFFILE section */
1607 cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 -
1608 p_fci_internal->sizeFileCFDATA2;
1610 cfheader.reserved3=0;
1611 cfheader.versionMinor=3;
1612 cfheader.versionMajor=1;
1613 /* number of CFFOLDER entries in the cabinet */
1614 cfheader.cFolders=p_fci_internal->cFolders;
1615 /* number of CFFILE entries in the cabinet */
1616 cfheader.cFiles=p_fci_internal->cFiles;
1617 cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved setions */
1619 if( p_fci_internal->fPrevCab ) {
1620 cfheader.flags = cfheadPREV_CABINET;
1623 if( p_fci_internal->fNextCab ) {
1624 cfheader.flags |= cfheadNEXT_CABINET;
1627 if( p_fci_internal->fNextCab ||
1628 p_fci_internal->fGetNextCabInVain ) {
1629 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1630 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1631 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1632 cfheader.flags |= cfheadRESERVE_PRESENT;
1634 cfheader.setID = p_fci_internal->oldCCAB.setID;
1635 cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1;
1636 } else {
1637 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1638 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1639 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1640 cfheader.flags |= cfheadRESERVE_PRESENT;
1642 cfheader.setID = p_fci_internal->pccab->setID;
1643 cfheader.iCabinet = p_fci_internal->pccab->iCab-1;
1646 /* set little endian */
1647 cfheader.reserved1=fci_set_little_endian_ulong(cfheader.reserved1);
1648 cfheader.cbCabinet=fci_set_little_endian_ulong(cfheader.cbCabinet);
1649 cfheader.reserved2=fci_set_little_endian_ulong(cfheader.reserved2);
1650 cfheader.coffFiles=fci_set_little_endian_ulong(cfheader.coffFiles);
1651 cfheader.reserved3=fci_set_little_endian_ulong(cfheader.reserved3);
1652 cfheader.cFolders=fci_set_little_endian_uword(cfheader.cFolders);
1653 cfheader.cFiles=fci_set_little_endian_uword(cfheader.cFiles);
1654 cfheader.flags=fci_set_little_endian_uword(cfheader.flags);
1655 cfheader.setID=fci_set_little_endian_uword(cfheader.setID);
1656 cfheader.iCabinet=fci_set_little_endian_uword(cfheader.iCabinet);
1658 /* write CFHEADER into cabinet file */
1659 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1660 &cfheader, /* memory buffer */
1661 sizeof(cfheader), /* number of bytes to copy */
1662 &err, p_fci_internal->pv) != sizeof(cfheader) ) {
1663 /* TODO write error */
1664 return FALSE;
1666 /* TODO error handling of err */
1668 /* reset little endian */
1669 cfheader.reserved1=fci_get_little_endian_ulong(cfheader.reserved1);
1670 cfheader.cbCabinet=fci_get_little_endian_ulong(cfheader.cbCabinet);
1671 cfheader.reserved2=fci_get_little_endian_ulong(cfheader.reserved2);
1672 cfheader.coffFiles=fci_get_little_endian_ulong(cfheader.coffFiles);
1673 cfheader.reserved3=fci_get_little_endian_ulong(cfheader.reserved3);
1674 cfheader.cFolders=fci_get_little_endian_uword(cfheader.cFolders);
1675 cfheader.cFiles=fci_get_little_endian_uword(cfheader.cFiles);
1676 cfheader.flags=fci_get_little_endian_uword(cfheader.flags);
1677 cfheader.setID=fci_get_little_endian_uword(cfheader.setID);
1678 cfheader.iCabinet=fci_get_little_endian_uword(cfheader.iCabinet);
1680 if( cfheader.flags & cfheadRESERVE_PRESENT ) {
1681 /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1682 cfreserved.cbCFHeader = cbReserveCFHeader;
1683 cfreserved.cbCFFolder = cbReserveCFFolder;
1684 if( p_fci_internal->fNextCab ||
1685 p_fci_internal->fGetNextCabInVain ) {
1686 cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1687 } else {
1688 cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData;
1691 /* set little endian */
1692 cfreserved.cbCFHeader=fci_set_little_endian_uword(cfreserved.cbCFHeader);
1694 /* write reserved info into cabinet file */
1695 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1696 &cfreserved, /* memory buffer */
1697 sizeof(cfreserved), /* number of bytes to copy */
1698 &err, p_fci_internal->pv) != sizeof(cfreserved) ) {
1699 /* TODO write error */
1700 return FALSE;
1702 /* TODO error handling of err */
1704 /* reset little endian */
1705 cfreserved.cbCFHeader=fci_get_little_endian_uword(cfreserved.cbCFHeader);
1708 /* add optional reserved area */
1709 if (cbReserveCFHeader!=0) {
1710 if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) {
1711 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1712 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1713 p_fci_internal->perf->fError = TRUE;
1714 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1715 return FALSE;
1717 for(i=0;i<cbReserveCFHeader;) {
1718 reserved[i++]='\0';
1720 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1721 reserved, /* memory buffer */
1722 cbReserveCFHeader, /* number of bytes to copy */
1723 &err, p_fci_internal->pv) != cbReserveCFHeader ) {
1724 PFCI_FREE(hfci, reserved);
1725 /* TODO write error */
1726 return FALSE;
1728 /* TODO error handling of err */
1729 PFCI_FREE(hfci, reserved);
1732 if( cfheader.flags & cfheadPREV_CABINET ) {
1733 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1734 p_fci_internal->szPrevCab, /* memory buffer */
1735 strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */
1736 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) {
1737 /* TODO write error */
1738 return FALSE;
1740 /* TODO error handling of err */
1742 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1743 p_fci_internal->szPrevDisk, /* memory buffer */
1744 strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */
1745 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) {
1746 /* TODO write error */
1747 return FALSE;
1749 /* TODO error handling of err */
1752 if( cfheader.flags & cfheadNEXT_CABINET ) {
1753 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1754 p_fci_internal->pccab->szCab, /* memory buffer */
1755 strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */
1756 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) {
1757 /* TODO write error */
1758 return FALSE;
1760 /* TODO error handling of err */
1762 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1763 p_fci_internal->pccab->szDisk, /* memory buffer */
1764 strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */
1765 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) {
1766 /* TODO write error */
1767 return FALSE;
1769 /* TODO error handling of err */
1772 /* set seek of p_fci_internal->handleCFFOLDER to 0 */
1773 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER,
1774 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1775 /* TODO wrong return value */
1777 /* TODO error handling of err */
1779 /* while not all CFFOLDER structures have been copied into the cabinet do */
1780 while(!FALSE) {
1781 /* use the variable read_result */
1782 /* read cffolder of p_fci_internal->handleCFFOLDER */
1783 read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */
1784 &cffolder, /* memory buffer */
1785 sizeof(cffolder), /* number of bytes to copy */
1786 &err, p_fci_internal->pv);
1787 if( read_result != sizeof(cffolder) ) {
1788 if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/
1789 /* TODO read error */
1790 return FALSE;
1792 /* TODO error handling of err */
1794 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1795 cffolder.coffCabStart +=
1796 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
1797 sizeof(CFHEADER);
1798 if( p_fci_internal->fNextCab ||
1799 p_fci_internal->fGetNextCabInVain ) {
1800 cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1801 } else {
1802 cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader;
1805 if (p_fci_internal->fPrevCab) {
1806 cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 +
1807 strlen(p_fci_internal->szPrevDisk)+1;
1810 if (p_fci_internal->fNextCab) {
1811 cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 +
1812 strlen(p_fci_internal->oldCCAB.szDisk)+1;
1815 if( p_fci_internal->fNextCab ||
1816 p_fci_internal->fGetNextCabInVain ) {
1817 cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader;
1818 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1819 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1820 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1821 cffolder.coffCabStart += 4;
1823 } else {
1824 cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader;
1825 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1826 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1827 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1828 cffolder.coffCabStart += 4;
1832 /* set little endian */
1833 cffolder.coffCabStart=fci_set_little_endian_ulong(cffolder.coffCabStart);
1834 cffolder.cCFData=fci_set_little_endian_uword(cffolder.cCFData);
1835 cffolder.typeCompress=fci_set_little_endian_uword(cffolder.typeCompress);
1837 /* write cffolder to cabinet file */
1838 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1839 &cffolder, /* memory buffer */
1840 sizeof(cffolder), /* number of bytes to copy */
1841 &err, p_fci_internal->pv) != sizeof(cffolder) ) {
1842 /* TODO write error */
1843 return FALSE;
1845 /* TODO error handling of err */
1847 /* reset little endian */
1848 cffolder.coffCabStart=fci_get_little_endian_ulong(cffolder.coffCabStart);
1849 cffolder.cCFData=fci_get_little_endian_uword(cffolder.cCFData);
1850 cffolder.typeCompress=fci_get_little_endian_uword(cffolder.typeCompress);
1852 /* add optional reserved area */
1854 /* This allocation and freeing at each CFFolder block is a bit */
1855 /* inefficent, but it's harder to forget about freeing the buffer :-). */
1856 /* Reserved areas are used seldom besides that... */
1857 if (cbReserveCFFolder!=0) {
1858 if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) {
1859 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1860 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1861 p_fci_internal->perf->fError = TRUE;
1862 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1863 return FALSE;
1866 if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
1867 reserved, /* memory buffer */
1868 cbReserveCFFolder, /* number of bytes to copy */
1869 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1870 PFCI_FREE(hfci, reserved);
1871 /* TODO read error */
1872 return FALSE;
1874 /* TODO error handling of err */
1876 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1877 reserved, /* memory buffer */
1878 cbReserveCFFolder, /* number of bytes to copy */
1879 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1880 PFCI_FREE(hfci, reserved);
1881 /* TODO read error */
1882 return FALSE;
1884 /* TODO error handling of err */
1886 PFCI_FREE(hfci, reserved);
1889 } /* END OF while */
1891 /* set seek of p_fci_internal->handleCFFILE2 to 0 */
1892 if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2,
1893 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1894 /* TODO wrong return value */
1896 /* TODO error handling of err */
1898 /* while not all CFFILE structures have been copied to the cabinet do */
1899 while(!FALSE) {
1900 /* REUSE the variable read_result */
1901 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1902 /* read a block from p_fci_internal->handleCFFILE2 */
1903 read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */,
1904 p_fci_internal->data_out, /* memory buffer */
1905 32768, /* number of bytes to copy */
1906 &err, p_fci_internal->pv);
1907 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
1908 /* TODO error handling of err */
1910 /* write the block to the cabinet file */
1911 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1912 p_fci_internal->data_out, /* memory buffer */
1913 read_result, /* number of bytes to copy */
1914 &err, p_fci_internal->pv) != read_result ) {
1915 /* TODO write error */
1916 return FALSE;
1918 /* TODO error handling of err */
1920 if (p_fci_internal->fSplitFolder==FALSE) {
1921 p_fci_internal->statusFolderCopied = 0;
1922 p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+
1923 p_fci_internal->sizeFileCFFILE2;
1925 p_fci_internal->statusFolderCopied += read_result;
1927 /* TODO is this correct */
1928 /* report status with pfnfcis about copied size of folder */
1929 if( (*pfnfcis)(statusFolder,
1930 p_fci_internal->statusFolderCopied, /* length of copied blocks */
1931 p_fci_internal->statusFolderTotal, /* total size of folder */
1932 p_fci_internal->pv) == -1) {
1933 /* TODO set error code and abort */
1934 return FALSE;
1937 } /* END OF while */
1939 /* set seek of p_fci_internal->handleCFDATA2 to 0 */
1940 if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2,
1941 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1942 /* TODO wrong return value */
1943 return FALSE;
1945 /* TODO error handling of err */
1947 /* reset the number of folders for the next cabinet */
1948 p_fci_internal->cFolders=0;
1949 /* reset the number of files for the next cabinet */
1950 p_fci_internal->cFiles=0;
1952 /* while not all CFDATA structures have been copied to the cabinet do */
1953 while(!FALSE) {
1954 /* REUSE the variable read_result AGAIN */
1955 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1956 /* read a block from p_fci_internal->handleCFDATA2 */
1957 read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */,
1958 p_fci_internal->data_out, /* memory buffer */
1959 32768, /* number of bytes to copy */
1960 &err, p_fci_internal->pv);
1961 if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */
1962 /* TODO error handling of err */
1964 /* write the block to the cabinet file */
1965 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1966 p_fci_internal->data_out, /* memory buffer */
1967 read_result, /* number of bytes to copy */
1968 &err, p_fci_internal->pv) != read_result ) {
1969 /* TODO write error */
1970 return FALSE;
1972 /* TODO error handling of err */
1974 p_fci_internal->statusFolderCopied += read_result;
1975 /* report status with pfnfcis about copied size of folder */
1976 if( (*pfnfcis)(statusFolder,
1977 p_fci_internal->statusFolderCopied, /* length of copied blocks */
1978 p_fci_internal->statusFolderTotal, /* total size of folder */
1979 p_fci_internal->pv) == -1) {
1980 /* TODO set error code and abort */
1981 return FALSE;
1983 } /* END OF while */
1985 /* set seek of the cabinet file to 0 */
1986 if( PFCI_SEEK(hfci, handleCABINET,
1987 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1988 /* TODO wrong return value */
1990 /* TODO error handling of err */
1992 /* write the signature "MSCF" into the cabinet file */
1993 memcpy( cfheader.signature, "MSCF", 4 );
1994 if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1995 &cfheader, /* memory buffer */
1996 4, /* number of bytes to copy */
1997 &err, p_fci_internal->pv) != 4 ) {
1998 /* TODO write error */
1999 return FALSE;
2001 /* TODO error handling of err */
2003 /* close the cabinet file */
2004 PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv);
2005 /* TODO error handling of err */
2008 /* COPIED FROM FCIDestroy */
2010 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2011 /* TODO error handling of err */
2012 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
2013 p_fci_internal->pv);
2014 /* TODO error handling of err */
2015 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2016 /* TODO error handling of err */
2017 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
2018 p_fci_internal->pv);
2019 /* TODO error handling of err */
2020 PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2021 /* TODO error handling of err */
2022 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
2023 p_fci_internal->pv);
2024 /* TODO error handling of err */
2026 /* END OF copied from FCIDestroy */
2028 /* get 3 temporary files and open them */
2029 /* write names and handles to hfci */
2032 p_fci_internal->sizeFileCFDATA2 = 0;
2033 p_fci_internal->sizeFileCFFILE2 = 0;
2034 p_fci_internal->sizeFileCFFOLDER = 0;
2036 /* COPIED FROM FCICreate */
2038 /* CFDATA with checksum and ready to be copied into cabinet */
2039 if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2,
2040 CB_MAX_FILENAME)) {
2041 /* TODO error handling */
2042 return FALSE;
2044 /* safety */
2045 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
2046 /* TODO set error code */
2047 return FALSE;
2049 p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
2050 p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv);
2051 /* TODO check handle */
2052 /* TODO error checking of err */
2054 /* array of all CFFILE in a folder, ready to be copied into cabinet */
2055 if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
2056 CB_MAX_FILENAME)) {
2057 /* TODO error handling */
2058 return FALSE;
2060 /* safety */
2061 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
2062 /* TODO set error code */
2063 return FALSE;
2065 p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
2066 p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv);
2067 /* TODO check handle */
2068 /* TODO error checking of err */
2070 /* array of all CFFILE in a folder, ready to be copied into cabinet */
2071 if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) {
2072 /* TODO error handling */
2073 return FALSE;
2075 /* safety */
2076 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
2077 /* TODO set error code */
2078 return FALSE;
2080 p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
2081 p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv);
2082 /* TODO check handle */
2083 /* TODO error checking of err */
2085 /* END OF copied from FCICreate */
2088 /* TODO close and delete new files when return FALSE */
2091 /* report status with pfnfcis about copied size of folder */
2092 if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */
2093 cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) {
2094 /* TODO set error code and abort */
2095 return FALSE;
2098 p_fci_internal->fPrevCab=TRUE;
2099 /* The sections szPrevCab and szPrevDisk are not being updated, because */
2100 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
2102 if (p_fci_internal->fNextCab) {
2103 p_fci_internal->fNextCab=FALSE;
2105 if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) {
2106 /* THIS CAN NEVER HAPPEN */
2107 /* TODO set error code */
2108 return FALSE;
2111 /* COPIED FROM FCIAddFile and modified */
2113 /* REUSE the variable read_result */
2114 if (p_fci_internal->fGetNextCabInVain) {
2115 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader;
2116 if(p_fci_internal->sizeFileCFFILE1!=0) {
2117 read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder;
2119 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2120 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2121 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2122 read_result+=4;
2124 } else {
2125 read_result=p_fci_internal->pccab->cbReserveCFHeader;
2126 if(p_fci_internal->sizeFileCFFILE1!=0) {
2127 read_result+=p_fci_internal->pccab->cbReserveCFFolder;
2129 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2130 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2131 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2132 read_result+=4;
2135 if ( p_fci_internal->fPrevCab ) {
2136 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2137 strlen(p_fci_internal->szPrevDisk)+1;
2139 read_result+= p_fci_internal->sizeFileCFDATA1 +
2140 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2141 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2142 sizeof(CFHEADER) +
2143 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2145 if( p_fci_internal->fNewPrevious ) {
2146 memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab,
2147 CB_MAX_CABINET_NAME);
2148 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk,
2149 CB_MAX_DISK_NAME);
2150 p_fci_internal->fNewPrevious=FALSE;
2153 /* too much data for the maximum size of a cabinet */
2154 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2155 p_fci_internal->pccab->cb < read_result ) {
2156 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2159 /* Might be too much data for the maximum size of a cabinet.*/
2160 /* When any further data will be added later, it might not */
2161 /* be possible to flush the cabinet, because there might */
2162 /* not be enough space to store the name of the following */
2163 /* cabinet and name of the corresponding disk. */
2164 /* So take care of this and get the name of the next cabinet */
2165 if (p_fci_internal->fGetNextCabInVain==FALSE && (
2166 p_fci_internal->pccab->cb < read_result +
2167 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2168 )) {
2169 /* save CCAB */
2170 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2171 /* increment cabinet index */
2172 ++(p_fci_internal->pccab->iCab);
2173 /* get name of next cabinet */
2174 if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
2175 p_fci_internal->pv)) {
2176 /* TODO error handling */
2177 return FALSE;
2179 /* Skip a few lines of code. This is catched by the next if. */
2180 p_fci_internal->fGetNextCabInVain=TRUE;
2183 /* too much data for cabinet */
2184 if (p_fci_internal->fGetNextCabInVain && (
2185 p_fci_internal->oldCCAB.cb < read_result +
2186 strlen(p_fci_internal->oldCCAB.szCab)+1+
2187 strlen(p_fci_internal->oldCCAB.szDisk)+1
2188 )) {
2189 p_fci_internal->fGetNextCabInVain=FALSE;
2190 p_fci_internal->fNextCab=TRUE;
2191 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2194 /* if the FolderThreshold has been reached flush the folder automatically */
2195 if( p_fci_internal->fGetNextCabInVain ) {
2196 if( p_fci_internal->cCompressedBytesInFolder >=
2197 p_fci_internal->oldCCAB.cbFolderThresh) {
2198 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2200 } else {
2201 if( p_fci_internal->cCompressedBytesInFolder >=
2202 p_fci_internal->pccab->cbFolderThresh) {
2203 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2207 /* END OF COPIED FROM FCIAddFile and modified */
2209 if( p_fci_internal->sizeFileCFFILE1>0 ) {
2210 if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE;
2211 p_fci_internal->fNewPrevious=TRUE;
2213 } else {
2214 p_fci_internal->fNewPrevious=FALSE;
2215 if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) {
2216 /* THIS MAY NEVER HAPPEN */
2217 /* TODO set error structures */
2218 return FALSE;
2222 return TRUE;
2223 } /* end of fci_flush_cabinet */
2229 /***********************************************************************
2230 * FCIAddFile (CABINET.11)
2232 * FCIAddFile adds a file to the to be created cabinet file
2234 * PARAMS
2235 * hfci [I] An HFCI from FCICreate
2236 * pszSourceFile [I] A pointer to a C string which contains the name and
2237 * location of the file which will be added to the cabinet
2238 * pszFileName [I] A pointer to a C string which contains the name under
2239 * which the file will be stored in the cabinet
2240 * fExecute [I] A boolean value which indicates if the file should be
2241 * executed after extraction of self extracting
2242 * executables
2243 * pfnfcignc [I] A pointer to a function which gets information about
2244 * the next cabinet
2245 * pfnfcis [IO] A pointer to a function which will report status
2246 * information about the compression process
2247 * pfnfcioi [I] A pointer to a function which reports file attributes
2248 * and time and date information
2249 * typeCompress [I] Compression type
2251 * RETURNS
2252 * On success, returns TRUE
2253 * On failure, returns FALSE
2255 * INCLUDES
2256 * fci.h
2259 BOOL __cdecl FCIAddFile(
2260 HFCI hfci,
2261 char *pszSourceFile,
2262 char *pszFileName,
2263 BOOL fExecute,
2264 PFNFCIGETNEXTCABINET pfnfcignc,
2265 PFNFCISTATUS pfnfcis,
2266 PFNFCIGETOPENINFO pfnfcigoi,
2267 TCOMP typeCompress)
2269 int err;
2270 CFFILE cffile;
2271 cab_ULONG read_result;
2272 int file_handle;
2273 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2275 /* test hfci */
2276 if (!REALLY_IS_FCI(hfci)) {
2277 SetLastError(ERROR_INVALID_HANDLE);
2278 return FALSE;
2281 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
2282 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
2283 p_fci_internal->perf->erfOper = FCIERR_NONE;
2284 p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
2285 p_fci_internal->perf->fError = TRUE;
2287 SetLastError(ERROR_BAD_ARGUMENTS);
2288 return FALSE;
2291 /* TODO check if pszSourceFile??? */
2293 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
2294 /* TODO internal error */
2295 return FALSE;
2298 if(p_fci_internal->fNextCab) {
2299 /* TODO internal error */
2300 return FALSE;
2303 cffile.cbFile=0; /* size of the to be added file*/
2304 /* offset of the uncompressed file in the folder */
2305 cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in;
2306 /* number of folder in the cabinet or special 0=first */
2307 cffile.iFolder = p_fci_internal->cFolders;
2309 /* allocation of memory */
2310 if (p_fci_internal->data_in==NULL) {
2311 if (p_fci_internal->cdata_in!=0) {
2312 /* TODO error handling */
2313 return FALSE;
2315 if (p_fci_internal->data_out!=NULL) {
2316 /* TODO error handling */
2317 return FALSE;
2319 if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) {
2320 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2321 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2322 p_fci_internal->perf->fError = TRUE;
2323 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2324 return FALSE;
2326 if (p_fci_internal->data_out==NULL) {
2327 if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){
2328 p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2329 p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2330 p_fci_internal->perf->fError = TRUE;
2331 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2332 return FALSE;
2337 if (p_fci_internal->data_out==NULL) {
2338 PFCI_FREE(hfci,p_fci_internal->data_in);
2339 /* TODO error handling */
2340 return FALSE;
2343 /* get information about the file */
2344 file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time),
2345 &(cffile.attribs), &err, p_fci_internal->pv);
2346 /* TODO check file_handle */
2347 /* TODO error handling of err */
2349 if (fExecute) { cffile.attribs |= _A_EXEC; }
2351 /* REUSE the variable read_result */
2352 if (p_fci_internal->fGetNextCabInVain) {
2353 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2354 p_fci_internal->oldCCAB.cbReserveCFFolder;
2355 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2356 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2357 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2358 read_result+=4;
2360 } else {
2361 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2362 p_fci_internal->pccab->cbReserveCFFolder;
2363 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2364 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2365 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2366 read_result+=4;
2369 if ( p_fci_internal->fPrevCab ) {
2370 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2371 strlen(p_fci_internal->szPrevDisk)+1;
2373 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2374 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2375 strlen(p_fci_internal->pccab->szDisk)+1;
2378 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
2379 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2380 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2381 sizeof(CFHEADER) +
2382 sizeof(CFFOLDER); /* size of new CFFolder entry */
2384 /* Might be too much data for the maximum size of a cabinet.*/
2385 /* When any further data will be added later, it might not */
2386 /* be possible to flush the cabinet, because there might */
2387 /* not be enough space to store the name of the following */
2388 /* cabinet and name of the corresponding disk. */
2389 /* So take care of this and get the name of the next cabinet */
2390 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2391 p_fci_internal->fNextCab==FALSE &&
2392 ( p_fci_internal->pccab->cb < read_result +
2393 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2396 /* save CCAB */
2397 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2398 /* increment cabinet index */
2399 ++(p_fci_internal->pccab->iCab);
2400 /* get name of next cabinet */
2401 if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2402 p_fci_internal->pv)) {
2403 /* TODO error handling */
2404 return FALSE;
2406 /* Skip a few lines of code. This is catched by the next if. */
2407 p_fci_internal->fGetNextCabInVain=TRUE;
2410 if( p_fci_internal->fGetNextCabInVain &&
2411 p_fci_internal->fNextCab
2413 /* THIS CAN NEVER HAPPEN */
2414 /* TODO set error code*/
2415 return FALSE;
2418 /* too much data for cabinet */
2419 if( p_fci_internal->fGetNextCabInVain &&
2421 p_fci_internal->oldCCAB.cb < read_result +
2422 strlen(p_fci_internal->pccab->szCab)+1+
2423 strlen(p_fci_internal->pccab->szDisk)+1
2424 )) {
2425 p_fci_internal->fGetNextCabInVain=FALSE;
2426 p_fci_internal->fNextCab=TRUE;
2427 if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE;
2430 if( p_fci_internal->fNextCab ) {
2431 /* THIS MAY NEVER HAPPEN */
2432 /* TODO set error code*/
2433 return FALSE;
2436 /* read the contents of the file blockwize*/
2437 while (!FALSE) {
2438 if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
2439 /* TODO internal error */
2440 return FALSE;
2443 read_result = PFCI_READ(hfci, file_handle /* file handle */,
2444 (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
2445 (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
2446 &err, p_fci_internal->pv);
2447 /* TODO error handling of err */
2449 if( read_result==0 ) break;
2451 /* increment the block size */
2452 p_fci_internal->cdata_in += read_result;
2454 /* increment the file size */
2455 cffile.cbFile += read_result;
2458 if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
2459 /* TODO report internal error */
2460 return FALSE;
2462 /* write a whole block */
2463 if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
2465 if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
2469 /* close the file from FCIAddFile */
2470 PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv);
2471 /* TODO error handling of err */
2473 /* write cffile to p_fci_internal->handleCFFILE1 */
2474 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2475 &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) {
2476 /* TODO write error */
2477 return FALSE;
2479 /* TODO error handling of err */
2481 p_fci_internal->sizeFileCFFILE1 += sizeof(cffile);
2483 /* append the name of file*/
2484 if (strlen(pszFileName)>=CB_MAX_FILENAME) {
2485 /* IMPOSSIBLE */
2486 /* TODO set error code */
2487 return FALSE;
2489 if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2490 pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv)
2491 != strlen(pszFileName)+1 ) {
2492 /* TODO write error */
2493 return FALSE;
2495 /* TODO error handling of err */
2497 p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1;
2499 /* REUSE the variable read_result */
2500 if (p_fci_internal->fGetNextCabInVain ||
2501 p_fci_internal->fNextCab
2503 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2504 p_fci_internal->oldCCAB.cbReserveCFFolder;
2505 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2506 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2507 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2508 read_result+=4;
2510 } else {
2511 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2512 p_fci_internal->pccab->cbReserveCFFolder;
2513 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2514 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2515 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2516 read_result+=4;
2519 if ( p_fci_internal->fPrevCab ) {
2520 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2521 strlen(p_fci_internal->szPrevDisk)+1;
2523 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2524 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2525 strlen(p_fci_internal->pccab->szDisk)+1;
2527 read_result+= p_fci_internal->sizeFileCFDATA1 +
2528 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2529 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2530 sizeof(CFHEADER) +
2531 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2533 /* too much data for the maximum size of a cabinet */
2534 /* (ignoring the unflushed data block) */
2535 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2536 p_fci_internal->fNextCab==FALSE && /* this is always the case */
2537 p_fci_internal->pccab->cb < read_result ) {
2538 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2541 /* Might be too much data for the maximum size of a cabinet.*/
2542 /* When any further data will be added later, it might not */
2543 /* be possible to flush the cabinet, because there might */
2544 /* not be enough space to store the name of the following */
2545 /* cabinet and name of the corresponding disk. */
2546 /* So take care of this and get the name of the next cabinet */
2547 /* (ignoring the unflushed data block) */
2548 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2549 p_fci_internal->fNextCab==FALSE &&
2550 ( p_fci_internal->pccab->cb < read_result +
2551 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2554 /* save CCAB */
2555 memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2556 /* increment cabinet index */
2557 ++(p_fci_internal->pccab->iCab);
2558 /* get name of next cabinet */
2559 if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2560 p_fci_internal->pv)) {
2561 /* TODO error handling */
2562 return FALSE;
2564 /* Skip a few lines of code. This is catched by the next if. */
2565 p_fci_internal->fGetNextCabInVain=TRUE;
2568 if( p_fci_internal->fGetNextCabInVain &&
2569 p_fci_internal->fNextCab
2571 /* THIS CAN NEVER HAPPEN */
2572 /* TODO set error code*/
2573 return FALSE;
2576 /* too much data for cabinet */
2577 if( (p_fci_internal->fGetNextCabInVain ||
2578 p_fci_internal->fNextCab) && (
2579 p_fci_internal->oldCCAB.cb < read_result +
2580 strlen(p_fci_internal->pccab->szCab)+1+
2581 strlen(p_fci_internal->pccab->szDisk)+1
2582 )) {
2584 p_fci_internal->fGetNextCabInVain=FALSE;
2585 p_fci_internal->fNextCab=TRUE;
2586 return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2589 if( p_fci_internal->fNextCab ) {
2590 /* THIS MAY NEVER HAPPEN */
2591 /* TODO set error code*/
2592 return FALSE;
2595 /* if the FolderThreshold has been reached flush the folder automatically */
2596 if( p_fci_internal->fGetNextCabInVain ) {
2597 if( p_fci_internal->cCompressedBytesInFolder >=
2598 p_fci_internal->oldCCAB.cbFolderThresh) {
2599 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2601 } else {
2602 if( p_fci_internal->cCompressedBytesInFolder >=
2603 p_fci_internal->pccab->cbFolderThresh) {
2604 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2608 return TRUE;
2609 } /* end of FCIAddFile */
2615 /***********************************************************************
2616 * FCIFlushFolder (CABINET.12)
2618 * FCIFlushFolder completes the CFFolder structure under construction.
2620 * All further data which is added by FCIAddFile will be associateed to
2621 * the next CFFolder structure.
2623 * FCIFlushFolder will be called by FCIAddFile automatically if the
2624 * threshold (stored in the member cbFolderThresh of the CCAB structure
2625 * pccab passed to FCICreate) is exceeded.
2627 * FCIFlushFolder will be called by FCIFlushFolder automatically before
2628 * any data will be written into the cabinet file.
2630 * PARAMS
2631 * hfci [I] An HFCI from FCICreate
2632 * pfnfcignc [I] A pointer to a function which gets information about
2633 * the next cabinet
2634 * pfnfcis [IO] A pointer to a function which will report status
2635 * information about the compression process
2637 * RETURNS
2638 * On success, returns TRUE
2639 * On failure, returns FALSE
2641 * INCLUDES
2642 * fci.h
2645 BOOL __cdecl FCIFlushFolder(
2646 HFCI hfci,
2647 PFNFCIGETNEXTCABINET pfnfcignc,
2648 PFNFCISTATUS pfnfcis)
2650 return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis);
2651 } /* end of FCIFlushFolder */
2655 /***********************************************************************
2656 * FCIFlushCabinet (CABINET.13)
2658 * FCIFlushCabinet stores the data which has been added by FCIAddFile
2659 * into the cabinet file. If the maximum cabinet size (stored in the
2660 * member cb of the CCAB structure pccab passed to FCICreate) has been
2661 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2662 * The remaining data still has to be flushed manually by calling
2663 * FCIFlushCabinet.
2665 * After FCIFlushCabinet has been called (manually) FCIAddFile must
2666 * NOT be called again. Then hfci has to be released by FCIDestroy.
2668 * PARAMS
2669 * hfci [I] An HFCI from FCICreate
2670 * fGetNextCab [I] Whether you want to add additional files to a
2671 * cabinet set (TRUE) or whether you want to
2672 * finalize it (FALSE)
2673 * pfnfcignc [I] A pointer to a function which gets information about
2674 * the next cabinet
2675 * pfnfcis [IO] A pointer to a function which will report status
2676 * information about the compression process
2678 * RETURNS
2679 * On success, returns TRUE
2680 * On failure, returns FALSE
2682 * INCLUDES
2683 * fci.h
2686 BOOL __cdecl FCIFlushCabinet(
2687 HFCI hfci,
2688 BOOL fGetNextCab,
2689 PFNFCIGETNEXTCABINET pfnfcignc,
2690 PFNFCISTATUS pfnfcis)
2692 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2694 if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2696 while( p_fci_internal->sizeFileCFFILE1>0 ||
2697 p_fci_internal->sizeFileCFFILE2>0 ) {
2698 if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2701 return TRUE;
2702 } /* end of FCIFlushCabinet */
2705 /***********************************************************************
2706 * FCIDestroy (CABINET.14)
2708 * Frees a handle created by FCICreate.
2709 * Only reason for failure would be an invalid handle.
2711 * PARAMS
2712 * hfci [I] The HFCI to free
2714 * RETURNS
2715 * TRUE for success
2716 * FALSE for failure
2718 BOOL __cdecl FCIDestroy(HFCI hfci)
2720 int err;
2721 PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2722 if (REALLY_IS_FCI(hfci)) {
2724 /* before hfci can be removed all temporary files must be closed */
2725 /* and deleted */
2726 p_fci_internal->FCI_Intmagic = 0;
2728 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
2729 /* TODO error handling of err */
2730 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err,
2731 p_fci_internal->pv);
2732 /* TODO error handling of err */
2733 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);
2734 /* TODO error handling of err */
2735 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err,
2736 p_fci_internal->pv);
2737 /* TODO error handling of err */
2738 PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2739 /* TODO error handling of err */
2740 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
2741 p_fci_internal->pv);
2742 /* TODO error handling of err */
2743 PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2744 /* TODO error handling of err */
2745 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
2746 p_fci_internal->pv);
2747 /* TODO error handling of err */
2748 PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2749 /* TODO error handling of err */
2750 PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
2751 p_fci_internal->pv);
2752 /* TODO error handling of err */
2754 /* data in and out buffers have to be removed */
2755 if (p_fci_internal->data_in!=NULL)
2756 PFCI_FREE(hfci, p_fci_internal->data_in);
2757 if (p_fci_internal->data_out!=NULL)
2758 PFCI_FREE(hfci, p_fci_internal->data_out);
2760 /* hfci can now be removed */
2761 PFCI_FREE(hfci, hfci);
2762 return TRUE;
2763 } else {
2764 SetLastError(ERROR_INVALID_HANDLE);
2765 return FALSE;
2768 } /* end of FCIDestroy */