char name[1];
};
+struct data_block
+{
+ struct list entry;
+ cab_UWORD compressed;
+ cab_UWORD uncompressed;
+};
+
typedef struct
{
unsigned int magic;
cab_ULONG estimatedCabinetSize;
struct list folders_list;
struct list files_list;
+ struct list blocks_list;
cab_ULONG folders_size;
cab_ULONG files_size;
cab_ULONG placed_files_size;
fci->free( folder );
}
+static struct data_block *add_data_block( FCI_Int *fci, cab_UWORD compressed, cab_UWORD uncompressed )
+{
+ struct data_block *block = fci->alloc( sizeof(*block) );
+
+ if (!block)
+ {
+ set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
+ return NULL;
+ }
+ block->compressed = compressed;
+ block->uncompressed = uncompressed;
+ list_add_tail( &fci->blocks_list, &block->entry );
+ fci->data2.size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + compressed;
+ fci->cDataBlocks++;
+ return block;
+}
+
+static void free_data_block( FCI_Int *fci, struct data_block *block )
+{
+ list_remove( &block->entry );
+ fci->free( block );
+}
+
+/* reset state for the next cabinet file once the current one has been flushed */
+static void reset_cabinet( FCI_Int *fci )
+{
+ struct folder *folder, *folder_next;
+ struct data_block *block, *block_next;
+
+ LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
+ free_folder( fci, folder );
+
+ LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &fci->blocks_list, struct data_block, entry )
+ free_data_block( fci, block );
+
+ close_temp_file( fci, &fci->data2 );
+
+ fci->cFolders = 0;
+ fci->cFiles = 0;
+ fci->folders_size = 0;
+ fci->placed_files_size = 0;
+ fci->data2.size = 0;
+}
+
+static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
+{
+ cab_ULONG csum;
+ cab_ULONG ul;
+ int cUlong;
+ const BYTE *pb;
+
+ csum = seed;
+ cUlong = cb / 4;
+ pb = pv;
+
+ while (cUlong-- > 0) {
+ ul = *pb++;
+ ul |= (((cab_ULONG)(*pb++)) << 8);
+ ul |= (((cab_ULONG)(*pb++)) << 16);
+ ul |= (((cab_ULONG)(*pb++)) << 24);
+ csum ^= ul;
+ }
+
+ ul = 0;
+ switch (cb % 4) {
+ case 3:
+ ul |= (((ULONG)(*pb++)) << 16);
+ case 2:
+ ul |= (((ULONG)(*pb++)) << 8);
+ case 1:
+ ul |= *pb;
+ default:
+ break;
+ }
+ csum ^= ul;
+
+ return csum;
+}
+
/* write all folders to disk and remove them from the list */
static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
{
- struct folder *folder, *next;
- struct file *file;
+ struct folder *folder;
int err;
BOOL ret = TRUE;
- CFFILE *cffile;
CFFOLDER *cffolder;
- cab_ULONG file_size, folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
+ cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
if (!(cffolder = fci->alloc( folder_size )))
{
}
memset( cffolder, 0, folder_size );
- if (!(cffile = fci->alloc( sizeof(CFFILE) + CB_MAX_FILENAME )))
- {
- fci->free( cffolder );
- set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
- return FALSE;
- }
-
/* write the folders */
LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
{
}
}
- /* write all the folders files */
+ fci->free( cffolder );
+ return ret;
+}
+
+/* write all the files to the cabinet file */
+static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
+{
+ cab_ULONG file_size;
+ struct folder *folder;
+ struct file *file;
+ int err;
+ BOOL ret = TRUE;
+ CFFILE *cffile;
+
+ if (!(cffile = fci->alloc( sizeof(CFFILE) + CB_MAX_FILENAME )))
+ {
+ set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+
LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
{
LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
}
}
- /* cleanup */
- LIST_FOR_EACH_ENTRY_SAFE( folder, next, &fci->folders_list, struct folder, entry )
- {
- free_folder( fci, folder );
- }
- fci->free( cffolder );
fci->free( cffile );
return ret;
}
+/* write all data blocks to the cabinet file */
+static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
+{
+ struct data_block *block;
+ int err, len;
+ CFDATA *cfdata;
+ void *data;
+ cab_UWORD header_size;
+
+ if (!fci->data_out) return TRUE;
+
+ if (fci->seek( fci->data2.handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
+ {
+ set_error( fci, FCIERR_CAB_FILE, err );
+ return FALSE;
+ }
+
+ header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
+ cfdata = (CFDATA *)fci->data_out;
+ memset( cfdata, 0, header_size );
+ data = (char *)cfdata + header_size;
+
+ LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
+ {
+ len = fci->read( fci->data2.handle, data, block->compressed, &err, fci->pv );
+ if (len != block->compressed) return FALSE;
+
+ cfdata->cbData = fci_endian_uword( block->compressed );
+ cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
+ cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
+ header_size - FIELD_OFFSET( CFDATA, cbData ),
+ fci_get_checksum( data, len, 0 )));
+
+ fci->statusFolderCopied += len;
+ len += header_size;
+ if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
+ {
+ set_error( fci, FCIERR_CAB_FILE, err );
+ return FALSE;
+ }
+ if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
+ {
+ set_error( fci, FCIERR_USER_ABORT, 0 );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
/* write the cabinet file to disk */
-static INT_PTR write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
+static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
{
char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
int err;
+ char *ptr;
INT_PTR handle;
+ CFHEADER *cfheader;
cab_UWORD flags = 0;
cab_ULONG header_size = get_header_size( fci );
- CFHEADER *cfheader;
- char *ptr;
+ cab_ULONG total_size = header_size + fci->folders_size + fci->placed_files_size + fci->data2.size;
if (!(cfheader = fci->alloc( header_size )))
{
set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
- return -1;
+ return FALSE;
}
memset( cfheader, 0, header_size );
flags |= cfheadRESERVE_PRESENT;
memcpy( cfheader->signature, "!CAB", 4 );
- cfheader->cbCabinet = fci_endian_ulong( header_size + fci->folders_size +
- fci->placed_files_size + fci->data2.size );
+ cfheader->cbCabinet = fci_endian_ulong( total_size );
cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
cfheader->versionMinor = 3;
cfheader->versionMajor = 1;
{
set_error( fci, FCIERR_CAB_FILE, err );
fci->free( cfheader );
- return -1;
+ return FALSE;
}
if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
/* add size of header size of all CFFOLDERs and size of all CFFILEs */
header_size += fci->placed_files_size + fci->folders_size;
if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
+ if (!write_files( fci, handle, status_callback )) goto failed;
+ if (!write_data_blocks( fci, handle, status_callback )) goto failed;
- /* FIXME: write data blocks here */
+ /* update the signature */
+ if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
+ {
+ set_error( fci, FCIERR_CAB_FILE, err );
+ goto failed;
+ }
+ memcpy( cfheader->signature, "MSCF", 4 );
+ if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
+ {
+ set_error( fci, FCIERR_CAB_FILE, err );
+ goto failed;
+ }
+ fci->close( handle, &err, fci->pv );
fci->free( cfheader );
- return handle;
+
+ reset_cabinet( fci );
+ status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
+ return TRUE;
failed:
fci->close( handle, &err, fci->pv );
fci->delete( filename, &err, fci->pv );
fci->free( cfheader );
- return -1;
+ return FALSE;
}
/* add all pending files to folder */
list_init( &p_fci_internal->folders_list );
list_init( &p_fci_internal->files_list );
+ list_init( &p_fci_internal->blocks_list );
memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
-static cab_ULONG fci_get_checksum(const void *pv, UINT cb, CHECKSUM seed)
-{
- cab_ULONG csum;
- cab_ULONG ul;
- int cUlong;
- const BYTE *pb;
-
- csum = seed;
- cUlong = cb / 4;
- pb = pv;
-
- while (cUlong-- > 0) {
- ul = *pb++;
- ul |= (((cab_ULONG)(*pb++)) << 8);
- ul |= (((cab_ULONG)(*pb++)) << 16);
- ul |= (((cab_ULONG)(*pb++)) << 24);
-
- csum ^= ul;
- }
-
- ul = 0;
- switch (cb % 4) {
- case 3:
- ul |= (((ULONG)(*pb++)) << 16);
- case 2:
- ul |= (((ULONG)(*pb++)) << 8);
- case 1:
- ul |= *pb;
- default:
- break;
- }
- csum ^= ul;
-
- return csum;
-} /* end of fci_get_checksum */
-
-
-
static BOOL fci_flushfolder_copy_cfdata(FCI_Int *p_fci_internal, char* buffer, UINT cbReserveCFData,
PFNFCISTATUS pfnfcis, int* err, struct temp_file *data1new,
cab_ULONG* payload)
{
+ struct data_block *block;
cab_ULONG read_result;
CFDATA* pcfdata=(CFDATA*)buffer;
BOOL split_block=FALSE;
return FALSE;
}
- /* set little endian */
- pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
- pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
-
- /* get checksum and write to cfdata.csum */
- pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
- sizeof(CFDATA)+cbReserveCFData -
- sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
- pcfdata->cbData, 0 ) );
-
- /* set little endian */
- pcfdata->csum=fci_endian_ulong(pcfdata->csum);
-
- /* write cfdata with checksum to p_fci_internal->data2.handle */
- if( p_fci_internal->write( p_fci_internal->data2.handle, /* file handle */
- buffer, /* memory buffer */
- sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
- err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
- set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
- return FALSE;
- }
- /* TODO error handling of err */
-
- p_fci_internal->data2.size += sizeof(CFDATA)+cbReserveCFData;
-
- /* reset little endian */
- pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
- pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
- pcfdata->csum=fci_endian_ulong(pcfdata->csum);
+ if (!(block = add_data_block( p_fci_internal, pcfdata->cbData, pcfdata->cbUncomp ))) return FALSE;
/* write compressed data into p_fci_internal->data2.handle */
if( p_fci_internal->write( p_fci_internal->data2.handle, /* file handle */
}
/* TODO error handling of err */
- p_fci_internal->data2.size += pcfdata->cbData;
- ++(p_fci_internal->cDataBlocks);
p_fci_internal->statusFolderCopied += pcfdata->cbData;
(*payload)+=pcfdata->cbUncomp;
/* if cabinet size too large and data has been split */
PFNFCIGETNEXTCABINET pfnfcignc,
PFNFCISTATUS pfnfcis)
{
- int err;
- cab_ULONG total_size, read_result=0;
- int handleCABINET; /* file handle for cabinet */
+ cab_ULONG read_result=0;
BOOL returntrue=FALSE;
- char signature[] = "MSCF";
/* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
return FALSE;
}
- total_size = /* size of the cabinet file in bytes */
- get_header_size( p_fci_internal ) +
- p_fci_internal->folders_size +
- p_fci_internal->placed_files_size +
- p_fci_internal->data2.size;
- if (total_size > p_fci_internal->ccab.cb)
- {
- set_error( p_fci_internal, FCIERR_NONE, ERROR_MORE_DATA );
- return FALSE;
- }
-
/* create the cabinet */
- handleCABINET = write_cabinet( p_fci_internal, pfnfcis );
- if (handleCABINET == -1) return FALSE;
-
- /* set seek of p_fci_internal->data2.handle to 0 */
- if( p_fci_internal->seek(p_fci_internal->data2.handle,
- 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
- /* wrong return value */
- set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
- return FALSE;
- }
- /* TODO error handling of err */
-
- /* reset the number of folders for the next cabinet */
- p_fci_internal->cFolders=0;
- /* reset the number of files for the next cabinet */
- p_fci_internal->cFiles=0;
-
- /* while not all CFDATA structures have been copied to the cabinet do */
- if (p_fci_internal->data_out) while(!FALSE) {
- /* REUSE the variable read_result AGAIN */
- /* REUSE the buffer p_fci_internal->data_out AGAIN */
- /* read a block from p_fci_internal->data2.handle */
- read_result = p_fci_internal->read( p_fci_internal->data2.handle /* handle */,
- p_fci_internal->data_out, /* memory buffer */
- CB_MAX_CHUNK, /* number of bytes to copy */
- &err, p_fci_internal->pv);
- if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */
- /* TODO error handling of err */
-
- /* write the block to the cabinet file */
- if( p_fci_internal->write( handleCABINET, /* file handle */
- p_fci_internal->data_out, /* memory buffer */
- read_result, /* number of bytes to copy */
- &err, p_fci_internal->pv) != read_result ) {
- /* write error */
- set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
- return FALSE;
- }
- /* TODO error handling of err */
-
- p_fci_internal->statusFolderCopied += read_result;
- /* report status with pfnfcis about copied size of folder */
- if( (*pfnfcis)(statusFolder,
- p_fci_internal->statusFolderCopied, /* length of copied blocks */
- p_fci_internal->statusFolderTotal, /* total size of folder */
- p_fci_internal->pv) == -1) {
- /* set error code and abort */
- set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
- return FALSE;
- }
- } /* END OF while */
-
- /* set seek of the cabinet file to 0 */
- if( p_fci_internal->seek( handleCABINET,
- 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
- /* wrong return value */
- set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
- return FALSE;
- }
- /* TODO error handling of err */
-
- /* write the signature "MSCF" into the cabinet file */
- if( p_fci_internal->write( handleCABINET, /* file handle */
- signature, /* memory buffer */
- 4, /* number of bytes to copy */
- &err, p_fci_internal->pv) != 4 ) {
- /* wrtie error */
- set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
- return FALSE;
- }
- /* TODO error handling of err */
-
- /* close the cabinet file */
- p_fci_internal->close(handleCABINET,&err,p_fci_internal->pv);
- /* TODO error handling of err */
-
- close_temp_file( p_fci_internal, &p_fci_internal->data2 );
-
- p_fci_internal->data2.size = 0;
- p_fci_internal->placed_files_size = 0;
- p_fci_internal->folders_size = 0;
+ if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
if (!create_temp_file( p_fci_internal, &p_fci_internal->data2 )) return FALSE;
- /* report status with pfnfcis about copied size of folder */
- (*pfnfcis)(statusCabinet,
- p_fci_internal->estimatedCabinetSize, /* estimated cabinet file size */
- total_size /* real cabinet file size */, p_fci_internal->pv);
-
p_fci_internal->fPrevCab=TRUE;
/* The sections szPrevCab and szPrevDisk are not being updated, because */
/* MS CABINET.DLL always puts the first cabinet name and disk into them */
{
struct folder *folder, *folder_next;
struct file *file, *file_next;
+ struct data_block *block, *block_next;
FCI_Int *p_fci_internal = get_fci_ptr( hfci );
if (!p_fci_internal) return FALSE;
{
free_file( p_fci_internal, file );
}
+ LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
+ {
+ free_data_block( p_fci_internal, block );
+ }
close_temp_file( p_fci_internal, &p_fci_internal->data1 );
close_temp_file( p_fci_internal, &p_fci_internal->data2 );