Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/cabinet/fci.c
4389 views
1
/*
2
* File Compression Interface
3
*
4
* Copyright 2002 Patrik Stridvall
5
* Copyright 2005 Gerold Jens Wucherpfennig
6
* Copyright 2011 Alexandre Julliard
7
*
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
12
*
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
17
*
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21
*/
22
23
/*
24
25
There is still some work to be done:
26
27
- unknown behaviour if files>=2GB or cabinet >=4GB
28
- check if the maximum size for a cabinet is too small to store any data
29
- call pfnfcignc on exactly the same position as MS FCIAddFile in every case
30
31
*/
32
33
#include <assert.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <string.h>
37
#include <sys/stat.h>
38
#include <fcntl.h>
39
#include <zlib.h>
40
41
#include "windef.h"
42
#include "winbase.h"
43
#include "winerror.h"
44
#include "winternl.h"
45
#include "fci.h"
46
#include "cabinet.h"
47
#include "wine/list.h"
48
#include "wine/debug.h"
49
50
WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
51
52
#ifdef WORDS_BIGENDIAN
53
#define fci_endian_ulong(x) RtlUlongByteSwap(x)
54
#define fci_endian_uword(x) RtlUshortByteSwap(x)
55
#else
56
#define fci_endian_ulong(x) (x)
57
#define fci_endian_uword(x) (x)
58
#endif
59
60
61
typedef struct {
62
cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
63
cab_ULONG reserved1;
64
cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
65
cab_ULONG reserved2;
66
cab_ULONG coffFiles; /* offset to first CFFILE section */
67
cab_ULONG reserved3;
68
cab_UBYTE versionMinor; /* 3 */
69
cab_UBYTE versionMajor; /* 1 */
70
cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
71
cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
72
cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
73
cab_UWORD setID; /* identification number of all cabinets in a set*/
74
cab_UWORD iCabinet; /* number of the cabinet in a set */
75
/* additional area if "flags" were set*/
76
} CFHEADER; /* minimum 36 bytes */
77
78
typedef struct {
79
cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
80
cab_UWORD cCFData; /* number of this folder's CFDATA sections */
81
cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
82
/* additional area if reserve flag was set */
83
} CFFOLDER; /* minimum 8 bytes */
84
85
typedef struct {
86
cab_ULONG cbFile; /* size of the uncompressed file in bytes */
87
cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
88
cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
89
/* for special values see below this structure*/
90
cab_UWORD date; /* last modification date*/
91
cab_UWORD time; /* last modification time*/
92
cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
93
/* ... and a C string with the name of the file */
94
} CFFILE; /* 16 bytes + name of file */
95
96
97
typedef struct {
98
cab_ULONG csum; /* checksum of this entry*/
99
cab_UWORD cbData; /* number of compressed bytes */
100
cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
101
/* optional reserved area */
102
/* compressed data */
103
} CFDATA;
104
105
struct temp_file
106
{
107
INT_PTR handle;
108
char name[CB_MAX_FILENAME];
109
};
110
111
struct folder
112
{
113
struct list entry;
114
struct list files_list;
115
struct list blocks_list;
116
struct temp_file data;
117
cab_ULONG data_start;
118
cab_UWORD data_count;
119
TCOMP compression;
120
};
121
122
struct file
123
{
124
struct list entry;
125
cab_ULONG size; /* uncompressed size */
126
cab_ULONG offset; /* offset in folder */
127
cab_UWORD folder; /* index of folder */
128
cab_UWORD date;
129
cab_UWORD time;
130
cab_UWORD attribs;
131
char name[1];
132
};
133
134
struct data_block
135
{
136
struct list entry;
137
cab_UWORD compressed;
138
cab_UWORD uncompressed;
139
};
140
141
typedef struct FCI_Int
142
{
143
unsigned int magic;
144
PERF perf;
145
PFNFCIFILEPLACED fileplaced;
146
PFNFCIALLOC alloc;
147
PFNFCIFREE free;
148
PFNFCIOPEN open;
149
PFNFCIREAD read;
150
PFNFCIWRITE write;
151
PFNFCICLOSE close;
152
PFNFCISEEK seek;
153
PFNFCIDELETE delete;
154
PFNFCIGETTEMPFILE gettemp;
155
CCAB ccab;
156
PCCAB pccab;
157
BOOL fPrevCab;
158
BOOL fNextCab;
159
BOOL fSplitFolder;
160
cab_ULONG statusFolderCopied;
161
cab_ULONG statusFolderTotal;
162
BOOL fGetNextCabInVain;
163
void *pv;
164
char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
165
char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
166
unsigned char data_in[CAB_BLOCKMAX]; /* uncompressed data blocks */
167
unsigned char data_out[2 * CAB_BLOCKMAX]; /* compressed data blocks */
168
cab_UWORD cdata_in;
169
ULONG cCompressedBytesInFolder;
170
cab_UWORD cFolders;
171
cab_UWORD cFiles;
172
cab_ULONG cDataBlocks;
173
cab_ULONG cbFileRemainder; /* uncompressed, yet to be written data */
174
/* of spanned file of a spanning folder of a spanning cabinet */
175
struct temp_file data;
176
BOOL fNewPrevious;
177
cab_ULONG estimatedCabinetSize;
178
struct list folders_list;
179
struct list files_list;
180
struct list blocks_list;
181
cab_ULONG folders_size;
182
cab_ULONG files_size; /* size of files not yet assigned to a folder */
183
cab_ULONG placed_files_size; /* size of files already placed into a folder */
184
cab_ULONG pending_data_size; /* size of data not yet assigned to a folder */
185
cab_ULONG folders_data_size; /* total size of data contained in the current folders */
186
TCOMP compression;
187
cab_UWORD (*compress)(struct FCI_Int *);
188
} FCI_Int;
189
190
#define FCI_INT_MAGIC 0xfcfcfc05
191
192
static void set_error( FCI_Int *fci, int oper, int err )
193
{
194
fci->perf->erfOper = oper;
195
fci->perf->erfType = err;
196
fci->perf->fError = TRUE;
197
if (err) SetLastError( err );
198
}
199
200
static FCI_Int *get_fci_ptr( HFCI hfci )
201
{
202
FCI_Int *fci= (FCI_Int *)hfci;
203
204
if (!fci || fci->magic != FCI_INT_MAGIC)
205
{
206
SetLastError( ERROR_INVALID_HANDLE );
207
return NULL;
208
}
209
return fci;
210
}
211
212
/* compute the cabinet header size */
213
static cab_ULONG get_header_size( FCI_Int *fci )
214
{
215
cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
216
217
if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
218
ret += 4;
219
220
if (fci->fPrevCab)
221
ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
222
223
if (fci->fNextCab)
224
ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
225
226
return ret;
227
}
228
229
static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
230
{
231
int err;
232
233
if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
234
{
235
set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
236
return FALSE;
237
}
238
if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
239
_S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
240
{
241
set_error( fci, FCIERR_TEMP_FILE, err );
242
return FALSE;
243
}
244
return TRUE;
245
}
246
247
static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
248
{
249
int err;
250
251
if (file->handle == -1) return TRUE;
252
if (fci->close( file->handle, &err, fci->pv ) == -1)
253
{
254
set_error( fci, FCIERR_TEMP_FILE, err );
255
return FALSE;
256
}
257
file->handle = -1;
258
if (fci->delete( file->name, &err, fci->pv ) == -1)
259
{
260
set_error( fci, FCIERR_TEMP_FILE, err );
261
return FALSE;
262
}
263
return TRUE;
264
}
265
266
static struct file *add_file( FCI_Int *fci, const char *filename )
267
{
268
unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
269
struct file *file = fci->alloc( size );
270
271
if (!file)
272
{
273
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
274
return NULL;
275
}
276
file->size = 0;
277
file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
278
file->folder = fci->cFolders;
279
file->date = 0;
280
file->time = 0;
281
file->attribs = 0;
282
strcpy( file->name, filename );
283
list_add_tail( &fci->files_list, &file->entry );
284
fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
285
return file;
286
}
287
288
static struct file *copy_file( FCI_Int *fci, const struct file *orig )
289
{
290
unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
291
struct file *file = fci->alloc( size );
292
293
if (!file)
294
{
295
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
296
return NULL;
297
}
298
memcpy( file, orig, size );
299
return file;
300
}
301
302
static void free_file( FCI_Int *fci, struct file *file )
303
{
304
list_remove( &file->entry );
305
fci->free( file );
306
}
307
308
/* create a new data block for the data in fci->data_in */
309
static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
310
{
311
int err;
312
struct data_block *block;
313
314
if (!fci->cdata_in) return TRUE;
315
316
if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
317
318
if (!(block = fci->alloc( sizeof(*block) )))
319
{
320
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
321
return FALSE;
322
}
323
block->uncompressed = fci->cdata_in;
324
block->compressed = fci->compress( fci );
325
326
if (fci->write( fci->data.handle, fci->data_out,
327
block->compressed, &err, fci->pv ) != block->compressed)
328
{
329
set_error( fci, FCIERR_TEMP_FILE, err );
330
fci->free( block );
331
return FALSE;
332
}
333
334
fci->cdata_in = 0;
335
fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
336
fci->cCompressedBytesInFolder += block->compressed;
337
fci->cDataBlocks++;
338
list_add_tail( &fci->blocks_list, &block->entry );
339
340
if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
341
{
342
set_error( fci, FCIERR_USER_ABORT, 0 );
343
return FALSE;
344
}
345
return TRUE;
346
}
347
348
/* add compressed blocks for all the data that can be read from the file */
349
static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
350
PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
351
{
352
int err, len;
353
INT_PTR handle;
354
struct file *file;
355
356
if (!(file = add_file( fci, filename ))) return FALSE;
357
358
handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
359
if (handle == -1)
360
{
361
free_file( fci, file );
362
set_error( fci, FCIERR_OPEN_SRC, err );
363
return FALSE;
364
}
365
if (execute) file->attribs |= _A_EXEC;
366
367
for (;;)
368
{
369
len = fci->read( handle, fci->data_in + fci->cdata_in,
370
CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
371
if (!len) break;
372
373
if (len == -1)
374
{
375
set_error( fci, FCIERR_READ_SRC, err );
376
return FALSE;
377
}
378
file->size += len;
379
fci->cdata_in += len;
380
if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
381
}
382
fci->close( handle, &err, fci->pv );
383
return TRUE;
384
}
385
386
static void free_data_block( FCI_Int *fci, struct data_block *block )
387
{
388
list_remove( &block->entry );
389
fci->free( block );
390
}
391
392
static struct folder *add_folder( FCI_Int *fci )
393
{
394
struct folder *folder = fci->alloc( sizeof(*folder) );
395
396
if (!folder)
397
{
398
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
399
return NULL;
400
}
401
folder->data.handle = -1;
402
folder->data_start = fci->folders_data_size;
403
folder->data_count = 0;
404
folder->compression = fci->compression;
405
list_init( &folder->files_list );
406
list_init( &folder->blocks_list );
407
list_add_tail( &fci->folders_list, &folder->entry );
408
fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
409
fci->cFolders++;
410
return folder;
411
}
412
413
static void free_folder( FCI_Int *fci, struct folder *folder )
414
{
415
struct file *file, *file_next;
416
struct data_block *block, *block_next;
417
418
LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
419
free_file( fci, file );
420
LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
421
free_data_block( fci, block );
422
close_temp_file( fci, &folder->data );
423
list_remove( &folder->entry );
424
fci->free( folder );
425
}
426
427
/* reset state for the next cabinet file once the current one has been flushed */
428
static void reset_cabinet( FCI_Int *fci )
429
{
430
struct folder *folder, *folder_next;
431
432
LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
433
free_folder( fci, folder );
434
435
fci->cFolders = 0;
436
fci->cFiles = 0;
437
fci->folders_size = 0;
438
fci->placed_files_size = 0;
439
fci->folders_data_size = 0;
440
}
441
442
static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
443
{
444
cab_ULONG csum;
445
cab_ULONG ul;
446
int cUlong;
447
const BYTE *pb;
448
449
csum = seed;
450
cUlong = cb / 4;
451
pb = pv;
452
453
while (cUlong-- > 0) {
454
ul = *pb++;
455
ul |= (((cab_ULONG)(*pb++)) << 8);
456
ul |= (((cab_ULONG)(*pb++)) << 16);
457
ul |= (((cab_ULONG)(*pb++)) << 24);
458
csum ^= ul;
459
}
460
461
ul = 0;
462
switch (cb % 4) {
463
case 3:
464
ul |= (((ULONG)(*pb++)) << 16);
465
/* fall through */
466
case 2:
467
ul |= (((ULONG)(*pb++)) << 8);
468
/* fall through */
469
case 1:
470
ul |= *pb;
471
/* fall through */
472
default:
473
break;
474
}
475
csum ^= ul;
476
477
return csum;
478
}
479
480
/* copy all remaining data block to a new temp file */
481
static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
482
struct temp_file *temp, PFNFCISTATUS status_callback )
483
{
484
struct data_block *block;
485
int err;
486
487
if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
488
{
489
set_error( fci, FCIERR_TEMP_FILE, err );
490
return FALSE;
491
}
492
if (!create_temp_file( fci, temp )) return FALSE;
493
494
LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
495
{
496
if (fci->read( handle, fci->data_out, block->compressed,
497
&err, fci->pv ) != block->compressed)
498
{
499
close_temp_file( fci, temp );
500
set_error( fci, FCIERR_TEMP_FILE, err );
501
return FALSE;
502
}
503
if (fci->write( temp->handle, fci->data_out, block->compressed,
504
&err, fci->pv ) != block->compressed)
505
{
506
close_temp_file( fci, temp );
507
set_error( fci, FCIERR_TEMP_FILE, err );
508
return FALSE;
509
}
510
fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
511
fci->statusFolderCopied += block->compressed;
512
513
if (status_callback( statusFolder, fci->statusFolderCopied,
514
fci->statusFolderTotal, fci->pv) == -1)
515
{
516
close_temp_file( fci, temp );
517
set_error( fci, FCIERR_USER_ABORT, 0 );
518
return FALSE;
519
}
520
}
521
return TRUE;
522
}
523
524
/* write all folders to disk and remove them from the list */
525
static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
526
{
527
struct folder *folder;
528
int err;
529
CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
530
cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
531
532
memset( cffolder, 0, folder_size );
533
534
/* write the folders */
535
LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
536
{
537
cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
538
cffolder->cCFData = fci_endian_uword( folder->data_count );
539
cffolder->typeCompress = fci_endian_uword( folder->compression );
540
if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
541
{
542
set_error( fci, FCIERR_CAB_FILE, err );
543
return FALSE;
544
}
545
}
546
return TRUE;
547
}
548
549
/* write all the files to the cabinet file */
550
static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
551
{
552
cab_ULONG file_size;
553
struct folder *folder;
554
struct file *file;
555
int err;
556
CFFILE *cffile = (CFFILE *)fci->data_out;
557
558
LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
559
{
560
LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
561
{
562
cffile->cbFile = fci_endian_ulong( file->size );
563
cffile->uoffFolderStart = fci_endian_ulong( file->offset );
564
cffile->iFolder = fci_endian_uword( file->folder );
565
cffile->date = fci_endian_uword( file->date );
566
cffile->time = fci_endian_uword( file->time );
567
cffile->attribs = fci_endian_uword( file->attribs );
568
lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
569
file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
570
if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
571
{
572
set_error( fci, FCIERR_CAB_FILE, err );
573
return FALSE;
574
}
575
if (!fci->fSplitFolder)
576
{
577
fci->statusFolderCopied = 0;
578
/* TODO TEST THIS further */
579
fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
580
}
581
fci->statusFolderCopied += file_size;
582
/* report status about copied size of folder */
583
if (status_callback( statusFolder, fci->statusFolderCopied,
584
fci->statusFolderTotal, fci->pv ) == -1)
585
{
586
set_error( fci, FCIERR_USER_ABORT, 0 );
587
return FALSE;
588
}
589
}
590
}
591
return TRUE;
592
}
593
594
/* write all data blocks to the cabinet file */
595
static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
596
{
597
struct folder *folder;
598
struct data_block *block;
599
int err, len;
600
CFDATA *cfdata;
601
void *data;
602
cab_UWORD header_size;
603
604
header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
605
cfdata = (CFDATA *)fci->data_out;
606
memset( cfdata, 0, header_size );
607
data = (char *)cfdata + header_size;
608
609
LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
610
{
611
if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
612
{
613
set_error( fci, FCIERR_CAB_FILE, err );
614
return FALSE;
615
}
616
LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
617
{
618
len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
619
if (len != block->compressed) return FALSE;
620
621
cfdata->cbData = fci_endian_uword( block->compressed );
622
cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
623
cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
624
header_size - FIELD_OFFSET(CFDATA, cbData),
625
fci_get_checksum( data, len, 0 )));
626
627
fci->statusFolderCopied += len;
628
len += header_size;
629
if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
630
{
631
set_error( fci, FCIERR_CAB_FILE, err );
632
return FALSE;
633
}
634
if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
635
{
636
set_error( fci, FCIERR_USER_ABORT, 0 );
637
return FALSE;
638
}
639
}
640
}
641
return TRUE;
642
}
643
644
/* write the cabinet file to disk */
645
static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
646
{
647
char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
648
int err;
649
char *ptr;
650
INT_PTR handle;
651
CFHEADER *cfheader = (CFHEADER *)fci->data_out;
652
cab_UWORD flags = 0;
653
cab_ULONG header_size = get_header_size( fci );
654
cab_ULONG total_size = header_size + fci->folders_size +
655
fci->placed_files_size + fci->folders_data_size;
656
657
assert( header_size <= sizeof(fci->data_out) );
658
memset( cfheader, 0, header_size );
659
660
if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
661
if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
662
if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
663
flags |= cfheadRESERVE_PRESENT;
664
665
memcpy( cfheader->signature, "!CAB", 4 );
666
cfheader->cbCabinet = fci_endian_ulong( total_size );
667
cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
668
cfheader->versionMinor = 3;
669
cfheader->versionMajor = 1;
670
cfheader->cFolders = fci_endian_uword( fci->cFolders );
671
cfheader->cFiles = fci_endian_uword( fci->cFiles );
672
cfheader->flags = fci_endian_uword( flags );
673
cfheader->setID = fci_endian_uword( fci->ccab.setID );
674
cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
675
ptr = (char *)(cfheader + 1);
676
677
if (flags & cfheadRESERVE_PRESENT)
678
{
679
struct
680
{
681
cab_UWORD cbCFHeader;
682
cab_UBYTE cbCFFolder;
683
cab_UBYTE cbCFData;
684
} *reserve = (void *)ptr;
685
686
reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
687
reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
688
reserve->cbCFData = fci->ccab.cbReserveCFData;
689
ptr = (char *)(reserve + 1);
690
}
691
ptr += fci->ccab.cbReserveCFHeader;
692
693
if (flags & cfheadPREV_CABINET)
694
{
695
strcpy( ptr, fci->szPrevCab );
696
ptr += strlen( ptr ) + 1;
697
strcpy( ptr, fci->szPrevDisk );
698
ptr += strlen( ptr ) + 1;
699
}
700
701
if (flags & cfheadNEXT_CABINET)
702
{
703
strcpy( ptr, fci->pccab->szCab );
704
ptr += strlen( ptr ) + 1;
705
strcpy( ptr, fci->pccab->szDisk );
706
ptr += strlen( ptr ) + 1;
707
}
708
709
assert( ptr - (char *)cfheader == header_size );
710
711
strcpy( filename, fci->ccab.szCabPath );
712
strcat( filename, fci->ccab.szCab );
713
714
if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
715
_S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
716
{
717
set_error( fci, FCIERR_CAB_FILE, err );
718
return FALSE;
719
}
720
721
if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
722
{
723
set_error( fci, FCIERR_CAB_FILE, err );
724
goto failed;
725
}
726
727
/* add size of header size of all CFFOLDERs and size of all CFFILEs */
728
header_size += fci->placed_files_size + fci->folders_size;
729
if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
730
if (!write_files( fci, handle, status_callback )) goto failed;
731
if (!write_data_blocks( fci, handle, status_callback )) goto failed;
732
733
/* update the signature */
734
if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
735
{
736
set_error( fci, FCIERR_CAB_FILE, err );
737
goto failed;
738
}
739
memcpy( cfheader->signature, "MSCF", 4 );
740
if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
741
{
742
set_error( fci, FCIERR_CAB_FILE, err );
743
goto failed;
744
}
745
fci->close( handle, &err, fci->pv );
746
747
reset_cabinet( fci );
748
status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
749
return TRUE;
750
751
failed:
752
fci->close( handle, &err, fci->pv );
753
fci->delete( filename, &err, fci->pv );
754
return FALSE;
755
}
756
757
/* add all pending data blocks folder */
758
static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
759
PFNFCISTATUS status_callback )
760
{
761
struct data_block *block, *new, *next;
762
BOOL split_block = FALSE;
763
cab_ULONG current_size, start_pos = 0;
764
765
*payload = 0;
766
current_size = get_header_size( fci ) + fci->folders_size +
767
fci->files_size + fci->placed_files_size + fci->folders_data_size;
768
769
/* move the temp file into the folder structure */
770
folder->data = fci->data;
771
fci->data.handle = -1;
772
fci->pending_data_size = 0;
773
774
LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
775
{
776
/* No more CFDATA fits into the cabinet under construction */
777
/* So don't try to store more data into it */
778
if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
779
current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
780
break;
781
782
if (!(new = fci->alloc( sizeof(*new) )))
783
{
784
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
785
return FALSE;
786
}
787
/* Is cabinet with new CFDATA too large? Then data block has to be split */
788
if( fci->fNextCab &&
789
(fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
790
block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
791
{
792
/* Modify the size of the compressed data to store only a part of the */
793
/* data block into the current cabinet. This is done to prevent */
794
/* that the maximum cabinet size will be exceeded. The remainder */
795
/* will be stored into the next following cabinet. */
796
797
new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
798
sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
799
new->uncompressed = 0; /* on split blocks of data this is zero */
800
block->compressed -= new->compressed;
801
split_block = TRUE;
802
}
803
else
804
{
805
new->compressed = block->compressed;
806
new->uncompressed = block->uncompressed;
807
}
808
809
start_pos += new->compressed;
810
current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
811
fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
812
fci->statusFolderCopied += new->compressed;
813
(*payload) += new->uncompressed;
814
815
list_add_tail( &folder->blocks_list, &new->entry );
816
folder->data_count++;
817
818
/* report status with pfnfcis about copied size of folder */
819
if (status_callback( statusFolder, fci->statusFolderCopied,
820
fci->statusFolderTotal, fci->pv ) == -1)
821
{
822
set_error( fci, FCIERR_USER_ABORT, 0 );
823
return FALSE;
824
}
825
if (split_block) break;
826
free_data_block( fci, block );
827
fci->cDataBlocks--;
828
}
829
830
if (list_empty( &fci->blocks_list )) return TRUE;
831
return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
832
}
833
834
/* add all pending files to folder */
835
static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
836
{
837
cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
838
cab_ULONG cbFileRemainder = 0;
839
struct file *file, *next;
840
841
LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
842
{
843
cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
844
845
/* fnfilfnfildest: placed file on cabinet */
846
fci->fileplaced( &fci->ccab, file->name, file->size,
847
(file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
848
849
sizeOfFilesPrev = sizeOfFiles;
850
/* set complete size of all processed files */
851
if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainder != 0)
852
{
853
sizeOfFiles += fci->cbFileRemainder;
854
fci->cbFileRemainder = 0;
855
}
856
else sizeOfFiles += file->size;
857
858
/* check if spanned file fits into this cabinet folder */
859
if (sizeOfFiles > payload)
860
{
861
if (file->folder == cffileCONTINUED_FROM_PREV)
862
file->folder = cffileCONTINUED_PREV_AND_NEXT;
863
else
864
file->folder = cffileCONTINUED_TO_NEXT;
865
}
866
867
list_remove( &file->entry );
868
list_add_tail( &folder->files_list, &file->entry );
869
fci->placed_files_size += size;
870
fci->cFiles++;
871
872
/* This is only true for files which will be written into the */
873
/* next cabinet of the spanning folder */
874
if (sizeOfFiles > payload)
875
{
876
/* add a copy back onto the list */
877
if (!(file = copy_file( fci, file ))) return FALSE;
878
list_add_before( &next->entry, &file->entry );
879
880
/* Files which data will be partially written into the current cabinet */
881
if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
882
{
883
if (sizeOfFilesPrev <= payload)
884
{
885
/* The size of the uncompressed, data of a spanning file in a */
886
/* spanning data */
887
cbFileRemainder = sizeOfFiles - payload;
888
}
889
file->folder = cffileCONTINUED_FROM_PREV;
890
}
891
else file->folder = 0;
892
}
893
else
894
{
895
fci->files_size -= size;
896
}
897
}
898
fci->cbFileRemainder = cbFileRemainder;
899
return TRUE;
900
}
901
902
static cab_UWORD compress_NONE( FCI_Int *fci )
903
{
904
memcpy( fci->data_out, fci->data_in, fci->cdata_in );
905
return fci->cdata_in;
906
}
907
908
static void *zalloc( void *opaque, unsigned int items, unsigned int size )
909
{
910
FCI_Int *fci = opaque;
911
return fci->alloc( items * size );
912
}
913
914
static void zfree( void *opaque, void *ptr )
915
{
916
FCI_Int *fci = opaque;
917
fci->free( ptr );
918
}
919
920
static cab_UWORD compress_MSZIP( FCI_Int *fci )
921
{
922
z_stream stream;
923
924
stream.zalloc = zalloc;
925
stream.zfree = zfree;
926
stream.opaque = fci;
927
if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
928
{
929
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
930
return 0;
931
}
932
stream.next_in = fci->data_in;
933
stream.avail_in = fci->cdata_in;
934
stream.next_out = fci->data_out + 2;
935
stream.avail_out = sizeof(fci->data_out) - 2;
936
/* insert the signature */
937
fci->data_out[0] = 'C';
938
fci->data_out[1] = 'K';
939
deflate( &stream, Z_FINISH );
940
deflateEnd( &stream );
941
return stream.total_out + 2;
942
}
943
944
945
/***********************************************************************
946
* FCICreate (CABINET.10)
947
*
948
* FCICreate is provided with several callbacks and
949
* returns a handle which can be used to create cabinet files.
950
*
951
* PARAMS
952
* perf [IO] A pointer to an ERF structure. When FCICreate
953
* returns an error condition, error information may
954
* be found here as well as from GetLastError.
955
* pfnfiledest [I] A pointer to a function which is called when a file
956
* is placed. Only useful for subsequent cabinet files.
957
* pfnalloc [I] A pointer to a function which allocates ram. Uses
958
* the same interface as malloc.
959
* pfnfree [I] A pointer to a function which frees ram. Uses the
960
* same interface as free.
961
* pfnopen [I] A pointer to a function which opens a file. Uses
962
* the same interface as _open.
963
* pfnread [I] A pointer to a function which reads from a file into
964
* a caller-provided buffer. Uses the same interface
965
* as _read.
966
* pfnwrite [I] A pointer to a function which writes to a file from
967
* a caller-provided buffer. Uses the same interface
968
* as _write.
969
* pfnclose [I] A pointer to a function which closes a file handle.
970
* Uses the same interface as _close.
971
* pfnseek [I] A pointer to a function which seeks in a file.
972
* Uses the same interface as _lseek.
973
* pfndelete [I] A pointer to a function which deletes a file.
974
* pfnfcigtf [I] A pointer to a function which gets the name of a
975
* temporary file.
976
* pccab [I] A pointer to an initialized CCAB structure.
977
* pv [I] A pointer to an application-defined notification
978
* function which will be passed to other FCI functions
979
* as a parameter.
980
*
981
* RETURNS
982
* On success, returns an FCI handle of type HFCI.
983
* On failure, the NULL file handle is returned. Error
984
* info can be retrieved from perf.
985
*
986
* INCLUDES
987
* fci.h
988
*
989
*/
990
HFCI __cdecl FCICreate(
991
PERF perf,
992
PFNFCIFILEPLACED pfnfiledest,
993
PFNFCIALLOC pfnalloc,
994
PFNFCIFREE pfnfree,
995
PFNFCIOPEN pfnopen,
996
PFNFCIREAD pfnread,
997
PFNFCIWRITE pfnwrite,
998
PFNFCICLOSE pfnclose,
999
PFNFCISEEK pfnseek,
1000
PFNFCIDELETE pfndelete,
1001
PFNFCIGETTEMPFILE pfnfcigtf,
1002
PCCAB pccab,
1003
void *pv)
1004
{
1005
FCI_Int *p_fci_internal;
1006
1007
if (!perf) {
1008
SetLastError(ERROR_BAD_ARGUMENTS);
1009
return NULL;
1010
}
1011
if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1012
(!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1013
(!pfnfcigtf) || (!pccab)) {
1014
perf->erfOper = FCIERR_NONE;
1015
perf->erfType = ERROR_BAD_ARGUMENTS;
1016
perf->fError = TRUE;
1017
1018
SetLastError(ERROR_BAD_ARGUMENTS);
1019
return NULL;
1020
}
1021
1022
if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1023
perf->erfOper = FCIERR_ALLOC_FAIL;
1024
perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1025
perf->fError = TRUE;
1026
1027
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1028
return NULL;
1029
}
1030
1031
memset(p_fci_internal, 0, sizeof(FCI_Int));
1032
p_fci_internal->magic = FCI_INT_MAGIC;
1033
p_fci_internal->perf = perf;
1034
p_fci_internal->fileplaced = pfnfiledest;
1035
p_fci_internal->alloc = pfnalloc;
1036
p_fci_internal->free = pfnfree;
1037
p_fci_internal->open = pfnopen;
1038
p_fci_internal->read = pfnread;
1039
p_fci_internal->write = pfnwrite;
1040
p_fci_internal->close = pfnclose;
1041
p_fci_internal->seek = pfnseek;
1042
p_fci_internal->delete = pfndelete;
1043
p_fci_internal->gettemp = pfnfcigtf;
1044
p_fci_internal->ccab = *pccab;
1045
p_fci_internal->pccab = pccab;
1046
p_fci_internal->pv = pv;
1047
p_fci_internal->data.handle = -1;
1048
p_fci_internal->compress = compress_NONE;
1049
1050
list_init( &p_fci_internal->folders_list );
1051
list_init( &p_fci_internal->files_list );
1052
list_init( &p_fci_internal->blocks_list );
1053
1054
memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1055
memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1056
1057
return (HFCI)p_fci_internal;
1058
}
1059
1060
1061
1062
1063
static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1064
BOOL fGetNextCab,
1065
PFNFCIGETNEXTCABINET pfnfcignc,
1066
PFNFCISTATUS pfnfcis)
1067
{
1068
cab_ULONG payload;
1069
cab_ULONG read_result;
1070
struct folder *folder;
1071
1072
if ((!pfnfcignc) || (!pfnfcis)) {
1073
set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1074
return FALSE;
1075
}
1076
1077
if( p_fci_internal->fGetNextCabInVain &&
1078
p_fci_internal->fNextCab ){
1079
/* internal error */
1080
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1081
return FALSE;
1082
}
1083
1084
/* If there was no FCIAddFile or FCIFlushFolder has already been called */
1085
/* this function will return TRUE */
1086
if( p_fci_internal->files_size == 0 ) {
1087
if ( p_fci_internal->pending_data_size != 0 ) {
1088
/* error handling */
1089
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1090
return FALSE;
1091
}
1092
return TRUE;
1093
}
1094
1095
/* FCIFlushFolder has already been called... */
1096
if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1097
return TRUE;
1098
}
1099
1100
/* This can be set already, because it makes only a difference */
1101
/* when the current function exits with return FALSE */
1102
p_fci_internal->fSplitFolder=FALSE;
1103
1104
/* START of COPY */
1105
if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1106
1107
/* reset to get the number of data blocks of this folder which are */
1108
/* actually in this cabinet ( at least partially ) */
1109
p_fci_internal->cDataBlocks=0;
1110
1111
p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1112
sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1113
p_fci_internal->placed_files_size+
1114
p_fci_internal->folders_data_size + p_fci_internal->files_size+
1115
p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1116
p_fci_internal->statusFolderCopied = 0;
1117
1118
/* report status with pfnfcis about copied size of folder */
1119
if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1120
p_fci_internal->statusFolderTotal, /* TODO total folder size */
1121
p_fci_internal->pv) == -1) {
1122
set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1123
return FALSE;
1124
}
1125
1126
/* USE the variable read_result */
1127
read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1128
p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1129
1130
if(p_fci_internal->files_size!=0) {
1131
read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1132
}
1133
1134
/* Check if multiple cabinets have to be created. */
1135
1136
/* Might be too much data for the maximum allowed cabinet size.*/
1137
/* When any further data will be added later, it might not */
1138
/* be possible to flush the cabinet, because there might */
1139
/* not be enough space to store the name of the following */
1140
/* cabinet and name of the corresponding disk. */
1141
/* So take care of this and get the name of the next cabinet */
1142
if( p_fci_internal->fGetNextCabInVain==FALSE &&
1143
p_fci_internal->fNextCab==FALSE &&
1144
(
1145
(
1146
p_fci_internal->ccab.cb < read_result +
1147
p_fci_internal->pending_data_size +
1148
p_fci_internal->files_size +
1149
CB_MAX_CABINET_NAME + /* next cabinet name */
1150
CB_MAX_DISK_NAME /* next disk name */
1151
) || fGetNextCab
1152
)
1153
) {
1154
/* increment cabinet index */
1155
++(p_fci_internal->pccab->iCab);
1156
/* get name of next cabinet */
1157
p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1158
if (!(*pfnfcignc)(p_fci_internal->pccab,
1159
p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1160
p_fci_internal->pv)) {
1161
set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1162
return FALSE;
1163
}
1164
1165
/* Skip a few lines of code. This is caught by the next if. */
1166
p_fci_internal->fGetNextCabInVain=TRUE;
1167
}
1168
1169
/* too much data for cabinet */
1170
if( (p_fci_internal->fGetNextCabInVain ||
1171
p_fci_internal->fNextCab ) &&
1172
(
1173
(
1174
p_fci_internal->ccab.cb < read_result +
1175
p_fci_internal->pending_data_size +
1176
p_fci_internal->files_size +
1177
strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1178
strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1179
) || fGetNextCab
1180
)
1181
) {
1182
p_fci_internal->fGetNextCabInVain=FALSE;
1183
p_fci_internal->fNextCab=TRUE;
1184
1185
/* return FALSE if there is not enough space left*/
1186
/* this should never happen */
1187
if (p_fci_internal->ccab.cb <=
1188
p_fci_internal->files_size +
1189
read_result +
1190
strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1191
strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1192
) {
1193
1194
return FALSE;
1195
}
1196
1197
/* the folder will be split across cabinets */
1198
p_fci_internal->fSplitFolder=TRUE;
1199
1200
} else {
1201
/* this should never happen */
1202
if (p_fci_internal->fNextCab) {
1203
/* internal error */
1204
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1205
return FALSE;
1206
}
1207
}
1208
1209
if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1210
if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1211
if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1212
1213
/* reset CFFolder specific information */
1214
p_fci_internal->cDataBlocks=0;
1215
p_fci_internal->cCompressedBytesInFolder=0;
1216
1217
return TRUE;
1218
}
1219
1220
1221
1222
1223
static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1224
BOOL fGetNextCab,
1225
PFNFCIGETNEXTCABINET pfnfcignc,
1226
PFNFCISTATUS pfnfcis)
1227
{
1228
cab_ULONG read_result=0;
1229
BOOL returntrue=FALSE;
1230
1231
/* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1232
1233
/* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1234
if( p_fci_internal->files_size==0 && fGetNextCab ) {
1235
returntrue=TRUE;
1236
}
1237
1238
if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1239
/* TODO set error */
1240
return FALSE;
1241
}
1242
1243
if(returntrue) return TRUE;
1244
1245
if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1246
(p_fci_internal->folders_size==0 &&
1247
(p_fci_internal->files_size!=0 ||
1248
p_fci_internal->placed_files_size!=0 )
1249
) )
1250
{
1251
/* error */
1252
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1253
return FALSE;
1254
}
1255
1256
/* create the cabinet */
1257
if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1258
1259
p_fci_internal->fPrevCab=TRUE;
1260
/* The sections szPrevCab and szPrevDisk are not being updated, because */
1261
/* MS CABINET.DLL always puts the first cabinet name and disk into them */
1262
1263
if (p_fci_internal->fNextCab) {
1264
p_fci_internal->fNextCab=FALSE;
1265
1266
if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1267
/* THIS CAN NEVER HAPPEN */
1268
/* set error code */
1269
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1270
return FALSE;
1271
}
1272
1273
if( p_fci_internal->fNewPrevious ) {
1274
memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1275
CB_MAX_CABINET_NAME);
1276
memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1277
CB_MAX_DISK_NAME);
1278
p_fci_internal->fNewPrevious=FALSE;
1279
}
1280
p_fci_internal->ccab = *p_fci_internal->pccab;
1281
1282
/* REUSE the variable read_result */
1283
read_result=get_header_size( p_fci_internal );
1284
if(p_fci_internal->files_size!=0) {
1285
read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1286
}
1287
read_result+= p_fci_internal->pending_data_size +
1288
p_fci_internal->files_size + p_fci_internal->folders_data_size +
1289
p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1290
sizeof(CFFOLDER); /* set size of new CFFolder entry */
1291
1292
/* too much data for the maximum size of a cabinet */
1293
if( p_fci_internal->fGetNextCabInVain==FALSE &&
1294
p_fci_internal->ccab.cb < read_result ) {
1295
return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1296
}
1297
1298
/* Might be too much data for the maximum size of a cabinet.*/
1299
/* When any further data will be added later, it might not */
1300
/* be possible to flush the cabinet, because there might */
1301
/* not be enough space to store the name of the following */
1302
/* cabinet and name of the corresponding disk. */
1303
/* So take care of this and get the name of the next cabinet */
1304
if (p_fci_internal->fGetNextCabInVain==FALSE && (
1305
p_fci_internal->ccab.cb < read_result +
1306
CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1307
)) {
1308
/* increment cabinet index */
1309
++(p_fci_internal->pccab->iCab);
1310
/* get name of next cabinet */
1311
p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1312
if (!(*pfnfcignc)(p_fci_internal->pccab,
1313
p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1314
p_fci_internal->pv)) {
1315
/* error handling */
1316
set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1317
return FALSE;
1318
}
1319
/* Skip a few lines of code. This is caught by the next if. */
1320
p_fci_internal->fGetNextCabInVain=TRUE;
1321
}
1322
1323
/* too much data for cabinet */
1324
if (p_fci_internal->fGetNextCabInVain && (
1325
p_fci_internal->ccab.cb < read_result +
1326
strlen(p_fci_internal->ccab.szCab)+1+
1327
strlen(p_fci_internal->ccab.szDisk)+1
1328
)) {
1329
p_fci_internal->fGetNextCabInVain=FALSE;
1330
p_fci_internal->fNextCab=TRUE;
1331
return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1332
}
1333
1334
/* if the FolderThreshold has been reached flush the folder automatically */
1335
if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1336
return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1337
1338
if( p_fci_internal->files_size>0 ) {
1339
if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1340
p_fci_internal->fNewPrevious=TRUE;
1341
}
1342
} else {
1343
p_fci_internal->fNewPrevious=FALSE;
1344
if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1345
/* THIS MAY NEVER HAPPEN */
1346
/* set error structures */
1347
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1348
return FALSE;
1349
}
1350
}
1351
1352
return TRUE;
1353
} /* end of fci_flush_cabinet */
1354
1355
1356
1357
1358
1359
/***********************************************************************
1360
* FCIAddFile (CABINET.11)
1361
*
1362
* FCIAddFile adds a file to the to be created cabinet file
1363
*
1364
* PARAMS
1365
* hfci [I] An HFCI from FCICreate
1366
* pszSourceFile [I] A pointer to a C string which contains the name and
1367
* location of the file which will be added to the cabinet
1368
* pszFileName [I] A pointer to a C string which contains the name under
1369
* which the file will be stored in the cabinet
1370
* fExecute [I] A boolean value which indicates if the file should be
1371
* executed after extraction of self extracting
1372
* executables
1373
* pfnfcignc [I] A pointer to a function which gets information about
1374
* the next cabinet
1375
* pfnfcis [IO] A pointer to a function which will report status
1376
* information about the compression process
1377
* pfnfcioi [I] A pointer to a function which reports file attributes
1378
* and time and date information
1379
* typeCompress [I] Compression type
1380
*
1381
* RETURNS
1382
* On success, returns TRUE
1383
* On failure, returns FALSE
1384
*
1385
* INCLUDES
1386
* fci.h
1387
*
1388
*/
1389
BOOL __cdecl FCIAddFile(
1390
HFCI hfci,
1391
char *pszSourceFile,
1392
char *pszFileName,
1393
BOOL fExecute,
1394
PFNFCIGETNEXTCABINET pfnfcignc,
1395
PFNFCISTATUS pfnfcis,
1396
PFNFCIGETOPENINFO pfnfcigoi,
1397
TCOMP typeCompress)
1398
{
1399
cab_ULONG read_result;
1400
FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1401
1402
if (!p_fci_internal) return FALSE;
1403
1404
if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1405
(!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1406
set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1407
return FALSE;
1408
}
1409
1410
if (typeCompress != p_fci_internal->compression)
1411
{
1412
if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1413
switch (typeCompress)
1414
{
1415
case tcompTYPE_MSZIP:
1416
p_fci_internal->compression = tcompTYPE_MSZIP;
1417
p_fci_internal->compress = compress_MSZIP;
1418
break;
1419
default:
1420
FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1421
/* fall through */
1422
case tcompTYPE_NONE:
1423
p_fci_internal->compression = tcompTYPE_NONE;
1424
p_fci_internal->compress = compress_NONE;
1425
break;
1426
}
1427
}
1428
1429
/* TODO check if pszSourceFile??? */
1430
1431
if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1432
/* internal error */
1433
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1434
return FALSE;
1435
}
1436
1437
if(p_fci_internal->fNextCab) {
1438
/* internal error */
1439
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1440
return FALSE;
1441
}
1442
1443
/* REUSE the variable read_result */
1444
read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1445
1446
read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1447
p_fci_internal->files_size + p_fci_internal->folders_data_size +
1448
p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1449
sizeof(CFFOLDER); /* size of new CFFolder entry */
1450
1451
/* Might be too much data for the maximum size of a cabinet.*/
1452
/* When any further data will be added later, it might not */
1453
/* be possible to flush the cabinet, because there might */
1454
/* not be enough space to store the name of the following */
1455
/* cabinet and name of the corresponding disk. */
1456
/* So take care of this and get the name of the next cabinet */
1457
if( p_fci_internal->fGetNextCabInVain==FALSE &&
1458
p_fci_internal->fNextCab==FALSE &&
1459
( p_fci_internal->ccab.cb < read_result +
1460
CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1461
)
1462
) {
1463
/* increment cabinet index */
1464
++(p_fci_internal->pccab->iCab);
1465
/* get name of next cabinet */
1466
p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1467
if (!(*pfnfcignc)(p_fci_internal->pccab,
1468
p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1469
p_fci_internal->pv)) {
1470
/* error handling */
1471
set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1472
return FALSE;
1473
}
1474
/* Skip a few lines of code. This is caught by the next if. */
1475
p_fci_internal->fGetNextCabInVain=TRUE;
1476
}
1477
1478
if( p_fci_internal->fGetNextCabInVain &&
1479
p_fci_internal->fNextCab
1480
) {
1481
/* THIS CAN NEVER HAPPEN */
1482
/* set error code */
1483
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1484
return FALSE;
1485
}
1486
1487
/* too much data for cabinet */
1488
if( p_fci_internal->fGetNextCabInVain &&
1489
(
1490
p_fci_internal->ccab.cb < read_result +
1491
strlen(p_fci_internal->pccab->szCab)+1+
1492
strlen(p_fci_internal->pccab->szDisk)+1
1493
)) {
1494
p_fci_internal->fGetNextCabInVain=FALSE;
1495
p_fci_internal->fNextCab=TRUE;
1496
if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1497
}
1498
1499
if( p_fci_internal->fNextCab ) {
1500
/* THIS MAY NEVER HAPPEN */
1501
/* set error code */
1502
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1503
return FALSE;
1504
}
1505
1506
if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1507
return FALSE;
1508
1509
/* REUSE the variable read_result */
1510
read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1511
read_result+= p_fci_internal->pending_data_size +
1512
p_fci_internal->files_size + p_fci_internal->folders_data_size +
1513
p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1514
sizeof(CFFOLDER); /* set size of new CFFolder entry */
1515
1516
/* too much data for the maximum size of a cabinet */
1517
/* (ignoring the unflushed data block) */
1518
if( p_fci_internal->fGetNextCabInVain==FALSE &&
1519
p_fci_internal->fNextCab==FALSE && /* this is always the case */
1520
p_fci_internal->ccab.cb < read_result ) {
1521
return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1522
}
1523
1524
/* Might be too much data for the maximum size of a cabinet.*/
1525
/* When any further data will be added later, it might not */
1526
/* be possible to flush the cabinet, because there might */
1527
/* not be enough space to store the name of the following */
1528
/* cabinet and name of the corresponding disk. */
1529
/* So take care of this and get the name of the next cabinet */
1530
/* (ignoring the unflushed data block) */
1531
if( p_fci_internal->fGetNextCabInVain==FALSE &&
1532
p_fci_internal->fNextCab==FALSE &&
1533
( p_fci_internal->ccab.cb < read_result +
1534
CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1535
)
1536
) {
1537
/* increment cabinet index */
1538
++(p_fci_internal->pccab->iCab);
1539
/* get name of next cabinet */
1540
p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1541
if (!(*pfnfcignc)(p_fci_internal->pccab,
1542
p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1543
p_fci_internal->pv)) {
1544
/* error handling */
1545
set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1546
return FALSE;
1547
}
1548
/* Skip a few lines of code. This is caught by the next if. */
1549
p_fci_internal->fGetNextCabInVain=TRUE;
1550
}
1551
1552
if( p_fci_internal->fGetNextCabInVain &&
1553
p_fci_internal->fNextCab
1554
) {
1555
/* THIS CAN NEVER HAPPEN */
1556
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1557
return FALSE;
1558
}
1559
1560
/* too much data for cabinet */
1561
if( (p_fci_internal->fGetNextCabInVain ||
1562
p_fci_internal->fNextCab) && (
1563
p_fci_internal->ccab.cb < read_result +
1564
strlen(p_fci_internal->pccab->szCab)+1+
1565
strlen(p_fci_internal->pccab->szDisk)+1
1566
)) {
1567
1568
p_fci_internal->fGetNextCabInVain=FALSE;
1569
p_fci_internal->fNextCab=TRUE;
1570
return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1571
}
1572
1573
if( p_fci_internal->fNextCab ) {
1574
/* THIS MAY NEVER HAPPEN */
1575
/* set error code */
1576
set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1577
return FALSE;
1578
}
1579
1580
/* if the FolderThreshold has been reached flush the folder automatically */
1581
if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1582
return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1583
1584
return TRUE;
1585
} /* end of FCIAddFile */
1586
1587
1588
1589
1590
1591
/***********************************************************************
1592
* FCIFlushFolder (CABINET.12)
1593
*
1594
* FCIFlushFolder completes the CFFolder structure under construction.
1595
*
1596
* All further data which is added by FCIAddFile will be associated to
1597
* the next CFFolder structure.
1598
*
1599
* FCIFlushFolder will be called by FCIAddFile automatically if the
1600
* threshold (stored in the member cbFolderThresh of the CCAB structure
1601
* pccab passed to FCICreate) is exceeded.
1602
*
1603
* FCIFlushFolder will be called by FCIFlushFolder automatically before
1604
* any data will be written into the cabinet file.
1605
*
1606
* PARAMS
1607
* hfci [I] An HFCI from FCICreate
1608
* pfnfcignc [I] A pointer to a function which gets information about
1609
* the next cabinet
1610
* pfnfcis [IO] A pointer to a function which will report status
1611
* information about the compression process
1612
*
1613
* RETURNS
1614
* On success, returns TRUE
1615
* On failure, returns FALSE
1616
*
1617
* INCLUDES
1618
* fci.h
1619
*
1620
*/
1621
BOOL __cdecl FCIFlushFolder(
1622
HFCI hfci,
1623
PFNFCIGETNEXTCABINET pfnfcignc,
1624
PFNFCISTATUS pfnfcis)
1625
{
1626
FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1627
1628
if (!p_fci_internal) return FALSE;
1629
return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1630
}
1631
1632
1633
1634
/***********************************************************************
1635
* FCIFlushCabinet (CABINET.13)
1636
*
1637
* FCIFlushCabinet stores the data which has been added by FCIAddFile
1638
* into the cabinet file. If the maximum cabinet size (stored in the
1639
* member cb of the CCAB structure pccab passed to FCICreate) has been
1640
* exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1641
* The remaining data still has to be flushed manually by calling
1642
* FCIFlushCabinet.
1643
*
1644
* After FCIFlushCabinet has been called (manually) FCIAddFile must
1645
* NOT be called again. Then hfci has to be released by FCIDestroy.
1646
*
1647
* PARAMS
1648
* hfci [I] An HFCI from FCICreate
1649
* fGetNextCab [I] Whether you want to add additional files to a
1650
* cabinet set (TRUE) or whether you want to
1651
* finalize it (FALSE)
1652
* pfnfcignc [I] A pointer to a function which gets information about
1653
* the next cabinet
1654
* pfnfcis [IO] A pointer to a function which will report status
1655
* information about the compression process
1656
*
1657
* RETURNS
1658
* On success, returns TRUE
1659
* On failure, returns FALSE
1660
*
1661
* INCLUDES
1662
* fci.h
1663
*
1664
*/
1665
BOOL __cdecl FCIFlushCabinet(
1666
HFCI hfci,
1667
BOOL fGetNextCab,
1668
PFNFCIGETNEXTCABINET pfnfcignc,
1669
PFNFCISTATUS pfnfcis)
1670
{
1671
FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1672
1673
if (!p_fci_internal) return FALSE;
1674
1675
if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1676
1677
while( p_fci_internal->files_size>0 ||
1678
p_fci_internal->placed_files_size>0 ) {
1679
if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1680
}
1681
1682
return TRUE;
1683
}
1684
1685
1686
/***********************************************************************
1687
* FCIDestroy (CABINET.14)
1688
*
1689
* Frees a handle created by FCICreate.
1690
* Only reason for failure would be an invalid handle.
1691
*
1692
* PARAMS
1693
* hfci [I] The HFCI to free
1694
*
1695
* RETURNS
1696
* TRUE for success
1697
* FALSE for failure
1698
*/
1699
BOOL __cdecl FCIDestroy(HFCI hfci)
1700
{
1701
struct folder *folder, *folder_next;
1702
struct file *file, *file_next;
1703
struct data_block *block, *block_next;
1704
FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1705
1706
if (!p_fci_internal) return FALSE;
1707
1708
/* before hfci can be removed all temporary files must be closed */
1709
/* and deleted */
1710
p_fci_internal->magic = 0;
1711
1712
LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1713
{
1714
free_folder( p_fci_internal, folder );
1715
}
1716
LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1717
{
1718
free_file( p_fci_internal, file );
1719
}
1720
LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1721
{
1722
free_data_block( p_fci_internal, block );
1723
}
1724
1725
close_temp_file( p_fci_internal, &p_fci_internal->data );
1726
1727
/* hfci can now be removed */
1728
p_fci_internal->free(hfci);
1729
return TRUE;
1730
}
1731
1732