2003-08-24 10:36:07 +00:00
/*
* COPYRIGHT : See COPYING in the top level directory
* PROJECT : ReactOS cabinet manager
2015-09-28 17:31:37 +00:00
* FILE : tools / cabman / cabinet . cxx
2003-08-24 10:36:07 +00:00
* PURPOSE : Cabinet routines
* PROGRAMMERS : Casper S . Hornstrup ( chorns @ users . sourceforge . net )
2007-05-04 22:21:55 +00:00
* Colin Finck < mail @ colinfinck . de >
2003-08-24 10:36:07 +00:00
* NOTES : Define CAB_READ_ONLY for read only version
* REVISIONS :
* CSH 21 / 03 - 2001 Created
* CSH 15 / 08 - 2003 Made it portable
2007-05-27 10:26:43 +00:00
* CF 04 / 05 - 2007 Made it compatible with 64 - bit operating systems
2003-08-24 10:36:07 +00:00
* TODO :
* - Checksum of datablocks should be calculated
* - EXTRACT . EXE complains if a disk is created manually
* - Folders that are created manually and span disks will result in a damaged cabinet
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2011-06-26 22:17:01 +00:00
# if !defined(_WIN32)
2008-02-04 22:48:42 +00:00
# include <dirent.h>
2005-11-02 16:13:00 +00:00
# include <sys / stat.h>
2010-08-26 18:33:46 +00:00
# include <sys / types.h>
# endif
2003-08-24 10:36:07 +00:00
# include "cabinet.h"
2020-08-30 18:38:43 +00:00
# include "CCFDATAStorage.h"
2003-08-24 10:36:07 +00:00
# include "raw.h"
# include "mszip.h"
# ifndef CAB_READ_ONLY
#if 0
2009-06-17 12:44:05 +00:00
# if DBG
2003-08-24 10:36:07 +00:00
2007-08-18 13:08:58 +00:00
void DumpBuffer ( void * Buffer , ULONG Size )
2003-08-24 10:36:07 +00:00
{
2018-01-26 15:44:14 +00:00
HANDLE FileHandle ;
2008-02-02 11:57:16 +00:00
ULONG BytesWritten ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* Create file, overwrite if it already exists */
FileHandle = CreateFile ( " dump.bin " , // Create this file
GENERIC_WRITE , // Open for writing
0 , // No sharing
NULL , // No security
CREATE_ALWAYS , // Create or overwrite
FILE_ATTRIBUTE_NORMAL , // Normal file
NULL ) ; // No attribute template
if ( FileHandle = = INVALID_HANDLE_VALUE )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " ERROR OPENING '%u'. \n " , ( UINT ) GetLastError ( ) ) ) ;
2008-02-02 11:57:16 +00:00
return ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ! WriteFile ( FileHandle , Buffer , Size , & BytesWritten , NULL ) )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " ERROR WRITING '%u'. \n " , ( UINT ) GetLastError ( ) ) ) ;
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CloseFile ( FileHandle ) ;
2003-08-24 10:36:07 +00:00
}
# endif /* DBG */
# endif
# endif /* CAB_READ_ONLY */
/* CCabinet */
CCabinet : : CCabinet ( )
/*
* FUNCTION : Default constructor
*/
{
2008-02-02 11:57:16 +00:00
* CabinetName = ' \0 ' ;
* CabinetPrev = ' \0 ' ;
* DiskPrev = ' \0 ' ;
* CabinetNext = ' \0 ' ;
* DiskNext = ' \0 ' ;
2005-03-05 05:13:38 +00:00
2008-02-02 11:57:16 +00:00
FileOpen = false ;
CabinetReservedFileBuffer = NULL ;
CabinetReservedFileSize = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 14:32:44 +00:00
Codec = NULL ;
CodecId = - 1 ;
CodecSelected = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
OutputBuffer = NULL ;
InputBuffer = NULL ;
MaxDiskSize = 0 ;
BlockIsSplit = false ;
ScratchFile = NULL ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
FolderUncompSize = 0 ;
BytesLeftInBlock = 0 ;
ReuseBlock = false ;
CurrentDataNode = NULL ;
2003-08-24 10:36:07 +00:00
}
CCabinet : : ~ CCabinet ( )
/*
* FUNCTION : Default destructor
*/
{
2008-02-02 11:57:16 +00:00
if ( CabinetReservedFileBuffer ! = NULL )
{
2018-01-26 15:44:14 +00:00
free ( CabinetReservedFileBuffer ) ;
2008-02-02 11:57:16 +00:00
CabinetReservedFileBuffer = NULL ;
CabinetReservedFileSize = 0 ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( CodecSelected )
delete Codec ;
2003-08-24 10:36:07 +00:00
}
bool CCabinet : : IsSeparator ( char Char )
/*
* FUNCTION : Determines if a character is a separator
* ARGUMENTS :
* Char = Character to check
* RETURNS :
2008-02-02 14:32:44 +00:00
* Whether it is a separator
2003-08-24 10:36:07 +00:00
*/
{
2008-02-02 11:57:16 +00:00
if ( ( Char = = ' \\ ' ) | | ( Char = = ' / ' ) )
return true ;
else
return false ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
void CCabinet : : ConvertPath ( std : : string & Path )
2003-08-24 10:36:07 +00:00
/*
2008-02-05 15:31:12 +00:00
* FUNCTION : Replaces \ or / with the one used by the host environment
2003-08-24 10:36:07 +00:00
* ARGUMENTS :
* Path = Pointer to string with pathname
2008-02-05 15:31:12 +00:00
* Allocate = Specifies whether to allocate memory for the new
2003-08-24 10:36:07 +00:00
* string or to change the existing buffer
* RETURNS :
* Pointer to new path
*/
{
2020-08-30 13:31:04 +00:00
for ( size_t i = 0 ; i < Path . size ( ) ; + + i )
2008-02-02 11:57:16 +00:00
{
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 11:57:16 +00:00
if ( Path [ i ] = = ' / ' )
2020-08-30 13:31:04 +00:00
Path [ i ] = ' \\ ' ;
2003-08-24 10:36:07 +00:00
# else
2008-02-02 11:57:16 +00:00
if ( Path [ i ] = = ' \\ ' )
2020-08-30 13:31:04 +00:00
Path [ i ] = ' / ' ;
2003-08-24 10:36:07 +00:00
# endif
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
}
2020-09-12 14:21:34 +00:00
std : : string CCabinet : : GetFileName ( const std : : string & Path )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns a pointer to file name
* ARGUMENTS :
* Path = Pointer to string with pathname
* RETURNS :
* Pointer to filename
*/
{
2008-02-02 11:57:16 +00:00
ULONG i , j ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
j = i = ( Path [ 0 ] ? ( Path [ 1 ] = = ' : ' ? 2 : 0 ) : 0 ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
while ( Path [ i + + ] )
if ( IsSeparator ( Path [ i - 1 ] ) )
j = i ;
2007-05-04 22:21:55 +00:00
2020-09-12 14:21:34 +00:00
return Path . c_str ( ) + j ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
void CCabinet : : NormalizePath ( std : : string & Path )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Normalizes a path
* ARGUMENTS :
2020-08-30 13:31:04 +00:00
* Path = string with pathname
2003-08-24 10:36:07 +00:00
*/
{
2020-08-30 13:31:04 +00:00
if ( Path . length ( ) > 0 )
2008-02-02 11:57:16 +00:00
{
2020-08-30 13:31:04 +00:00
if ( ! IsSeparator ( Path [ Path . length ( ) - 1 ] ) )
Path + = DIR_SEPARATOR_CHAR ;
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
}
char * CCabinet : : GetCabinetName ( )
/*
* FUNCTION : Returns pointer to cabinet file name
* RETURNS :
* Pointer to string with name of cabinet
*/
{
2008-02-02 11:57:16 +00:00
return CabinetName ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
void CCabinet : : SetCabinetName ( const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Sets cabinet file name
* ARGUMENTS :
* FileName = Pointer to string with name of cabinet
*/
{
2008-02-02 11:57:16 +00:00
strcpy ( CabinetName , FileName ) ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
void CCabinet : : SetDestinationPath ( const char * DestinationPath )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Sets destination path
* ARGUMENTS :
* DestinationPath = Pointer to string with name of destination path
*/
{
2020-08-30 13:31:04 +00:00
DestPath = DestinationPath ;
ConvertPath ( DestPath ) ;
NormalizePath ( DestPath ) ;
2003-08-24 10:36:07 +00:00
}
2020-09-12 14:21:34 +00:00
ULONG CCabinet : : AddSearchCriteria ( const std : : string & SearchCriteria , const std : : string & TargetFolder )
2008-02-04 22:48:42 +00:00
/*
* FUNCTION : Adds a criteria to the search criteria list
* ARGUMENTS :
* SearchCriteria = String with the search criteria to add
* RETURNS :
* Status of operation
*/
{
PSEARCH_CRITERIA Criteria ;
// Add the criteria to the list of search criteria
2020-08-30 13:31:04 +00:00
Criteria = new SEARCH_CRITERIA ;
2008-02-04 22:48:42 +00:00
if ( ! Criteria )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2020-09-03 16:12:25 +00:00
CriteriaList . push_back ( Criteria ) ;
2008-02-04 22:48:42 +00:00
// Set the actual criteria string
2020-08-30 13:31:04 +00:00
Criteria - > Search = SearchCriteria ;
2020-09-12 14:21:34 +00:00
Criteria - > TargetFolder = TargetFolder ;
2008-02-04 22:48:42 +00:00
return CAB_STATUS_SUCCESS ;
}
void CCabinet : : DestroySearchCriteria ( )
/*
* FUNCTION : Destroys the list with the search criteria
*/
{
2020-09-03 16:12:25 +00:00
for ( PSEARCH_CRITERIA Criteria : CriteriaList )
2008-02-04 22:48:42 +00:00
{
2020-08-30 13:31:04 +00:00
delete Criteria ;
2008-02-04 22:48:42 +00:00
}
2020-09-03 16:12:25 +00:00
CriteriaList . clear ( ) ;
2008-02-04 22:48:42 +00:00
}
bool CCabinet : : HasSearchCriteria ( )
/*
* FUNCTION : Returns whether we have search criteria
* RETURNS :
* Whether we have search criteria or not .
*/
{
2020-09-03 16:12:25 +00:00
return ! CriteriaList . empty ( ) ;
2008-02-04 22:48:42 +00:00
}
2020-09-12 14:21:34 +00:00
std : : string CCabinet : : CreateCabFilename ( PCFFILE_NODE Node )
{
std : : string fname = GetFileName ( Node - > FileName ) ;
if ( ! Node - > TargetFolder . empty ( ) )
{
fname = Node - > TargetFolder + fname ;
}
return fname ;
}
2020-08-30 13:31:04 +00:00
bool CCabinet : : SetCompressionCodec ( const char * CodecName )
2008-02-02 14:32:44 +00:00
/*
* FUNCTION : Selects the codec to use for compression
* ARGUMENTS :
* CodecName = Pointer to a string with the name of the codec
*/
{
if ( ! strcasecmp ( CodecName , " raw " ) )
SelectCodec ( CAB_CODEC_RAW ) ;
else if ( ! strcasecmp ( CodecName , " mszip " ) )
SelectCodec ( CAB_CODEC_MSZIP ) ;
else
{
2013-09-29 14:48:37 +00:00
printf ( " ERROR: Invalid codec specified! \n " ) ;
2008-02-02 14:32:44 +00:00
return false ;
}
return true ;
}
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
const char * CCabinet : : GetDestinationPath ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns destination path
* RETURNS :
* Pointer to string with name of destination path
*/
{
2020-08-30 13:31:04 +00:00
return DestPath . c_str ( ) ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
bool CCabinet : : SetCabinetReservedFile ( const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Sets cabinet reserved file
* ARGUMENTS :
* FileName = Pointer to string with name of cabinet reserved file
*/
{
2018-01-26 15:44:14 +00:00
FILE * FileHandle ;
2008-02-02 11:57:16 +00:00
ULONG BytesRead ;
2020-08-30 13:31:04 +00:00
std : : string ConvertedFileName ;
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
ConvertedFileName = FileName ;
ConvertPath ( ConvertedFileName ) ;
2018-01-26 15:44:14 +00:00
2020-08-30 13:31:04 +00:00
FileHandle = fopen ( ConvertedFileName . c_str ( ) , " rb " ) ;
2008-02-02 11:57:16 +00:00
if ( FileHandle = = NULL )
{
DPRINT ( MID_TRACE , ( " Cannot open cabinet reserved file. \n " ) ) ;
return false ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CabinetReservedFileSize = GetSizeOfFile ( FileHandle ) ;
if ( CabinetReservedFileSize = = ( ULONG ) - 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot read from cabinet reserved file. \n " ) ) ;
2019-11-27 00:49:08 +00:00
fclose ( FileHandle ) ;
2008-02-02 11:57:16 +00:00
return false ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( CabinetReservedFileSize = = 0 )
{
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2008-02-02 11:57:16 +00:00
return false ;
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
CabinetReservedFileBuffer = malloc ( CabinetReservedFileSize ) ;
2008-02-02 11:57:16 +00:00
if ( ! CabinetReservedFileBuffer )
{
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2008-02-02 11:57:16 +00:00
return false ;
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
BytesRead = fread ( CabinetReservedFileBuffer , 1 , CabinetReservedFileSize , FileHandle ) ;
if ( BytesRead ! = CabinetReservedFileSize )
2008-02-02 11:57:16 +00:00
{
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2008-02-02 11:57:16 +00:00
return false ;
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
CabinetReservedFile = FileName ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return true ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : GetCurrentDiskNumber ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns current disk number
* RETURNS :
* Current disk number
*/
{
2008-02-02 11:57:16 +00:00
return CurrentDiskNumber ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : Open ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Opens a cabinet file
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
ULONG Index ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ! FileOpen )
{
ULONG BytesRead ;
ULONG Size ;
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
OutputBuffer = malloc ( CAB_BLOCKSIZE + 12 ) ; // This should be enough
2008-02-02 11:57:16 +00:00
if ( ! OutputBuffer )
return CAB_STATUS_NOMEMORY ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
FileHandle = fopen ( CabinetName , " rb " ) ;
if ( FileHandle = = NULL )
{
DPRINT ( MID_TRACE , ( " Cannot open file. \n " ) ) ;
return CAB_STATUS_CANNOT_OPEN ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
FileOpen = true ;
/* Load CAB header */
if ( ( Status = ReadBlock ( & CABHeader , sizeof ( CFHEADER ) , & BytesRead ) )
! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
/* Check header */
if ( ( BytesRead ! = sizeof ( CFHEADER ) ) | |
( CABHeader . Signature ! = CAB_SIGNATURE ) | |
( CABHeader . Version ! = CAB_VERSION ) | |
( CABHeader . FolderCount = = 0 ) | |
( CABHeader . FileCount = = 0 ) | |
( CABHeader . FileTableOffset < sizeof ( CFHEADER ) ) )
{
CloseCabinet ( ) ;
DPRINT ( MID_TRACE , ( " File has invalid header. \n " ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
Size = 0 ;
/* Read/skip any reserved bytes */
if ( CABHeader . Flags & CAB_FLAG_RESERVE )
{
if ( ( Status = ReadBlock ( & Size , sizeof ( ULONG ) , & BytesRead ) )
! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
CabinetReserved = Size & 0xFFFF ;
FolderReserved = ( Size > > 16 ) & 0xFF ;
DataReserved = ( Size > > 24 ) & 0xFF ;
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
if ( fseek ( FileHandle , CabinetReserved , SEEK_CUR ) ! = 0 )
2008-02-02 11:57:16 +00:00
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
return CAB_STATUS_FAILURE ;
}
}
if ( ( CABHeader . Flags & CAB_FLAG_HASPREV ) > 0 )
{
/* Read name of previous cabinet */
Status = ReadString ( CabinetPrev , 256 ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
/* Read label of previous disk */
Status = ReadString ( DiskPrev , 256 ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
else
{
strcpy ( CabinetPrev , " " ) ;
strcpy ( DiskPrev , " " ) ;
}
if ( ( CABHeader . Flags & CAB_FLAG_HASNEXT ) > 0 )
{
/* Read name of next cabinet */
Status = ReadString ( CabinetNext , 256 ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
/* Read label of next disk */
Status = ReadString ( DiskNext , 256 ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
else
{
strcpy ( CabinetNext , " " ) ;
strcpy ( DiskNext , " " ) ;
}
/* Read all folders */
for ( Index = 0 ; Index < CABHeader . FolderCount ; Index + + )
{
2020-09-03 16:12:25 +00:00
PCFFOLDER_NODE FolderNode = NewFolderNode ( ) ;
2008-02-02 11:57:16 +00:00
if ( ! FolderNode )
{
DPRINT ( MIN_TRACE , ( " Insufficient resources. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
if ( Index = = 0 )
FolderNode - > UncompOffset = FolderUncompSize ;
FolderNode - > Index = Index ;
if ( ( Status = ReadBlock ( & FolderNode - > Folder ,
sizeof ( CFFOLDER ) , & BytesRead ) ) ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
}
/* Read file entries */
Status = ReadFileTable ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " ReadFileTable() failed (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return Status ;
}
/* Read data blocks for all folders */
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE Node : FolderList )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
Status = ReadDataBlocks ( Node ) ;
2008-02-02 11:57:16 +00:00
if ( Status ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " ReadDataBlocks() failed (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return Status ;
}
}
}
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : Close ( )
/*
* FUNCTION : Closes the cabinet file
*/
{
2008-02-02 11:57:16 +00:00
if ( FileOpen )
{
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2008-02-02 11:57:16 +00:00
FileOpen = false ;
}
2003-08-24 10:36:07 +00:00
}
2008-02-04 22:48:42 +00:00
ULONG CCabinet : : FindFirst ( PCAB_SEARCH Search )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Finds the first file in the cabinet that matches a search criteria
* ARGUMENTS :
* Search = Pointer to search structure
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
RestartSearch = false ;
2020-09-03 16:12:25 +00:00
Search - > Next = FileList . begin ( ) ;
2008-02-02 11:57:16 +00:00
return FindNext ( Search ) ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : FindNext ( PCAB_SEARCH Search )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Finds next file in the cabinet that matches a search criteria
* ARGUMENTS :
* Search = Pointer to search structure
* RETURNS :
* Status of operation
*/
{
2008-02-04 22:48:42 +00:00
bool bFound = false ;
2008-02-02 11:57:16 +00:00
ULONG Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( RestartSearch )
{
2020-09-03 16:12:25 +00:00
Search - > Next = FileList . begin ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Skip split files already extracted */
2020-09-03 16:12:25 +00:00
while ( ( Search - > Next ! = FileList . end ( ) ) & &
( ( * Search - > Next ) - > File . FileControlID > CAB_FILE_MAX_FOLDER ) & &
( ( * Search - > Next ) - > File . FileOffset < = LastFileOffset ) )
2008-02-02 11:57:16 +00:00
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Skipping file (%s) FileOffset (0x%X) LastFileOffset (0x%X). \n " ,
2020-09-03 16:12:25 +00:00
( * Search - > Next ) - > FileName . c_str ( ) , ( UINT ) ( * Search - > Next ) - > File . FileOffset , ( UINT ) LastFileOffset ) ) ;
Search - > Next + + ;
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
RestartSearch = false ;
}
2003-08-24 10:36:07 +00:00
2008-02-04 22:48:42 +00:00
/* Check each search criteria against each file */
2020-09-03 16:12:25 +00:00
while ( Search - > Next ! = FileList . end ( ) )
2008-02-04 22:48:42 +00:00
{
// Some features (like displaying cabinets) don't require search criteria, so we can just break here.
// If a feature requires it, handle this in the ParseCmdline() function in "main.cxx".
2020-09-03 16:12:25 +00:00
if ( CriteriaList . empty ( ) )
2008-02-04 22:48:42 +00:00
break ;
2020-09-03 16:12:25 +00:00
for ( PSEARCH_CRITERIA Criteria : CriteriaList )
2008-02-04 22:48:42 +00:00
{
2020-09-12 14:21:34 +00:00
// FIXME: We could handle path\filename here
2020-09-03 16:12:25 +00:00
if ( MatchFileNamePattern ( ( * Search - > Next ) - > FileName . c_str ( ) , Criteria - > Search . c_str ( ) ) )
2008-02-04 22:48:42 +00:00
{
bFound = true ;
break ;
}
}
if ( bFound )
break ;
2020-09-03 16:12:25 +00:00
Search - > Next + + ;
2008-02-04 22:48:42 +00:00
}
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
if ( Search - > Next = = FileList . end ( ) )
2008-02-02 11:57:16 +00:00
{
if ( strlen ( DiskNext ) > 0 )
{
CloseCabinet ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
SetCabinetName ( CabinetNext ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
OnDiskChange ( CabinetNext , DiskNext ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Status = Open ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
Search - > Next = FileList . begin ( ) ;
if ( Search - > Next = = FileList . end ( ) )
2008-02-02 11:57:16 +00:00
return CAB_STATUS_NOFILE ;
}
else
return CAB_STATUS_NOFILE ;
}
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
Search - > File = & ( * Search - > Next ) - > File ;
Search - > FileName = ( * Search - > Next ) - > FileName ;
Search - > Next + + ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
ULONG CCabinet : : ExtractFile ( const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Extracts a file from the cabinet
* ARGUMENTS :
* FileName = Pointer to buffer with name of file
* RETURNS
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Size ;
ULONG Offset ;
ULONG BytesRead ;
ULONG BytesToRead ;
ULONG BytesWritten ;
ULONG BytesSkipped ;
ULONG BytesToWrite ;
ULONG TotalBytesRead ;
ULONG CurrentOffset ;
2008-02-06 18:30:15 +00:00
PUCHAR Buffer ;
PUCHAR CurrentBuffer ;
2018-01-26 15:44:14 +00:00
FILE * DestFile ;
2008-02-02 11:57:16 +00:00
PCFFILE_NODE File ;
CFDATA CFData ;
ULONG Status ;
bool Skip ;
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 11:57:16 +00:00
FILETIME FileTime ;
2003-08-24 10:36:07 +00:00
# endif
2012-02-16 17:21:10 +00:00
CHAR DestName [ PATH_MAX ] ;
CHAR TempName [ PATH_MAX ] ;
2008-02-02 11:57:16 +00:00
Status = LocateFile ( FileName , & File ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " Cannot locate file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return Status ;
}
LastFileOffset = File - > File . FileOffset ;
switch ( CurrentFolderNode - > Folder . CompressionType & CAB_COMP_MASK )
{
case CAB_COMP_NONE :
SelectCodec ( CAB_CODEC_RAW ) ;
break ;
case CAB_COMP_MSZIP :
SelectCodec ( CAB_CODEC_MSZIP ) ;
break ;
default :
return CAB_STATUS_UNSUPPCOMP ;
}
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Extracting file at uncompressed offset (0x%X) Size (%u bytes) AO (0x%X) UO (0x%X). \n " ,
( UINT ) File - > File . FileOffset ,
( UINT ) File - > File . FileSize ,
( UINT ) File - > DataBlock - > AbsoluteOffset ,
( UINT ) File - > DataBlock - > UncompOffset ) ) ;
2008-02-02 11:57:16 +00:00
2020-08-30 13:31:04 +00:00
strcpy ( DestName , DestPath . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
strcat ( DestName , FileName ) ;
/* Create destination file, fail if it already exists */
DestFile = fopen ( DestName , " rb " ) ;
if ( DestFile ! = NULL )
{
fclose ( DestFile ) ;
/* If file exists, ask to overwrite file */
if ( OnOverwrite ( & File - > File , FileName ) )
{
DestFile = fopen ( DestName , " w+b " ) ;
if ( DestFile = = NULL )
return CAB_STATUS_CANNOT_CREATE ;
}
else
return CAB_STATUS_FILE_EXISTS ;
}
else
{
DestFile = fopen ( DestName , " w+b " ) ;
if ( DestFile = = NULL )
return CAB_STATUS_CANNOT_CREATE ;
}
2018-01-26 15:44:14 +00:00
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 11:57:16 +00:00
if ( ! DosDateTimeToFileTime ( File - > File . FileDate , File - > File . FileTime , & FileTime ) )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " DosDateTimeToFileTime() failed (%u). \n " , ( UINT ) GetLastError ( ) ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_CANNOT_WRITE ;
}
SetFileTime ( DestFile , NULL , & FileTime , NULL ) ;
2003-08-24 10:36:07 +00:00
# else
2008-02-02 11:57:16 +00:00
//DPRINT(MIN_TRACE, ("FIXME: DosDateTimeToFileTime\n"));
2003-08-24 10:36:07 +00:00
# endif
2018-01-26 15:44:14 +00:00
2008-02-02 19:21:35 +00:00
SetAttributesOnFile ( DestName , File - > File . Attributes ) ;
2007-05-04 22:21:55 +00:00
2018-01-26 15:44:14 +00:00
Buffer = ( PUCHAR ) malloc ( CAB_BLOCKSIZE + 12 ) ; // This should be enough
2008-02-02 11:57:16 +00:00
if ( ! Buffer )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
2008-02-02 11:57:16 +00:00
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Call OnExtract event handler */
OnExtract ( & File - > File , FileName ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Search to start of file */
if ( fseek ( FileHandle , ( off_t ) File - > DataBlock - > AbsoluteOffset , SEEK_SET ) ! = 0 )
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
return CAB_STATUS_INVALID_CAB ;
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Size = File - > File . FileSize ;
Offset = File - > File . FileOffset ;
CurrentOffset = File - > DataBlock - > UncompOffset ;
Skip = true ;
ReuseBlock = ( CurrentDataNode = = File - > DataBlock ) ;
if ( Size > 0 )
{
do
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " CO (0x%X) ReuseBlock (%u) Offset (0x%X) Size (%d) BytesLeftInBlock (%d) \n " ,
( UINT ) File - > DataBlock - > UncompOffset , ( UINT ) ReuseBlock , ( UINT ) Offset , ( UINT ) Size ,
( UINT ) BytesLeftInBlock ) ) ;
2008-02-02 11:57:16 +00:00
if ( /*(CurrentDataNode != File->DataBlock) &&*/ ( ! ReuseBlock ) | | ( BytesLeftInBlock < = 0 ) )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Filling buffer. ReuseBlock (%u) \n " , ( UINT ) ReuseBlock ) ) ;
2008-02-02 11:57:16 +00:00
CurrentBuffer = Buffer ;
TotalBytesRead = 0 ;
do
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Size (%u bytes). \n " , ( UINT ) Size ) ) ;
2008-02-02 11:57:16 +00:00
if ( ( ( Status = ReadBlock ( & CFData , sizeof ( CFDATA ) , & BytesRead ) ) ! =
CAB_STATUS_SUCCESS ) | | ( BytesRead ! = sizeof ( CFDATA ) ) )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Data block: Checksum (0x%X) CompSize (%u bytes) UncompSize (%u bytes) \n " ,
( UINT ) CFData . Checksum ,
CFData . CompSize ,
CFData . UncompSize ) ) ;
2008-02-02 11:57:16 +00:00
ASSERT ( CFData . CompSize < = CAB_BLOCKSIZE + 12 ) ;
BytesToRead = CFData . CompSize ;
2008-02-16 22:49:52 +00:00
DPRINT ( MAX_TRACE , ( " Read: (0x%lX,0x%lX). \n " ,
( unsigned long ) CurrentBuffer , ( unsigned long ) Buffer ) ) ;
2008-02-02 11:57:16 +00:00
if ( ( ( Status = ReadBlock ( CurrentBuffer , BytesToRead , & BytesRead ) ) ! =
CAB_STATUS_SUCCESS ) | | ( BytesToRead ! = BytesRead ) )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
/* FIXME: Does not work with files generated by makecab.exe */
/*
if ( CFData . Checksum ! = 0 )
{
ULONG Checksum = ComputeChecksum ( CurrentBuffer , BytesRead , 0 ) ;
if ( Checksum ! = CFData . Checksum )
{
CloseFile ( DestFile ) ;
2018-01-26 15:44:14 +00:00
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
DPRINT ( MIN_TRACE , ( " Bad checksum (is 0x%X, should be 0x%X). \n " ,
Checksum , CFData . Checksum ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
}
2003-08-24 10:36:07 +00:00
*/
2008-02-02 11:57:16 +00:00
TotalBytesRead + = BytesRead ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentBuffer + = BytesRead ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( CFData . UncompSize = = 0 )
{
if ( strlen ( DiskNext ) = = 0 )
2017-04-14 09:50:37 +00:00
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_NOFILE ;
2017-04-14 09:50:37 +00:00
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* CloseCabinet() will destroy all file entries so in case
FileName refers to the FileName field of a CFFOLDER_NODE
structure , we have to save a copy of the filename */
strcpy ( TempName , FileName ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CloseCabinet ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
SetCabinetName ( CabinetNext ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
OnDiskChange ( CabinetNext , DiskNext ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Status = Open ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
2017-04-14 09:50:37 +00:00
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return Status ;
2017-04-14 09:50:37 +00:00
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* The first data block of the file will not be
found as it is located in the previous file */
Status = LocateFile ( TempName , & File ) ;
if ( Status = = CAB_STATUS_NOFILE )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " Cannot locate file (%u). \n " , ( UINT ) Status ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return Status ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* The file is continued in the first data block in the folder */
2020-09-03 16:12:25 +00:00
File - > DataBlock = CurrentFolderNode - > DataList . front ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Search to start of file */
if ( fseek ( FileHandle , ( off_t ) File - > DataBlock - > AbsoluteOffset , SEEK_SET ) ! = 0 )
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Continuing extraction of file at uncompressed offset (0x%X) Size (%u bytes) AO (0x%X) UO (0x%X). \n " ,
( UINT ) File - > File . FileOffset ,
( UINT ) File - > File . FileSize ,
( UINT ) File - > DataBlock - > AbsoluteOffset ,
( UINT ) File - > DataBlock - > UncompOffset ) ) ;
2008-02-02 11:57:16 +00:00
CurrentDataNode = File - > DataBlock ;
ReuseBlock = true ;
RestartSearch = true ;
}
} while ( CFData . UncompSize = = 0 ) ;
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " TotalBytesRead (%u). \n " , ( UINT ) TotalBytesRead ) ) ;
2008-02-02 11:57:16 +00:00
Status = Codec - > Uncompress ( OutputBuffer , Buffer , TotalBytesRead , & BytesToWrite ) ;
if ( Status ! = CS_SUCCESS )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
DPRINT ( MID_TRACE , ( " Cannot uncompress block. \n " ) ) ;
if ( Status = = CS_NOMEMORY )
return CAB_STATUS_NOMEMORY ;
return CAB_STATUS_INVALID_CAB ;
}
if ( BytesToWrite ! = CFData . UncompSize )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " BytesToWrite (%u) != CFData.UncompSize (%d) \n " ,
( UINT ) BytesToWrite , CFData . UncompSize ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
BytesLeftInBlock = BytesToWrite ;
}
else
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Using same buffer. ReuseBlock (%u) \n " , ( UINT ) ReuseBlock ) ) ;
2008-02-02 11:57:16 +00:00
BytesToWrite = BytesLeftInBlock ;
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Seeking to absolute offset 0x%X. \n " ,
2008-02-03 11:52:42 +00:00
( UINT ) ( CurrentDataNode - > AbsoluteOffset + sizeof ( CFDATA ) + CurrentDataNode - > Data . CompSize ) ) ) ;
2008-02-02 11:57:16 +00:00
if ( ( ( Status = ReadBlock ( & CFData , sizeof ( CFDATA ) , & BytesRead ) ) ! =
CAB_STATUS_SUCCESS ) | | ( BytesRead ! = sizeof ( CFDATA ) ) )
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
DPRINT ( MAX_TRACE , ( " CFData.CompSize 0x%X CFData.UncompSize 0x%X. \n " ,
CFData . CompSize , CFData . UncompSize ) ) ;
/* Go to next data block */
if ( fseek ( FileHandle , ( off_t ) CurrentDataNode - > AbsoluteOffset + sizeof ( CFDATA ) +
CurrentDataNode - > Data . CompSize , SEEK_SET ) ! = 0 )
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
ReuseBlock = false ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( Skip )
BytesSkipped = ( Offset - CurrentOffset ) ;
else
BytesSkipped = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
BytesToWrite - = BytesSkipped ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( Size < BytesToWrite )
BytesToWrite = Size ;
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Offset (0x%X) CurrentOffset (0x%X) ToWrite (%u) Skipped (%u)(%u) Size (%u). \n " ,
( UINT ) Offset ,
( UINT ) CurrentOffset ,
( UINT ) BytesToWrite ,
( UINT ) BytesSkipped , ( UINT ) Skip ,
( UINT ) Size ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
BytesWritten = BytesToWrite ;
2008-02-06 18:30:15 +00:00
if ( fwrite ( ( void * ) ( ( PUCHAR ) OutputBuffer + BytesSkipped ) ,
2018-01-26 15:44:14 +00:00
BytesToWrite , 1 , DestFile ) < 1 )
2008-02-02 11:57:16 +00:00
{
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
free ( Buffer ) ;
2008-02-02 11:57:16 +00:00
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
2018-01-26 15:44:14 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_CANNOT_WRITE ;
}
2018-01-26 15:44:14 +00:00
2008-02-02 11:57:16 +00:00
Size - = BytesToWrite ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentOffset + = BytesToWrite ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Don't skip any more bytes */
Skip = false ;
} while ( Size > 0 ) ;
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
fclose ( DestFile ) ;
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
free ( Buffer ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2008-02-02 14:32:44 +00:00
bool CCabinet : : IsCodecSelected ( )
/*
* FUNCTION : Returns the value of CodecSelected
* RETURNS :
* Whether a codec is selected
*/
{
return CodecSelected ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 14:32:44 +00:00
void CCabinet : : SelectCodec ( LONG Id )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Selects codec engine to use
* ARGUMENTS :
* Id = Codec identifier
*/
{
2008-02-02 11:57:16 +00:00
if ( CodecSelected )
{
if ( Id = = CodecId )
return ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CodecSelected = false ;
delete Codec ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
switch ( Id )
{
case CAB_CODEC_RAW :
Codec = new CRawCodec ( ) ;
break ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
case CAB_CODEC_MSZIP :
Codec = new CMSZipCodec ( ) ;
break ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
default :
return ;
}
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
CodecId = Id ;
CodecSelected = true ;
2003-08-24 10:36:07 +00:00
}
# ifndef CAB_READ_ONLY
/* CAB write methods */
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : NewCabinet ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Creates a new cabinet
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentDiskNumber = 0 ;
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
OutputBuffer = malloc ( CAB_BLOCKSIZE + 12 ) ; // This should be enough
InputBuffer = malloc ( CAB_BLOCKSIZE + 12 ) ; // This should be enough
2008-02-02 11:57:16 +00:00
if ( ( ! OutputBuffer ) | | ( ! InputBuffer ) )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
CurrentIBuffer = InputBuffer ;
CurrentIBufferSize = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CABHeader . Signature = CAB_SIGNATURE ;
CABHeader . Reserved1 = 0 ; // Not used
CABHeader . CabinetSize = 0 ; // Not yet known
CABHeader . Reserved2 = 0 ; // Not used
CABHeader . Reserved3 = 0 ; // Not used
CABHeader . Version = CAB_VERSION ;
CABHeader . FolderCount = 0 ; // Not yet known
CABHeader . FileCount = 0 ; // Not yet known
CABHeader . Flags = 0 ; // Not yet known
// FIXME: Should be random
CABHeader . SetID = 0x534F ;
CABHeader . CabinetNumber = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
TotalFolderSize = 0 ;
TotalFileSize = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize = sizeof ( CFHEADER ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
InitCabinetHeader ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
// NextFolderNumber is 0-based
NextFolderNumber = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode = NULL ;
Status = NewFolder ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode - > Folder . DataOffset = DiskSize - TotalHeaderSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
ScratchFile = new CCFDATAStorage ;
if ( ! ScratchFile )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2003-08-24 10:36:07 +00:00
2012-03-05 19:18:19 +00:00
Status = ScratchFile - > Create ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CreateNewFolder = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CreateNewDisk = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
PrevCabinetNumber = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return Status ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : NewDisk ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Forces a new disk to be created
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
// NextFolderNumber is 0-based
NextFolderNumber = 1 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CreateNewDisk = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize = sizeof ( CFHEADER ) + TotalFolderSize + TotalFileSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
InitCabinetHeader ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode - > TotalFolderSize = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode - > Folder . DataBlockCount = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : NewFolder ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Forces a new folder to be created
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " Creating new folder. \n " ) ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode = NewFolderNode ( ) ;
if ( ! CurrentFolderNode )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
switch ( CodecId ) {
case CAB_CODEC_RAW :
CurrentFolderNode - > Folder . CompressionType = CAB_COMP_NONE ;
break ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
case CAB_CODEC_MSZIP :
CurrentFolderNode - > Folder . CompressionType = CAB_COMP_MSZIP ;
break ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
default :
return CAB_STATUS_UNSUPPCOMP ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* FIXME: This won't work if no files are added to the new folder */
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize + = sizeof ( CFFOLDER ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
TotalFolderSize + = sizeof ( CFFOLDER ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
NextFolderNumber + + ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CABHeader . FolderCount + + ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
LastBlockStart = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteFileToScratchStorage ( PCFFILE_NODE FileNode )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes a file to the scratch file
* ARGUMENTS :
* FileNode = Pointer to file node
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG BytesToRead ;
ULONG BytesRead ;
ULONG Status ;
ULONG Size ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ! ContinueFile )
{
/* Try to open file */
2020-08-30 13:31:04 +00:00
SourceFile = fopen ( FileNode - > FileName . c_str ( ) , " rb " ) ;
2008-02-02 11:57:16 +00:00
if ( SourceFile = = NULL )
{
2020-09-12 14:21:34 +00:00
DPRINT ( MID_TRACE , ( " File not found (%s). \n " , FileNode - > FileNameOnDisk . c_str ( ) ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_NOFILE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( CreateNewFolder )
{
/* There is always a new folder after
a split file is completely stored */
Status = NewFolder ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
CreateNewFolder = false ;
}
/* Call OnAdd event handler */
2020-08-30 13:31:04 +00:00
OnAdd ( & FileNode - > File , FileNode - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
TotalBytesLeft = FileNode - > File . FileSize ;
FileNode - > File . FileOffset = CurrentFolderNode - > UncompOffset ;
CurrentFolderNode - > UncompOffset + = TotalBytesLeft ;
FileNode - > File . FileControlID = ( USHORT ) ( NextFolderNumber - 1 ) ;
CurrentFolderNode - > Commit = true ;
2015-01-07 19:26:49 +00:00
PrevCabinetNumber = CurrentDiskNumber ;
2008-02-02 11:57:16 +00:00
2020-09-12 14:21:34 +00:00
Size = sizeof ( CFFILE ) + ( ULONG ) CreateCabFilename ( FileNode ) . length ( ) + 1 ;
2008-02-02 11:57:16 +00:00
CABHeader . FileTableOffset + = Size ;
TotalFileSize + = Size ;
DiskSize + = Size ;
}
FileNode - > Commit = true ;
if ( TotalBytesLeft > 0 )
{
do
{
if ( TotalBytesLeft > ( ULONG ) CAB_BLOCKSIZE - CurrentIBufferSize )
BytesToRead = CAB_BLOCKSIZE - CurrentIBufferSize ;
else
BytesToRead = TotalBytesLeft ;
2018-01-26 15:44:14 +00:00
if ( ( BytesRead = fread ( CurrentIBuffer , 1 , BytesToRead , SourceFile ) ) ! = BytesToRead )
2008-02-02 11:57:16 +00:00
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file. BytesToRead (%u) BytesRead (%u) CurrentIBufferSize (%u). \n " ,
( UINT ) BytesToRead , ( UINT ) BytesRead , ( UINT ) CurrentIBufferSize ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2008-07-24 11:05:22 +00:00
CurrentIBuffer = ( unsigned char * ) CurrentIBuffer + BytesRead ;
2008-02-02 11:57:16 +00:00
CurrentIBufferSize + = ( USHORT ) BytesRead ;
if ( CurrentIBufferSize = = CAB_BLOCKSIZE )
{
Status = WriteDataBlock ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
TotalBytesLeft - = BytesRead ;
} while ( ( TotalBytesLeft > 0 ) & & ( ! CreateNewDisk ) ) ;
}
if ( TotalBytesLeft = = 0 )
{
2018-01-26 15:44:14 +00:00
fclose ( SourceFile ) ;
2008-02-02 11:57:16 +00:00
FileNode - > Delete = true ;
if ( FileNode - > File . FileControlID > CAB_FILE_MAX_FOLDER )
{
FileNode - > File . FileControlID = CAB_FILE_CONTINUED ;
CurrentFolderNode - > Delete = true ;
if ( ( CurrentIBufferSize > 0 ) | | ( CurrentOBufferSize > 0 ) )
{
Status = WriteDataBlock ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
CreateNewFolder = true ;
}
}
else
{
if ( FileNode - > File . FileControlID < = CAB_FILE_MAX_FOLDER )
FileNode - > File . FileControlID = CAB_FILE_SPLIT ;
else
FileNode - > File . FileControlID = CAB_FILE_PREV_NEXT ;
}
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteDisk ( ULONG MoreDisks )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Forces the current disk to be written
* ARGUMENTS :
* MoreDisks = true if there is one or more disks after this disk
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
ContinueFile = false ;
2020-09-03 16:12:25 +00:00
for ( auto it = FileList . begin ( ) ; it ! = FileList . end ( ) ; )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
Status = WriteFileToScratchStorage ( * it ) ;
2008-02-02 11:57:16 +00:00
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
if ( CreateNewDisk )
{
/* A data block could span more than two
disks if MaxDiskSize is very small */
while ( CreateNewDisk )
{
DPRINT ( MAX_TRACE , ( " Creating new disk. \n " ) ) ;
CommitDisk ( true ) ;
CloseDisk ( ) ;
NewDisk ( ) ;
ContinueFile = true ;
CreateNewDisk = false ;
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " First on new disk. CurrentIBufferSize (%u) CurrentOBufferSize (%u). \n " ,
( UINT ) CurrentIBufferSize , ( UINT ) CurrentOBufferSize ) ) ;
2008-02-02 11:57:16 +00:00
if ( ( CurrentIBufferSize > 0 ) | | ( CurrentOBufferSize > 0 ) )
{
Status = WriteDataBlock ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
}
}
else
{
ContinueFile = false ;
2020-09-03 16:12:25 +00:00
it + + ;
2008-02-02 11:57:16 +00:00
}
}
if ( ( CurrentIBufferSize > 0 ) | | ( CurrentOBufferSize > 0 ) )
{
/* A data block could span more than two
disks if MaxDiskSize is very small */
ASSERT ( CreateNewDisk = = false ) ;
do
{
if ( CreateNewDisk )
{
DPRINT ( MID_TRACE , ( " Creating new disk 2. \n " ) ) ;
CommitDisk ( true ) ;
CloseDisk ( ) ;
NewDisk ( ) ;
CreateNewDisk = false ;
}
if ( ( CurrentIBufferSize > 0 ) | | ( CurrentOBufferSize > 0 ) )
{
Status = WriteDataBlock ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
}
} while ( CreateNewDisk ) ;
}
CommitDisk ( MoreDisks ) ;
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : CommitDisk ( ULONG MoreDisks )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Commits the current disk
* ARGUMENTS :
* MoreDisks = true if there is one or more disks after this disk
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
OnCabinetName ( CurrentDiskNumber , CabinetName ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Create file, fail if it already exists */
FileHandle = fopen ( CabinetName , " rb " ) ;
if ( FileHandle ! = NULL )
{
fclose ( FileHandle ) ;
/* If file exists, ask to overwrite file */
if ( OnOverwrite ( NULL , CabinetName ) )
{
FileHandle = fopen ( CabinetName , " w+b " ) ;
if ( FileHandle = = NULL )
return CAB_STATUS_CANNOT_CREATE ;
}
else
return CAB_STATUS_FILE_EXISTS ;
}
else
{
FileHandle = fopen ( CabinetName , " w+b " ) ;
if ( FileHandle = = NULL )
return CAB_STATUS_CANNOT_CREATE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
WriteCabinetHeader ( MoreDisks ! = 0 ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
Status = WriteFolderEntries ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* Write file entries */
WriteFileEntries ( ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* Write data blocks */
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE FolderNode : FolderList )
2008-02-02 11:57:16 +00:00
{
if ( FolderNode - > Commit )
{
Status = CommitDataBlocks ( FolderNode ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
/* Remove data blocks for folder */
DestroyDataNodes ( FolderNode ) ;
}
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
fclose ( FileHandle ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
ScratchFile - > Truncate ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : CloseDisk ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Closes the current disk
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
DestroyDeletedFileNodes ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Destroy folder nodes that are completely stored */
DestroyDeletedFolderNodes ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentDiskNumber + + ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : CloseCabinet ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Closes the current cabinet
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DestroyFileNodes ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DestroyFolderNodes ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( InputBuffer )
{
2018-01-26 15:44:14 +00:00
free ( InputBuffer ) ;
2008-02-02 11:57:16 +00:00
InputBuffer = NULL ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( OutputBuffer )
{
2018-01-26 15:44:14 +00:00
free ( OutputBuffer ) ;
2008-02-02 11:57:16 +00:00
OutputBuffer = NULL ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Close ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ScratchFile )
{
Status = ScratchFile - > Destroy ( ) ;
delete ScratchFile ;
return Status ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2020-09-12 14:21:34 +00:00
ULONG CCabinet : : AddFile ( const std : : string & FileName , const std : : string & TargetFolder )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Adds a file to the current disk
* ARGUMENTS :
* FileName = Pointer to string with file name ( full path )
* RETURNS :
* Status of operation
*/
{
2018-01-26 15:44:14 +00:00
FILE * SrcFile ;
2008-02-02 11:57:16 +00:00
PCFFILE_NODE FileNode ;
2020-08-30 13:31:04 +00:00
std : : string NewFileName ;
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
NewFileName = FileName ;
ConvertPath ( NewFileName ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Try to open file */
2020-08-30 13:31:04 +00:00
SrcFile = fopen ( NewFileName . c_str ( ) , " rb " ) ;
2008-02-02 11:57:16 +00:00
if ( SrcFile = = NULL )
{
2020-08-30 13:31:04 +00:00
DPRINT ( MID_TRACE , ( " File not found (%s). \n " , NewFileName . c_str ( ) ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_CANNOT_OPEN ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
FileNode = NewFileNode ( ) ;
if ( ! FileNode )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( SrcFile ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_NOMEMORY ;
}
2005-04-06 22:27:22 +00:00
2008-02-02 11:57:16 +00:00
FileNode - > FolderNode = CurrentFolderNode ;
FileNode - > FileName = NewFileName ;
2020-09-12 14:21:34 +00:00
FileNode - > TargetFolder = TargetFolder ;
if ( FileNode - > TargetFolder . length ( ) > 0 & & FileNode - > TargetFolder [ FileNode - > TargetFolder . length ( ) - 1 ] ! = ' \\ ' )
FileNode - > TargetFolder + = ' \\ ' ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* FIXME: Check for and handle large files (>= 2GB) */
FileNode - > File . FileSize = GetSizeOfFile ( SrcFile ) ;
if ( FileNode - > File . FileSize = = ( ULONG ) - 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot read from file. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( SrcFile ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_CANNOT_READ ;
}
2003-08-24 10:36:07 +00:00
2008-11-19 19:59:54 +00:00
if ( GetFileTimes ( SrcFile , FileNode ) ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot read file times. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( SrcFile ) ;
2008-11-19 19:59:54 +00:00
return CAB_STATUS_CANNOT_READ ;
}
2003-08-24 10:36:07 +00:00
2008-11-19 19:59:54 +00:00
if ( GetAttributesOnFile ( FileNode ) ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot read file attributes. \n " ) ) ;
2018-01-26 15:44:14 +00:00
fclose ( SrcFile ) ;
2008-11-19 19:59:54 +00:00
return CAB_STATUS_CANNOT_READ ;
}
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
fclose ( SrcFile ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2008-02-04 22:48:42 +00:00
bool CCabinet : : CreateSimpleCabinet ( )
/*
* FUNCTION : Create a simple cabinet based on the files in the criteria list
*/
{
bool bRet = false ;
ULONG Status ;
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-04 22:48:42 +00:00
HANDLE hFind ;
WIN32_FIND_DATA FindFileData ;
# else
DIR * dirp ;
struct dirent * dp ;
struct stat stbuf ;
# endif
// Initialize a new cabinet
Status = NewCabinet ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot create cabinet (%u). \n " , ( UINT ) Status ) ) ;
2012-03-05 18:51:05 +00:00
goto cleanup2 ;
2008-02-04 22:48:42 +00:00
}
// Add each file in the criteria list
2020-09-03 16:12:25 +00:00
for ( PSEARCH_CRITERIA Criteria : CriteriaList )
2008-02-04 22:48:42 +00:00
{
// Store the file path with a trailing slash in szFilePath
2020-09-12 14:21:34 +00:00
std : : string szSearchPath = Criteria - > Search ;
ConvertPath ( szSearchPath ) ;
auto sep = szSearchPath . find_last_of ( DIR_SEPARATOR_CHAR ) ;
std : : string szFilePath ;
std : : string pszFile ;
2008-02-04 22:48:42 +00:00
2020-09-12 14:21:34 +00:00
if ( sep ! = std : : string : : npos )
2008-02-04 22:48:42 +00:00
{
2020-09-12 14:21:34 +00:00
pszFile = szSearchPath . substr ( sep + 1 ) ; // We want the filename, not the dir separator!
2008-02-05 15:31:12 +00:00
2020-09-12 14:21:34 +00:00
szFilePath = szSearchPath . substr ( 0 , sep + 1 ) ;
2008-02-04 22:48:42 +00:00
}
else
2008-02-05 15:31:12 +00:00
{
2020-09-12 14:21:34 +00:00
pszFile = Criteria - > Search ;
2008-02-05 15:31:12 +00:00
2020-09-12 14:21:34 +00:00
# if !defined(_WIN32)
2008-02-05 15:31:12 +00:00
// needed for opendir()
2020-09-12 14:21:34 +00:00
szFilePath = " ./ " ;
2008-02-05 15:31:12 +00:00
# endif
}
2008-02-04 22:48:42 +00:00
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-04 22:48:42 +00:00
// Windows: Use the easy FindFirstFile/FindNextFile API for getting all files and checking them against the pattern
2020-08-30 13:31:04 +00:00
hFind = FindFirstFile ( Criteria - > Search . c_str ( ) , & FindFileData ) ;
2008-02-04 22:48:42 +00:00
// Don't stop if a search criteria is not found
if ( hFind = = INVALID_HANDLE_VALUE & & GetLastError ( ) ! = ERROR_FILE_NOT_FOUND )
{
2020-08-30 13:31:04 +00:00
DPRINT ( MIN_TRACE , ( " FindFirstFile failed, Criteria: %s, error code is %u \n " , Criteria - > Search . c_str ( ) , ( UINT ) GetLastError ( ) ) ) ;
2008-02-04 22:48:42 +00:00
goto cleanup ;
}
do
{
if ( ! ( FindFileData . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
2020-09-12 14:21:34 +00:00
std : : string szFile = szFilePath ;
szFile + = FindFileData . cFileName ;
2008-02-04 22:48:42 +00:00
2020-09-12 14:21:34 +00:00
Status = AddFile ( szFile , Criteria - > TargetFolder ) ;
2008-02-04 22:48:42 +00:00
if ( Status ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot add file to cabinet (%u). \n " , ( UINT ) Status ) ) ;
2019-11-27 00:49:08 +00:00
FindClose ( hFind ) ;
2008-02-04 22:48:42 +00:00
goto cleanup ;
}
}
}
while ( FindNextFile ( hFind , & FindFileData ) ) ;
FindClose ( hFind ) ;
# else
// Unix: Use opendir/readdir to loop through all entries, stat to check if it's a file and MatchFileNamePattern to match the file against the pattern
2020-09-12 14:21:34 +00:00
dirp = opendir ( szFilePath . c_str ( ) ) ;
2008-02-04 22:48:42 +00:00
if ( dirp )
{
while ( ( dp = readdir ( dirp ) ) )
{
2020-09-12 14:21:34 +00:00
std : : string szFile = szFilePath ;
szFile + = dp - > d_name ;
2008-02-04 22:48:42 +00:00
2020-09-12 14:21:34 +00:00
if ( stat ( szFile . c_str ( ) , & stbuf ) = = 0 )
2008-02-04 22:48:42 +00:00
{
if ( stbuf . st_mode ! = S_IFDIR )
{
2020-09-12 14:21:34 +00:00
if ( MatchFileNamePattern ( dp - > d_name , pszFile . c_str ( ) ) )
2008-02-04 22:48:42 +00:00
{
2020-09-12 14:21:34 +00:00
Status = AddFile ( szFile , Criteria - > TargetFolder ) ;
2008-02-04 22:48:42 +00:00
if ( Status ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot add file to cabinet (%u). \n " , ( UINT ) Status ) ) ;
goto cleanup ;
}
}
}
}
else
{
DPRINT ( MIN_TRACE , ( " stat failed, error code is %i \n " , errno ) ) ;
goto cleanup ;
}
}
closedir ( dirp ) ;
}
# endif
}
Status = WriteDisk ( false ) ;
if ( Status = = CAB_STATUS_SUCCESS )
Status = CloseDisk ( ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot write disk (%u). \n " , ( UINT ) Status ) ) ;
goto cleanup ;
}
2012-03-05 18:51:05 +00:00
cleanup :
2008-02-04 22:48:42 +00:00
CloseCabinet ( ) ;
bRet = true ;
2012-03-05 18:51:05 +00:00
cleanup2 :
2008-02-04 22:48:42 +00:00
DestroySearchCriteria ( ) ;
return bRet ;
}
2003-08-24 10:36:07 +00:00
2007-08-18 13:08:58 +00:00
void CCabinet : : SetMaxDiskSize ( ULONG Size )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Sets the maximum size of the current disk
* ARGUMENTS :
* Size = Maximum size of current disk ( 0 means no maximum size )
*/
{
2008-02-02 11:57:16 +00:00
MaxDiskSize = Size ;
2003-08-24 10:36:07 +00:00
}
# endif /* CAB_READ_ONLY */
/* Default event handlers */
bool CCabinet : : OnOverwrite ( PCFFILE File ,
2020-08-30 13:31:04 +00:00
const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called when extracting a file and it already exists
* ARGUMENTS :
* File = Pointer to CFFILE for file being extracted
* FileName = Pointer to buffer with name of file ( full path )
* RETURNS
* true if the file should be overwritten , false if not
*/
{
2008-02-02 11:57:16 +00:00
return false ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : OnExtract ( PCFFILE File ,
2020-08-30 13:31:04 +00:00
const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called just before extracting a file
* ARGUMENTS :
* File = Pointer to CFFILE for file being extracted
* FileName = Pointer to buffer with name of file ( full path )
*/
{
}
2020-08-30 13:31:04 +00:00
void CCabinet : : OnDiskChange ( const char * CabinetName ,
const char * DiskLabel )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called when a new disk is to be processed
* ARGUMENTS :
* CabinetName = Pointer to buffer with name of cabinet
* DiskLabel = Pointer to buffer with label of disk
*/
{
}
2020-08-30 13:31:04 +00:00
void CCabinet : : OnVerboseMessage ( const char * Message )
{
}
2003-08-24 10:36:07 +00:00
# ifndef CAB_READ_ONLY
void CCabinet : : OnAdd ( PCFFILE File ,
2020-08-30 13:31:04 +00:00
const char * FileName )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called just before adding a file to a cabinet
* ARGUMENTS :
* File = Pointer to CFFILE for file being added
* FileName = Pointer to buffer with name of file ( full path )
*/
{
}
2007-08-18 13:08:58 +00:00
bool CCabinet : : OnDiskLabel ( ULONG Number , char * Label )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called when a disk needs a label
* ARGUMENTS :
* Number = Cabinet number that needs a label
* Label = Pointer to buffer to place label of disk
* RETURNS :
* true if a disk label was returned , false if not
*/
{
2008-02-02 11:57:16 +00:00
return false ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
bool CCabinet : : OnCabinetName ( ULONG Number , char * Name )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Called when a cabinet needs a name
* ARGUMENTS :
* Number = Disk number that needs a name
* Name = Pointer to buffer to place name of cabinet
* RETURNS :
* true if a cabinet name was returned , false if not
*/
{
2008-02-02 11:57:16 +00:00
return false ;
2003-08-24 10:36:07 +00:00
}
# endif /* CAB_READ_ONLY */
2007-08-18 13:08:58 +00:00
PCFFOLDER_NODE CCabinet : : LocateFolderNode ( ULONG Index )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Locates a folder node
* ARGUMENTS :
* Index = Folder index
* RETURNS :
* Pointer to folder node or NULL if the folder node was not found
*/
{
2008-02-02 11:57:16 +00:00
switch ( Index )
{
case CAB_FILE_SPLIT :
2020-09-03 16:12:25 +00:00
return FolderList . back ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
case CAB_FILE_CONTINUED :
case CAB_FILE_PREV_NEXT :
2020-09-03 16:12:25 +00:00
return FolderList . front ( ) ;
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE Node : FolderList )
2008-02-02 11:57:16 +00:00
{
if ( Node - > Index = = Index )
return Node ;
}
return NULL ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : GetAbsoluteOffset ( PCFFILE_NODE File )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns the absolute offset of a file
* ARGUMENTS :
* File = Pointer to CFFILE_NODE structure for file
* RETURNS :
* Status of operation
*/
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " FileName '%s' FileOffset (0x%X) FileSize (%u). \n " ,
2020-08-30 13:31:04 +00:00
File - > FileName . c_str ( ) ,
2008-02-03 11:23:31 +00:00
( UINT ) File - > File . FileOffset ,
( UINT ) File - > File . FileSize ) ) ;
2007-05-04 22:21:55 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFDATA_NODE Node : CurrentFolderNode - > DataList )
2008-02-02 11:57:16 +00:00
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%u). \n " ,
( UINT ) Node - > UncompOffset ,
( UINT ) ( Node - > UncompOffset + Node - > Data . UncompSize ) ,
( UINT ) Node - > Data . UncompSize ) ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* Node->Data.UncompSize will be 0 if the block is split
( ie . it is the last block in this cabinet ) */
if ( ( Node - > Data . UncompSize = = 0 ) | |
( ( File - > File . FileOffset > = Node - > UncompOffset ) & &
( File - > File . FileOffset < Node - > UncompOffset +
Node - > Data . UncompSize ) ) )
{
File - > DataBlock = Node ;
return CAB_STATUS_SUCCESS ;
}
}
return CAB_STATUS_INVALID_CAB ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
ULONG CCabinet : : LocateFile ( const char * FileName ,
2008-02-06 18:30:15 +00:00
PCFFILE_NODE * File )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Locates a file in the cabinet
* ARGUMENTS :
* FileName = Pointer to string with name of file to locate
* File = Address of pointer to CFFILE_NODE structure to fill
* RETURNS :
* Status of operation
* NOTES :
* Current folder is set to the folder of the file
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " FileName '%s' \n " , FileName ) ) ;
2007-05-04 22:21:55 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFFILE_NODE Node : FileList )
2008-02-02 11:57:16 +00:00
{
2020-09-12 14:21:34 +00:00
// FIXME: We could handle path\filename here
2020-08-30 13:31:04 +00:00
if ( strcasecmp ( FileName , Node - > FileName . c_str ( ) ) = = 0 )
2008-02-02 11:57:16 +00:00
{
CurrentFolderNode = LocateFolderNode ( Node - > File . FileControlID ) ;
if ( ! CurrentFolderNode )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MID_TRACE , ( " Folder with index number (%u) not found. \n " ,
Node - > File . FileControlID ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
if ( Node - > DataBlock = = NULL )
Status = GetAbsoluteOffset ( Node ) ;
else
Status = CAB_STATUS_SUCCESS ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
* File = Node ;
return Status ;
}
}
return CAB_STATUS_NOFILE ;
2003-08-24 10:36:07 +00:00
}
2008-02-06 18:30:15 +00:00
ULONG CCabinet : : ReadString ( char * String , LONG MaxLength )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Reads a NULL - terminated string from the cabinet
* ARGUMENTS :
* String = Pointer to buffer to place string
* MaxLength = Maximum length of string
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG BytesRead ;
ULONG Status ;
2008-02-06 18:30:15 +00:00
LONG Size ;
2008-02-02 11:57:16 +00:00
bool Found ;
Found = false ;
2008-02-06 18:30:15 +00:00
Status = ReadBlock ( String , MaxLength , & BytesRead ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
2008-02-02 11:57:16 +00:00
2008-02-06 18:30:15 +00:00
// Find the terminating NULL character
for ( Size = 0 ; Size < MaxLength ; Size + + )
{
if ( String [ Size ] = = ' \0 ' )
2008-02-02 11:57:16 +00:00
{
2008-02-06 18:30:15 +00:00
Found = true ;
break ;
2008-02-02 11:57:16 +00:00
}
2008-02-06 18:30:15 +00:00
}
2008-02-02 11:57:16 +00:00
2008-02-06 18:30:15 +00:00
if ( ! Found )
{
DPRINT ( MIN_TRACE , ( " Filename in the cabinet file is too long. \n " ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
2008-02-02 11:57:16 +00:00
2008-02-06 18:30:15 +00:00
// Compute the offset of the next CFFILE.
// We have to subtract from the current offset here, because we read MaxLength characters above and most-probably the file name isn't MaxLength characters long.
// + 1 to skip the terminating NULL character as well.
Size = - ( MaxLength - Size ) + 1 ;
2008-02-02 11:57:16 +00:00
2008-02-06 18:30:15 +00:00
if ( fseek ( FileHandle , ( off_t ) Size , SEEK_CUR ) ! = 0 )
2008-02-02 11:57:16 +00:00
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
2018-01-26 15:44:14 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : ReadFileTable ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Reads the file table from the cabinet file
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG i ;
ULONG Status ;
ULONG BytesRead ;
PCFFILE_NODE File ;
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Reading file table at absolute offset (0x%X). \n " ,
( UINT ) CABHeader . FileTableOffset ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Seek to file table */
if ( fseek ( FileHandle , ( off_t ) CABHeader . FileTableOffset , SEEK_SET ) ! = 0 )
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
for ( i = 0 ; i < CABHeader . FileCount ; i + + )
{
File = NewFileNode ( ) ;
if ( ! File )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
if ( ( Status = ReadBlock ( & File - > File , sizeof ( CFFILE ) ,
& BytesRead ) ) ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
/* Read file name */
2020-08-30 13:31:04 +00:00
char Buf [ PATH_MAX ] ;
Status = ReadString ( Buf , PATH_MAX ) ;
2008-02-02 11:57:16 +00:00
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
2020-09-12 14:21:34 +00:00
// FIXME: We could split up folder\file.txt here
2020-08-30 13:31:04 +00:00
File - > FileName = Buf ;
2008-02-02 11:57:16 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Found file '%s' at uncompressed offset (0x%X). Size (%u bytes) ControlId (0x%X). \n " ,
2020-08-30 13:31:04 +00:00
File - > FileName . c_str ( ) ,
2008-02-03 11:23:31 +00:00
( UINT ) File - > File . FileOffset ,
( UINT ) File - > File . FileSize ,
File - > File . FileControlID ) ) ;
2008-02-02 11:57:16 +00:00
}
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : ReadDataBlocks ( PCFFOLDER_NODE FolderNode )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Reads all CFDATA blocks for a folder from the cabinet file
* ARGUMENTS :
* FolderNode = Pointer to CFFOLDER_NODE structure for folder
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG AbsoluteOffset ;
ULONG UncompOffset ;
PCFDATA_NODE Node ;
ULONG BytesRead ;
ULONG Status ;
ULONG i ;
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Reading data blocks for folder (%u) at absolute offset (0x%X). \n " ,
( UINT ) FolderNode - > Index , ( UINT ) FolderNode - > Folder . DataOffset ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
AbsoluteOffset = FolderNode - > Folder . DataOffset ;
UncompOffset = FolderNode - > UncompOffset ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
for ( i = 0 ; i < FolderNode - > Folder . DataBlockCount ; i + + )
{
Node = NewDataNode ( FolderNode ) ;
if ( ! Node )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Seek to data block */
if ( fseek ( FileHandle , ( off_t ) AbsoluteOffset , SEEK_SET ) ! = 0 )
{
DPRINT ( MIN_TRACE , ( " fseek() failed. \n " ) ) ;
return CAB_STATUS_INVALID_CAB ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ( Status = ReadBlock ( & Node - > Data , sizeof ( CFDATA ) ,
& BytesRead ) ) ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
}
2007-05-04 22:21:55 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " AbsOffset (0x%X) UncompOffset (0x%X) Checksum (0x%X) CompSize (%u) UncompSize (%u). \n " ,
( UINT ) AbsoluteOffset ,
( UINT ) UncompOffset ,
( UINT ) Node - > Data . Checksum ,
Node - > Data . CompSize ,
Node - > Data . UncompSize ) ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
Node - > AbsoluteOffset = AbsoluteOffset ;
Node - > UncompOffset = UncompOffset ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
AbsoluteOffset + = sizeof ( CFDATA ) + Node - > Data . CompSize ;
UncompOffset + = Node - > Data . UncompSize ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
FolderUncompSize = UncompOffset ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
PCFFOLDER_NODE CCabinet : : NewFolderNode ( )
/*
* FUNCTION : Creates a new folder node
* RETURNS :
* Pointer to node if there was enough free memory available , otherwise NULL
*/
{
2008-02-02 11:57:16 +00:00
PCFFOLDER_NODE Node ;
2007-05-04 22:21:55 +00:00
2020-08-30 13:31:04 +00:00
Node = new CFFOLDER_NODE ;
2008-02-02 11:57:16 +00:00
if ( ! Node )
return NULL ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Node - > Folder . CompressionType = CAB_COMP_NONE ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
FolderList . push_back ( Node ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return Node ;
2003-08-24 10:36:07 +00:00
}
PCFFILE_NODE CCabinet : : NewFileNode ( )
/*
* FUNCTION : Creates a new file node
* ARGUMENTS :
* FolderNode = Pointer to folder node to bind file to
* RETURNS :
* Pointer to node if there was enough free memory available , otherwise NULL
*/
{
2008-02-02 11:57:16 +00:00
PCFFILE_NODE Node ;
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
Node = new CFFILE_NODE ;
2008-02-02 11:57:16 +00:00
if ( ! Node )
return NULL ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
FileList . push_back ( Node ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
return Node ;
2003-08-24 10:36:07 +00:00
}
PCFDATA_NODE CCabinet : : NewDataNode ( PCFFOLDER_NODE FolderNode )
/*
* FUNCTION : Creates a new data block node
* ARGUMENTS :
* FolderNode = Pointer to folder node to bind data block to
* RETURNS :
* Pointer to node if there was enough free memory available , otherwise NULL
*/
{
2008-02-02 11:57:16 +00:00
PCFDATA_NODE Node ;
2007-05-04 22:21:55 +00:00
2020-08-30 13:31:04 +00:00
Node = new CFDATA_NODE ;
2008-02-02 11:57:16 +00:00
if ( ! Node )
return NULL ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
FolderNode - > DataList . push_back ( Node ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return Node ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : DestroyDataNodes ( PCFFOLDER_NODE FolderNode )
/*
* FUNCTION : Destroys data block nodes bound to a folder node
* ARGUMENTS :
* FolderNode = Pointer to folder node
*/
{
2020-09-03 16:12:25 +00:00
for ( PCFDATA_NODE Node : FolderNode - > DataList )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
delete Node ;
2008-02-02 11:57:16 +00:00
}
2020-09-03 16:12:25 +00:00
FolderNode - > DataList . clear ( ) ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : DestroyFileNodes ( )
/*
* FUNCTION : Destroys file nodes
*/
{
2020-09-03 16:12:25 +00:00
for ( PCFFILE_NODE Node : FileList )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
delete Node ;
2008-02-02 11:57:16 +00:00
}
2020-09-03 16:12:25 +00:00
FileList . clear ( ) ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : DestroyDeletedFileNodes ( )
/*
* FUNCTION : Destroys file nodes that are marked for deletion
*/
{
2020-09-03 16:12:25 +00:00
for ( auto it = FileList . begin ( ) ; it ! = FileList . end ( ) ; )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
PCFFILE_NODE CurNode = * it ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
if ( CurNode - > Delete )
{
2020-09-03 16:12:25 +00:00
it = FileList . erase ( it ) ;
2007-05-04 22:21:55 +00:00
2020-08-30 13:31:04 +00:00
DPRINT ( MAX_TRACE , ( " Deleting file node: '%s' \n " , CurNode - > FileName . c_str ( ) ) ) ;
2007-05-04 22:21:55 +00:00
2020-09-12 14:21:34 +00:00
TotalFileSize - = ( sizeof ( CFFILE ) + ( ULONG ) CreateCabFilename ( CurNode ) . length ( ) + 1 ) ;
2007-05-04 22:21:55 +00:00
2020-08-30 13:31:04 +00:00
delete CurNode ;
2008-02-02 11:57:16 +00:00
}
2020-09-03 16:12:25 +00:00
else
{
it + + ;
}
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
}
void CCabinet : : DestroyFolderNodes ( )
/*
* FUNCTION : Destroys folder nodes
*/
{
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE Node : FolderList )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
DestroyDataNodes ( Node ) ;
delete Node ;
2008-02-02 11:57:16 +00:00
}
2020-09-03 16:12:25 +00:00
FolderList . clear ( ) ;
2003-08-24 10:36:07 +00:00
}
void CCabinet : : DestroyDeletedFolderNodes ( )
/*
* FUNCTION : Destroys folder nodes that are marked for deletion
*/
{
2020-09-03 16:12:25 +00:00
for ( auto it = FolderList . begin ( ) ; it ! = FolderList . end ( ) ; )
2008-02-02 11:57:16 +00:00
{
2020-09-03 16:12:25 +00:00
PCFFOLDER_NODE CurNode = * it ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
if ( CurNode - > Delete )
{
2020-09-03 16:12:25 +00:00
it = FolderList . erase ( it ) ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
DestroyDataNodes ( CurNode ) ;
2020-08-30 13:31:04 +00:00
delete CurNode ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
TotalFolderSize - = sizeof ( CFFOLDER ) ;
}
2020-09-03 16:12:25 +00:00
else
{
it + + ;
}
2008-02-02 11:57:16 +00:00
}
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : ComputeChecksum ( void * Buffer ,
2008-02-04 22:48:42 +00:00
ULONG Size ,
ULONG Seed )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Computes checksum for data block
* ARGUMENTS :
* Buffer = Pointer to data buffer
* Size = Length of data buffer
* Seed = Previously computed checksum
* RETURNS :
* Checksum of buffer
*/
{
2008-02-02 11:57:16 +00:00
int UlongCount ; // Number of ULONGs in block
ULONG Checksum ; // Checksum accumulator
unsigned char * pb ;
ULONG ul ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* FIXME: Doesn't seem to be correct. EXTRACT.EXE
won ' t accept checksums computed by this routine */
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Checksumming buffer (0x%p) Size (%u) \n " , Buffer , ( UINT ) Size ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
UlongCount = Size / 4 ; // Number of ULONGs
Checksum = Seed ; // Init checksum
pb = ( unsigned char * ) Buffer ; // Start at front of data block
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Checksum integral multiple of ULONGs */
while ( UlongCount - - > 0 )
{
/* NOTE: Build ULONG in big/little-endian independent manner */
ul = * pb + + ; // Get low-order byte
ul | = ( ( ( ULONG ) ( * pb + + ) ) < < 8 ) ; // Add 2nd byte
ul | = ( ( ( ULONG ) ( * pb + + ) ) < < 16 ) ; // Add 3nd byte
ul | = ( ( ( ULONG ) ( * pb + + ) ) < < 24 ) ; // Add 4th byte
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Checksum ^ = ul ; // Update checksum
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Checksum remainder bytes */
ul = 0 ;
switch ( Size % 4 )
{
case 3 :
ul | = ( ( ( ULONG ) ( * pb + + ) ) < < 16 ) ; // Add 3rd byte
case 2 :
ul | = ( ( ( ULONG ) ( * pb + + ) ) < < 8 ) ; // Add 2nd byte
case 1 :
ul | = * pb + + ; // Get low-order byte
default :
break ;
}
Checksum ^ = ul ; // Update checksum
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Return computed checksum */
return Checksum ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : ReadBlock ( void * Buffer ,
2008-02-04 22:48:42 +00:00
ULONG Size ,
PULONG BytesRead )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Read a block of data from file
* ARGUMENTS :
* Buffer = Pointer to data buffer
* Size = Length of data buffer
2007-08-18 13:08:58 +00:00
* BytesRead = Pointer to ULONG that on return will contain
2003-08-24 10:36:07 +00:00
* number of bytes read
* RETURNS :
* Status of operation
*/
{
2018-01-26 15:44:14 +00:00
* BytesRead = fread ( Buffer , 1 , Size , FileHandle ) ;
if ( * BytesRead ! = Size )
2008-02-02 11:57:16 +00:00
return CAB_STATUS_INVALID_CAB ;
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2020-08-30 13:31:04 +00:00
bool CCabinet : : MatchFileNamePattern ( const char * FileName , const char * Pattern )
2008-02-04 22:48:42 +00:00
/*
* FUNCTION : Matches a wildcard character pattern against a file
* ARGUMENTS :
* FileName = The file name to check
* Pattern = The pattern
* RETURNS :
* Whether the pattern matches the file
*
* COPYRIGHT :
* This function is based on Busybox code , Copyright ( C ) 1998 by Erik Andersen , released under GPL2 or any later version .
* Adapted from code written by Ingo Wilken .
* Original location : http : //www.busybox.net/cgi-bin/viewcvs.cgi/trunk/busybox/utility.c?rev=5&view=markup
*/
{
2020-08-30 13:31:04 +00:00
const char * retryPattern = NULL ;
const char * retryFileName = NULL ;
2008-02-04 22:48:42 +00:00
char ch ;
while ( * FileName | | * Pattern )
{
ch = * Pattern + + ;
switch ( ch )
{
case ' * ' :
retryPattern = Pattern ;
retryFileName = FileName ;
break ;
2011-06-26 22:17:01 +00:00
case ' ? ' :
2008-02-04 22:48:42 +00:00
if ( * FileName + + = = ' \0 ' )
return false ;
break ;
default :
if ( * FileName = = ch )
{
if ( * FileName )
FileName + + ;
break ;
}
if ( * FileName )
{
Pattern = retryPattern ;
FileName = + + retryFileName ;
break ;
}
return false ;
}
if ( ! Pattern )
return false ;
}
return true ;
}
2003-08-24 10:36:07 +00:00
# ifndef CAB_READ_ONLY
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : InitCabinetHeader ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Initializes cabinet header and optional fields
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG TotalSize ;
ULONG Size ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CABHeader . FileTableOffset = 0 ; // Not known yet
CABHeader . FolderCount = 0 ; // Not known yet
CABHeader . FileCount = 0 ; // Not known yet
CABHeader . Flags = 0 ; // Not known yet
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CABHeader . CabinetNumber = ( USHORT ) CurrentDiskNumber ;
2005-03-05 05:13:38 +00:00
2008-02-02 11:57:16 +00:00
if ( ( CurrentDiskNumber > 0 ) & & ( OnCabinetName ( PrevCabinetNumber , CabinetPrev ) ) )
{
CABHeader . Flags | = CAB_FLAG_HASPREV ;
if ( ! OnDiskLabel ( PrevCabinetNumber , DiskPrev ) )
strcpy ( CabinetPrev , " " ) ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( OnCabinetName ( CurrentDiskNumber + 1 , CabinetNext ) )
{
CABHeader . Flags | = CAB_FLAG_HASNEXT ;
if ( ! OnDiskLabel ( CurrentDiskNumber + 1 , DiskNext ) )
strcpy ( DiskNext , " " ) ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
TotalSize = 0 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ( CABHeader . Flags & CAB_FLAG_HASPREV ) > 0 )
{
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " CabinetPrev '%s'. \n " , CabinetPrev ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Calculate size of name of previous cabinet */
TotalSize + = ( ULONG ) strlen ( CabinetPrev ) + 1 ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Calculate size of label of previous disk */
TotalSize + = ( ULONG ) strlen ( DiskPrev ) + 1 ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ( CABHeader . Flags & CAB_FLAG_HASNEXT ) > 0 )
{
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " CabinetNext '%s'. \n " , CabinetNext ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Calculate size of name of next cabinet */
Size = ( ULONG ) strlen ( CabinetNext ) + 1 ;
TotalSize + = Size ;
NextFieldsSize = Size ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Calculate size of label of next disk */
Size = ( ULONG ) strlen ( DiskNext ) + 1 ;
TotalSize + = Size ;
NextFieldsSize + = Size ;
}
else
NextFieldsSize = 0 ;
2007-05-04 22:21:55 +00:00
2008-02-02 11:57:16 +00:00
/* Add cabinet reserved area size if present */
if ( CabinetReservedFileSize > 0 )
{
CABHeader . Flags | = CAB_FLAG_RESERVE ;
TotalSize + = CabinetReservedFileSize ;
TotalSize + = sizeof ( ULONG ) ; /* For CabinetResSize, FolderResSize, and FileResSize fields */
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize + = TotalSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
TotalHeaderSize = sizeof ( CFHEADER ) + TotalSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteCabinetHeader ( bool MoreDisks )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes the cabinet header and optional fields
* ARGUMENTS :
* MoreDisks = true if next cabinet name should be included
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG BytesWritten ;
ULONG Size ;
if ( MoreDisks )
{
CABHeader . Flags | = CAB_FLAG_HASNEXT ;
Size = TotalHeaderSize ;
}
else
{
CABHeader . Flags & = ~ CAB_FLAG_HASNEXT ;
DiskSize - = NextFieldsSize ;
Size = TotalHeaderSize - NextFieldsSize ;
}
/* Set absolute folder offsets */
BytesWritten = Size + TotalFolderSize + TotalFileSize ;
CABHeader . FolderCount = 0 ;
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE FolderNode : FolderList )
2008-02-02 11:57:16 +00:00
{
FolderNode - > Folder . DataOffset = BytesWritten ;
BytesWritten + = FolderNode - > TotalFolderSize ;
CABHeader . FolderCount + + ;
}
/* Set absolute offset of file table */
CABHeader . FileTableOffset = Size + TotalFolderSize ;
/* Count number of files to be committed */
CABHeader . FileCount = 0 ;
2020-09-03 16:12:25 +00:00
for ( PCFFILE_NODE FileNode : FileList )
2008-02-02 11:57:16 +00:00
{
if ( FileNode - > Commit )
CABHeader . FileCount + + ;
}
CABHeader . CabinetSize = DiskSize ;
/* Write header */
if ( fwrite ( & CABHeader , sizeof ( CFHEADER ) , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Write per-cabinet reserved area if present */
if ( CABHeader . Flags & CAB_FLAG_RESERVE )
{
ULONG ReservedSize ;
2005-03-05 05:13:38 +00:00
2008-02-02 11:57:16 +00:00
ReservedSize = CabinetReservedFileSize & 0xffff ;
ReservedSize | = ( 0 < < 16 ) ; /* Folder reserved area size */
ReservedSize | = ( 0 < < 24 ) ; /* Folder reserved area size */
2018-01-26 15:44:14 +00:00
2008-02-02 11:57:16 +00:00
BytesWritten = sizeof ( ULONG ) ;
if ( fwrite ( & ReservedSize , sizeof ( ULONG ) , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
BytesWritten = CabinetReservedFileSize ;
if ( fwrite ( CabinetReservedFileBuffer , CabinetReservedFileSize , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ( CABHeader . Flags & CAB_FLAG_HASPREV ) > 0 )
{
DPRINT ( MAX_TRACE , ( " CabinetPrev '%s'. \n " , CabinetPrev ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Write name of previous cabinet */
Size = ( ULONG ) strlen ( CabinetPrev ) + 1 ;
BytesWritten = Size ;
if ( fwrite ( CabinetPrev , Size , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " DiskPrev '%s'. \n " , DiskPrev ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Write label of previous disk */
Size = ( ULONG ) strlen ( DiskPrev ) + 1 ;
BytesWritten = Size ;
if ( fwrite ( DiskPrev , Size , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ( CABHeader . Flags & CAB_FLAG_HASNEXT ) > 0 )
{
DPRINT ( MAX_TRACE , ( " CabinetNext '%s'. \n " , CabinetNext ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Write name of next cabinet */
Size = ( ULONG ) strlen ( CabinetNext ) + 1 ;
BytesWritten = Size ;
if ( fwrite ( CabinetNext , Size , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " DiskNext '%s'. \n " , DiskNext ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* Write label of next disk */
Size = ( ULONG ) strlen ( DiskNext ) + 1 ;
BytesWritten = Size ;
if ( fwrite ( DiskNext , Size , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteFolderEntries ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes folder entries
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " Writing folder table. \n " ) ) ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFFOLDER_NODE FolderNode : FolderList )
2008-02-02 11:57:16 +00:00
{
if ( FolderNode - > Commit )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Writing folder entry. CompressionType (0x%X) DataBlockCount (%d) DataOffset (0x%X). \n " ,
FolderNode - > Folder . CompressionType , FolderNode - > Folder . DataBlockCount , ( UINT ) FolderNode - > Folder . DataOffset ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( fwrite ( & FolderNode - > Folder , sizeof ( CFFOLDER ) , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
}
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteFileEntries ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes file entries for all files
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
bool SetCont = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " Writing file table. \n " ) ) ;
2003-08-24 10:36:07 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFFILE_NODE File : FileList )
2008-02-02 11:57:16 +00:00
{
if ( File - > Commit )
{
/* Remove any continued files that ends in this disk */
if ( File - > File . FileControlID = = CAB_FILE_CONTINUED )
File - > Delete = true ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
/* The file could end in the last (split) block and should therefore
appear in the next disk too */
2005-03-05 05:13:38 +00:00
2008-02-02 11:57:16 +00:00
if ( ( File - > File . FileOffset + File - > File . FileSize > = LastBlockStart ) & &
( File - > File . FileControlID < = CAB_FILE_MAX_FOLDER ) & & ( BlockIsSplit ) )
{
File - > File . FileControlID = CAB_FILE_SPLIT ;
File - > Delete = false ;
SetCont = true ;
}
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Writing file entry. FileControlID (0x%X) FileOffset (0x%X) FileSize (%u) FileName (%s). \n " ,
2020-08-30 13:31:04 +00:00
File - > File . FileControlID , ( UINT ) File - > File . FileOffset , ( UINT ) File - > File . FileSize , File - > FileName . c_str ( ) ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( fwrite ( & File - > File , sizeof ( CFFILE ) , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2020-09-12 14:21:34 +00:00
std : : string fname = CreateCabFilename ( File ) ;
2020-08-30 13:31:04 +00:00
if ( fwrite ( fname . c_str ( ) , fname . length ( ) + 1 , 1 , FileHandle ) < 1 )
2008-02-02 11:57:16 +00:00
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( SetCont )
{
File - > File . FileControlID = CAB_FILE_CONTINUED ;
SetCont = false ;
}
}
}
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : CommitDataBlocks ( PCFFOLDER_NODE FolderNode )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes data blocks to the cabinet
* ARGUMENTS :
* FolderNode = Pointer to folder node containing the data blocks
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG BytesRead ;
ULONG Status ;
2020-09-03 16:12:25 +00:00
if ( ! FolderNode - > DataList . empty ( ) )
Status = ScratchFile - > Seek ( FolderNode - > DataList . front ( ) - > ScratchFilePosition ) ;
2008-02-02 11:57:16 +00:00
2020-09-03 16:12:25 +00:00
for ( PCFDATA_NODE DataNode : FolderNode - > DataList )
2008-02-02 11:57:16 +00:00
{
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Reading block at (0x%X) CompSize (%u) UncompSize (%u). \n " ,
( UINT ) DataNode - > ScratchFilePosition ,
2008-02-02 11:57:16 +00:00
DataNode - > Data . CompSize ,
DataNode - > Data . UncompSize ) ) ;
/* InputBuffer is free for us to use here, so we use it and avoid a
memory allocation . OutputBuffer can ' t be used here because it may
still contain valid data ( if a data block spans two or more disks ) */
Status = ScratchFile - > ReadBlock ( & DataNode - > Data , InputBuffer , & BytesRead ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
{
2008-02-03 11:23:31 +00:00
DPRINT ( MIN_TRACE , ( " Cannot read from scratch file (%u). \n " , ( UINT ) Status ) ) ;
2008-02-02 11:57:16 +00:00
return Status ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( fwrite ( & DataNode - > Data , sizeof ( CFDATA ) , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( fwrite ( InputBuffer , DataNode - > Data . CompSize , 1 , FileHandle ) < 1 )
{
DPRINT ( MIN_TRACE , ( " Cannot write to file. \n " ) ) ;
return CAB_STATUS_CANNOT_WRITE ;
}
}
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : WriteDataBlock ( )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Writes the current data block to the scratch file
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
ULONG Status ;
ULONG BytesWritten ;
PCFDATA_NODE DataNode ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ! BlockIsSplit )
{
Status = Codec - > Compress ( OutputBuffer ,
InputBuffer ,
CurrentIBufferSize ,
& TotalCompSize ) ;
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Block compressed. CurrentIBufferSize (%u) TotalCompSize(%u). \n " ,
( UINT ) CurrentIBufferSize , ( UINT ) TotalCompSize ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentOBuffer = OutputBuffer ;
CurrentOBufferSize = TotalCompSize ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DataNode = NewDataNode ( CurrentFolderNode ) ;
if ( ! DataNode )
{
DPRINT ( MIN_TRACE , ( " Insufficient memory. \n " ) ) ;
return CAB_STATUS_NOMEMORY ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize + = sizeof ( CFDATA ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( MaxDiskSize > 0 )
/* Disk size is limited */
BlockIsSplit = ( DiskSize + CurrentOBufferSize > MaxDiskSize ) ;
else
BlockIsSplit = false ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( BlockIsSplit )
{
DataNode - > Data . CompSize = ( USHORT ) ( MaxDiskSize - DiskSize ) ;
DataNode - > Data . UncompSize = 0 ;
CreateNewDisk = true ;
}
else
{
DataNode - > Data . CompSize = ( USHORT ) CurrentOBufferSize ;
DataNode - > Data . UncompSize = ( USHORT ) CurrentIBufferSize ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DataNode - > Data . Checksum = 0 ;
DataNode - > ScratchFilePosition = ScratchFile - > Position ( ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
// FIXME: MAKECAB.EXE does not like this checksum algorithm
//DataNode->Data.Checksum = ComputeChecksum(CurrentOBuffer, DataNode->Data.CompSize, 0);
2003-08-24 10:36:07 +00:00
2008-02-03 11:23:31 +00:00
DPRINT ( MAX_TRACE , ( " Writing block. Checksum (0x%X) CompSize (%u) UncompSize (%u). \n " ,
( UINT ) DataNode - > Data . Checksum ,
DataNode - > Data . CompSize ,
DataNode - > Data . UncompSize ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
Status = ScratchFile - > WriteBlock ( & DataNode - > Data ,
CurrentOBuffer , & BytesWritten ) ;
if ( Status ! = CAB_STATUS_SUCCESS )
return Status ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DiskSize + = BytesWritten ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
CurrentFolderNode - > TotalFolderSize + = ( BytesWritten + sizeof ( CFDATA ) ) ;
CurrentFolderNode - > Folder . DataBlockCount + + ;
2003-08-24 10:36:07 +00:00
2008-07-24 11:05:22 +00:00
CurrentOBuffer = ( unsigned char * ) CurrentOBuffer + DataNode - > Data . CompSize ;
CurrentOBufferSize - = DataNode - > Data . CompSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
LastBlockStart + = DataNode - > Data . UncompSize ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
if ( ! BlockIsSplit )
{
CurrentIBufferSize = 0 ;
CurrentIBuffer = InputBuffer ;
}
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2011-06-26 22:17:01 +00:00
# if !defined(_WIN32)
2003-08-24 10:36:07 +00:00
void CCabinet : : ConvertDateAndTime ( time_t * Time ,
2007-08-18 13:08:58 +00:00
PUSHORT DosDate ,
PUSHORT DosTime )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns file times of a file
* ARGUMENTS :
* FileHandle = File handle of file to get file times from
* File = Pointer to CFFILE node for file
* RETURNS :
* Status of operation
*/
{
2008-02-02 11:57:16 +00:00
struct tm * timedef ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
timedef = localtime ( Time ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
DPRINT ( MAX_TRACE , ( " day: %d, mon: %d, year:%d, hour: %d, min: %d, sec: %d \n " ,
timedef - > tm_mday , timedef - > tm_mon , timedef - > tm_year ,
timedef - > tm_sec , timedef - > tm_min , timedef - > tm_hour ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
* DosDate = ( ( timedef - > tm_mday + 1 ) < < 0 )
| ( ( timedef - > tm_mon + 1 ) < < 5 )
| ( ( ( timedef - > tm_year + 1900 ) - 1980 ) < < 9 ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
* DosTime = ( timedef - > tm_sec < < 0 )
| ( timedef - > tm_min < < 5 )
| ( timedef - > tm_hour < < 11 ) ;
2003-08-24 10:36:07 +00:00
}
2011-06-26 22:17:01 +00:00
# endif // !_WIN32
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
ULONG CCabinet : : GetFileTimes ( FILE * FileHandle , PCFFILE_NODE File )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns file times of a file
* ARGUMENTS :
* FileHandle = File handle of file to get file times from
* File = Pointer to CFFILE node for file
* RETURNS :
* Status of operation
*/
{
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 11:57:16 +00:00
FILETIME FileTime ;
2019-04-15 11:29:33 +00:00
HANDLE FileNo = UlongToHandle ( _fileno ( FileHandle ) ) ;
2003-08-24 10:36:07 +00:00
2018-01-26 15:44:14 +00:00
if ( GetFileTime ( FileNo , NULL , NULL , & FileTime ) )
2008-02-02 11:57:16 +00:00
FileTimeToDosDateTime ( & FileTime ,
& File - > File . FileDate ,
& File - > File . FileTime ) ;
2003-08-24 10:36:07 +00:00
# else
2008-02-02 11:57:16 +00:00
struct stat stbuf ;
2012-02-16 17:21:10 +00:00
char buf [ PATH_MAX ] ;
2008-02-02 11:57:16 +00:00
// Check for an absolute path
2020-08-30 13:31:04 +00:00
if ( File - > FileName . length ( ) > 0 & & IsSeparator ( File - > FileName [ 0 ] ) )
strcpy ( buf , File - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
else
{
2008-11-19 19:59:54 +00:00
if ( ! getcwd ( buf , sizeof ( buf ) ) )
return CAB_STATUS_CANNOT_READ ;
2008-02-02 11:57:16 +00:00
strcat ( buf , DIR_SEPARATOR_STRING ) ;
2020-08-30 13:31:04 +00:00
strcat ( buf , File - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
}
if ( stat ( buf , & stbuf ) = = - 1 )
return CAB_STATUS_CANNOT_READ ;
ConvertDateAndTime ( & stbuf . st_mtime , & File - > File . FileDate , & File - > File . FileTime ) ;
2003-08-24 10:36:07 +00:00
# endif
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2007-08-18 13:08:58 +00:00
ULONG CCabinet : : GetAttributesOnFile ( PCFFILE_NODE File )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Returns attributes on a file
* ARGUMENTS :
* File = Pointer to CFFILE node for file
* RETURNS :
* Status of operation
*/
{
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 11:57:16 +00:00
LONG Attributes ;
2003-08-24 10:36:07 +00:00
2020-08-30 13:31:04 +00:00
Attributes = GetFileAttributes ( File - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
if ( Attributes = = - 1 )
return CAB_STATUS_CANNOT_READ ;
2003-08-24 10:36:07 +00:00
2008-02-02 19:21:35 +00:00
// 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
// The IDs for these attributes are the same in the CAB file and under Windows
// If the file has any other attributes, strip them off by the logical AND.
File - > File . Attributes = ( USHORT ) ( Attributes & 0x37 ) ;
2003-08-24 10:36:07 +00:00
# else
2008-02-02 11:57:16 +00:00
struct stat stbuf ;
2012-02-16 17:21:10 +00:00
char buf [ PATH_MAX ] ;
2008-02-02 11:57:16 +00:00
// Check for an absolute path
2020-08-30 13:31:04 +00:00
if ( File - > FileName . length ( ) > 0 & & IsSeparator ( File - > FileName [ 0 ] ) )
strcpy ( buf , File - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
else
{
2008-11-19 19:59:54 +00:00
if ( ! getcwd ( buf , sizeof ( buf ) ) )
return CAB_STATUS_CANNOT_READ ;
2008-02-02 11:57:16 +00:00
strcat ( buf , DIR_SEPARATOR_STRING ) ;
2020-08-30 13:31:04 +00:00
strcat ( buf , File - > FileName . c_str ( ) ) ;
2008-02-02 11:57:16 +00:00
}
if ( stat ( buf , & stbuf ) = = - 1 )
return CAB_STATUS_CANNOT_READ ;
2003-08-24 10:36:07 +00:00
#if 0
2008-02-02 11:57:16 +00:00
File - > File . Attributes | = CAB_ATTRIB_READONLY ;
File - > File . Attributes | = CAB_ATTRIB_HIDDEN ;
File - > File . Attributes | = CAB_ATTRIB_SYSTEM ;
2003-08-24 10:36:07 +00:00
# endif
2008-02-02 11:57:16 +00:00
if ( stbuf . st_mode & S_IFDIR )
File - > File . Attributes | = CAB_ATTRIB_DIRECTORY ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
File - > File . Attributes | = CAB_ATTRIB_ARCHIVE ;
2003-08-24 10:36:07 +00:00
# endif
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
}
2008-02-02 19:21:35 +00:00
ULONG CCabinet : : SetAttributesOnFile ( char * FileName , USHORT FileAttributes )
2003-08-24 10:36:07 +00:00
/*
* FUNCTION : Sets attributes on a file
* ARGUMENTS :
2008-02-02 19:21:35 +00:00
* FileName = File name with path
* FileAttributes = Attributes of that file
2003-08-24 10:36:07 +00:00
* RETURNS :
* Status of operation
*/
{
2011-06-26 22:17:01 +00:00
# if defined(_WIN32)
2008-02-02 19:21:35 +00:00
// 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
// The IDs for these attributes are the same in the CAB file and under Windows
// If the file has any other attributes, strip them off by the logical AND.
SetFileAttributes ( FileName , ( DWORD ) ( FileAttributes & 0x37 ) ) ;
2003-08-24 10:36:07 +00:00
2008-02-02 11:57:16 +00:00
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
# else
2008-02-02 11:57:16 +00:00
//DPRINT(MIN_TRACE, ("FIXME: SetAttributesOnFile() is unimplemented\n"));
return CAB_STATUS_SUCCESS ;
2003-08-24 10:36:07 +00:00
# endif
}
# endif /* CAB_READ_ONLY */
/* EOF */