407 lines
17 KiB
C
407 lines
17 KiB
C
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
||
|
//
|
||
|
// File: cabinet.h
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
/*** cabinet.h - Definitions for Cabinet File structure
|
||
|
*
|
||
|
* Author:
|
||
|
* Benjamin W. Slivka
|
||
|
*
|
||
|
* History:
|
||
|
* 15-Aug-1993 bens Initial version
|
||
|
* 05-Sep-1993 bens Added Overview section
|
||
|
* 29-Nov-1993 chuckst Added disk names to folder first & next
|
||
|
* Used "CF" consistently
|
||
|
* Eliminated redundant cch fields
|
||
|
* 09-Feb-1994 chuckst merged in some related global constants
|
||
|
* 09-Mar-1994 bens Add RESERVE defintions (for encryption)
|
||
|
* 17-Mar-1994 bens Improve comments about split CFDATA structures
|
||
|
* 25-Mar-1994 bens Add cabinet set ID
|
||
|
* 13-May-1994 bens Define bad value for iCabinet
|
||
|
* 15-Jun-1997 pberkman added CABSignatureStruct_
|
||
|
*
|
||
|
* Overview:
|
||
|
* This file contains definitions for the Diamond Cabinet File format.
|
||
|
* A Cabinet File exists to store one or more files. Usually these
|
||
|
* files have been compressed, but that is not required. It is also
|
||
|
* possible for a cabinet file to contain only a portion of a larger
|
||
|
* file.
|
||
|
*
|
||
|
* In designing this format, the following goals where achieved:
|
||
|
* 1) Minimize overhead in the CF format
|
||
|
* ==> Where ever possible BYTEs or USHORTs were used, rather
|
||
|
* than using LONGs, even though the latter would be easier
|
||
|
* to manipulate on certain RISC platforms.
|
||
|
* 2) Support little-endian and big-endian byte ordering.
|
||
|
* ==> For simplicity on x86 systems, multi-byte numbers are
|
||
|
* stored in a little-endian form, but the code to read and
|
||
|
* write these numbers operates correctly on either type of
|
||
|
* computer.
|
||
|
*
|
||
|
* A cabinet file contains the following structures in the following
|
||
|
* order:
|
||
|
* Name Description
|
||
|
* ----------- -------------------
|
||
|
* CFHEADER Cabinet description
|
||
|
* [CFRESERVE] Optional RESERVED control information in CFHEADER
|
||
|
* CFFOLDER(s) Folder descriptions
|
||
|
* [reserved] Optional RESERVED data per folder
|
||
|
* CFFILE(s) File descriptions
|
||
|
* CFDATA(s) Data blocks
|
||
|
* [reserved] Optional RESERVED data per data block
|
||
|
*
|
||
|
* Data Integrity Strategy:
|
||
|
* The Cabinet File has built-in data integrity checks, since it is
|
||
|
* possible for customers to have damaged diskettes, or for accidental
|
||
|
* or malicious damage to occur. Rather than doing an individual
|
||
|
* checksum for the entire cabinet file (which would have a dramatic
|
||
|
* impact on the speed of installation from floppy disk, since the
|
||
|
* entire file would need to be read), we have per-component
|
||
|
* checksums, and compute and check them as we read the various
|
||
|
* components of the file.
|
||
|
*
|
||
|
* 1) Checksum CFHEADER
|
||
|
* 2) Store cabinet file length in CFHEADER (to detect file truncation)
|
||
|
* 3) Checksum entire set of CFFOLDER structures
|
||
|
* 4) Checksum entire set of CFFILE structures
|
||
|
* 5) Checksum each (compressed) data block independantly
|
||
|
*
|
||
|
* This approach allows us to avoid reading unnecessary parts of the
|
||
|
* file cabinet (though reading all of CFFOLDER and CFFILE structures
|
||
|
* would otherwise not be required in all cases), while still providing
|
||
|
* adequate integrity checking.
|
||
|
*/
|
||
|
|
||
|
#ifndef INCLUDED_CABINET
|
||
|
#define INCLUDED_CABINET 1
|
||
|
|
||
|
typedef unsigned long CHECKSUM;
|
||
|
typedef unsigned long COFF;
|
||
|
typedef unsigned long UOFF;
|
||
|
|
||
|
//** Pack structures tightly in cabinet files!
|
||
|
#pragma pack(1)
|
||
|
|
||
|
|
||
|
/*** verCF - Cabinet File format version
|
||
|
*
|
||
|
* The low-order byte is interpreted as a decimal number for the minor
|
||
|
* (1/100ths) portion of the version number.
|
||
|
* The high-order byte is interpreted as a decimal number for the major
|
||
|
* portion of the version number.
|
||
|
*
|
||
|
* Examples:
|
||
|
* 0x0000 0.00
|
||
|
* 0x010A 1.10
|
||
|
* 0x0410 4.16
|
||
|
*
|
||
|
* History:
|
||
|
* 1.01 Original
|
||
|
* 1.02 Added flags field, changed signature
|
||
|
* 1.03 Added setId,iCabinet so FDI can ensure correct cabinet
|
||
|
* on continuation.
|
||
|
*/
|
||
|
#define verCF 0x0103 // CF version 1.03
|
||
|
|
||
|
|
||
|
/*** Various cabinet file limits
|
||
|
*
|
||
|
*/
|
||
|
#define cMAX_FOLDERS_PER_CABINET (ifoldMASK-1)
|
||
|
#define cMAX_FILES_PER_CABINET 65535
|
||
|
|
||
|
|
||
|
/*** cbRESERVE_XXX_MAX - Maximum size of RESERVE sections
|
||
|
*
|
||
|
* NOTE: cbRESERVE_HEADER_MAX is a fair bit less than 64K because in
|
||
|
* the 16-bit version of this code, we want to have a USHORT
|
||
|
* variable that holds the size of the CFHEADER structure +
|
||
|
* the size of the CFRESERVE structure + the size of the per-header
|
||
|
* reserved data.
|
||
|
*/
|
||
|
#define cbRESERVE_HEADER_MAX 60000 // Fits in a USHORT
|
||
|
#define cbRESERVE_FOLDER_MAX 255 // Fits in a BYTE
|
||
|
#define cbRESERVE_DATA_MAX 255 // Fits in a BYTE
|
||
|
|
||
|
|
||
|
/*** ifoldXXXX - Special values for CFFILE.iFolder
|
||
|
*
|
||
|
*/
|
||
|
#define ifoldMASK 0xFFFC // Low two bits zero
|
||
|
#define ifoldCONTINUED_FROM_PREV 0xFFFD
|
||
|
#define ifoldCONTINUED_TO_NEXT 0xFFFE
|
||
|
#define ifoldCONTINUED_PREV_AND_NEXT 0xFFFF
|
||
|
|
||
|
#define IS_CONTD_FORWARD(ifold) ((ifold & 0xfffe) == ifoldCONTINUED_TO_NEXT)
|
||
|
#define IS_CONTD_BACK(ifold) ((ifold & 0xfffd) == ifoldCONTINUED_FROM_PREV)
|
||
|
|
||
|
|
||
|
#ifndef MAKESIG
|
||
|
/*** MAKESIG - Construct a 4 byte signature
|
||
|
*
|
||
|
* Entry:
|
||
|
* ch1,ch2,ch3,ch4 - four characters
|
||
|
*
|
||
|
* Exit:
|
||
|
* returns unsigned long
|
||
|
*/
|
||
|
#define MAKESIG(ch1,ch2,ch3,ch4) \
|
||
|
( ((unsigned long)ch1) + \
|
||
|
(((unsigned long)ch2)<< 8) + \
|
||
|
(((unsigned long)ch3)<<16) + \
|
||
|
(((unsigned long)ch4)<<24) )
|
||
|
#endif // !MAKESIG
|
||
|
|
||
|
|
||
|
#define sigCFHEADER MAKESIG('M','S','C','F') // CFHEADER signature
|
||
|
|
||
|
|
||
|
/*** cfhdrXXX - bit flags for cfheader.flags field
|
||
|
*
|
||
|
*/
|
||
|
#define cfhdrPREV_CABINET 0x0001 // Set if previous cab/disk present
|
||
|
#define cfhdrNEXT_CABINET 0x0002 // Set if next cab/disk present
|
||
|
#define cfhdrRESERVE_PRESENT 0x0004 // Set if RESERVE_CONTROL is present
|
||
|
|
||
|
|
||
|
/*** CFHEADER - Cabinet File Header
|
||
|
*
|
||
|
*/
|
||
|
typedef struct {
|
||
|
//** LONGs are first, to ensure alignment
|
||
|
long sig; // Cabinet File identification string
|
||
|
CHECKSUM csumHeader; // Structure checksum (excluding csumHeader!)
|
||
|
long cbCabinet; // Total length of file (consistency check)
|
||
|
CHECKSUM csumFolders; // Checksum of CFFOLDER list
|
||
|
COFF coffFiles; // Location in cabinet file of CFFILE list
|
||
|
CHECKSUM csumFiles; // Checksum of CFFILE list
|
||
|
|
||
|
//** SHORTs are next, to ensure alignment
|
||
|
USHORT version; // Cabinet File version (verCF)
|
||
|
USHORT cFolders; // Count of folders (CFIFOLDERs) in cabinet
|
||
|
USHORT cFiles; // Count of files (CFIFILEs) in cabinet
|
||
|
USHORT flags; // Flags to indicate optional data presence
|
||
|
USHORT setID; // Cabinet set ID (identifies set of cabinets)
|
||
|
USHORT iCabinet; // Cabinet number in set (0 based)
|
||
|
#define iCABINET_BAD 0xFFFF // Illegal number for iCabinet
|
||
|
|
||
|
//** If flags has the cfhdrRESERVE_PRESENT bit set, then a CFRESERVE
|
||
|
// structure appears here, followed possibly by some CFHEADER reserved
|
||
|
// space. The CFRESERVE structure has fields to define how much reserved
|
||
|
// space is present in the CFHEADER, CFFOLDER, and CFDATA structures.
|
||
|
// If CFRESERVE.cbCFHeader is non-zero, then abReserve[] immediately
|
||
|
// follows the CFRESERVE structure. Note that all of these sizes are
|
||
|
// multiples of 4 bytes, to ensure structure alignment!
|
||
|
//
|
||
|
// CFRESERVE cfres; // Reserve information
|
||
|
// BYTE abReserve[]; // Reserved data space
|
||
|
//
|
||
|
|
||
|
//** The following fields presence depends upon the settings in the flags
|
||
|
// field above. If cfhdrPREV_CABINET is set, then there are two ASCIIZ
|
||
|
// strings to describe the previous disk and cabinet.
|
||
|
//
|
||
|
// NOTE: This "previous" cabinet is not necessarily the immediately
|
||
|
// preceding cabinet! While it usually will be, if a file is
|
||
|
// continued into the current cabinet, then the "previous"
|
||
|
// cabinet identifies the cabinet where the folder that contains
|
||
|
// this file *starts*! For example, if EXCEL.EXE starts in
|
||
|
// cabinet excel.1 and is continued through excel.2 to excel.3,
|
||
|
// then cabinet excel.3 will point back to *cabinet.1*, since
|
||
|
// that is where you have to start in order to extract EXCEL.EXE.
|
||
|
//
|
||
|
// char szCabinetPrev[]; // Prev Cabinet filespec
|
||
|
// char szDiskPrev[]; // Prev descriptive disk name
|
||
|
//
|
||
|
// Similarly, If cfhdrNEXT_CABINET is set, then there are two ASCIIZ
|
||
|
// strings to describe the next disk and cabinet:
|
||
|
//
|
||
|
// char szCabinetNext[]; // Next Cabinet filespec
|
||
|
// char szDiskNext[]; // Next descriptive disk name
|
||
|
//
|
||
|
} CFHEADER; /* cfheader */
|
||
|
|
||
|
|
||
|
/*** CFRESERVE - Cabinet File Reserved data information
|
||
|
*
|
||
|
* This structure is present in the middle of the CFHEADER structure if
|
||
|
* CFHEADER.flags has the cfhdrRESERVE_PRESENT bit set. This structure
|
||
|
* defines the sizes of all the reserved data sections in the CFHEADER,
|
||
|
* CFFOLDER, and CFDATA structures.
|
||
|
*
|
||
|
* These reserved sizes can be zero (although it would be strange to have
|
||
|
* all of them be zero), but otherwise must be a multiple of 4, to ensure
|
||
|
* structure alignment for RISC machines.
|
||
|
*/
|
||
|
typedef struct {
|
||
|
USHORT cbCFHeader; // Size of abReserve in CFHEADER structure
|
||
|
BYTE cbCFFolder; // Size of abReserve in CFFOLDER structure
|
||
|
BYTE cbCFData; // Size of abReserve in CFDATA structure
|
||
|
} CFRESERVE; /* cfreserve */
|
||
|
|
||
|
#define cbCF_HEADER_BAD 0xFFFF // Bad value for CFRESERVE.cbCFHeader
|
||
|
|
||
|
//
|
||
|
// the following struct identifies the content of the signature area
|
||
|
// of abReserved for Athenticode version 2.
|
||
|
//
|
||
|
typedef struct CABSignatureStruct_
|
||
|
{
|
||
|
DWORD cbFileOffset;
|
||
|
DWORD cbSig;
|
||
|
BYTE Filler[8];
|
||
|
} CABSignatureStruct_;
|
||
|
|
||
|
|
||
|
|
||
|
/*** CFFOLDER - Cabinet Folder
|
||
|
*
|
||
|
* This structure describes a partial or complete "compression unit".
|
||
|
* A folder is by definition a stream of compressed data. To retrieve
|
||
|
* an uncompressed data from a folder, you *must* start decompressing
|
||
|
* the data at the start of the folder, regardless of how far into the
|
||
|
* folder the data you want actually starts.
|
||
|
*
|
||
|
* Folders may start in one cabinet, and continue on to one or more
|
||
|
* succeeding cabinets. In general, if a folder has been continued over
|
||
|
* a cabinet boundary, Diamond/FCI will terminate that folder as soon as
|
||
|
* the current file has been completely compressed. Generally this means
|
||
|
* that a folder would span at most two cabinets, but if the file is really
|
||
|
* large, it could span more than two cabinets.
|
||
|
*
|
||
|
* Note: CFFOLDERs actually refer to folder *fragments*, not necessarily
|
||
|
* complete folders. You know that a CFFOLDER is the beginning of a
|
||
|
* folder (as opposed to a continuation in a subsequent cabinet file)
|
||
|
* if a file starts in it (i.e., the CFFILE.uoffFolderStart field is
|
||
|
* 0).
|
||
|
*/
|
||
|
typedef struct {
|
||
|
COFF coffCabStart; // Offset in cabinet file of first CFDATA
|
||
|
// block for this folder.
|
||
|
|
||
|
USHORT cCFData; // Count of CFDATAs for this folder that
|
||
|
// are actually in this cabinet. Note that
|
||
|
// a folder can continue into another cabinet
|
||
|
// and have many more CFDATA blocks in that
|
||
|
// cabinet, *and* a folder may have started
|
||
|
// in a previous cabinet. This count is
|
||
|
// only of CFDATAs for this folder that are
|
||
|
// (at least partially) in this cabinet.
|
||
|
|
||
|
short typeCompress; // Indicates compression type for all CFDATA
|
||
|
// blocks for this folder. The valid values
|
||
|
// are defined in the types.h built into
|
||
|
// fci.h/fdi.h.
|
||
|
|
||
|
//** If CFHEADER.flags has the cfhdrRESERVE_PRESENT bit set, and
|
||
|
// CFRESERVE.cbCFFolder is non-zero, then abReserve[] appears here.
|
||
|
//
|
||
|
// BYTE abReserve[]; // Reserved data space
|
||
|
//
|
||
|
} CFFOLDER; /* cffolder */
|
||
|
|
||
|
|
||
|
|
||
|
/*** CFFILE - Cabinet File structure describing a single file in the cabinet
|
||
|
*
|
||
|
* NOTE: iFolder is used to indicatate continuation cases, so we have to
|
||
|
* calculate the real iFolder by examining the cabinet files:
|
||
|
*
|
||
|
* ifoldCONTINUED_FROM_PREV
|
||
|
* This file ends in this cabinet, but is continued from a
|
||
|
* previous cabinet. Therefore, the portion of the file contained
|
||
|
* in *this* cabinet *must* start in the first folder.
|
||
|
*
|
||
|
* NOTE: szCabinetPrev is the name of the cabinet where this file
|
||
|
* *starts*, which is not necessarily the immediately
|
||
|
* preceeding cabinet! Since it only makes sense to
|
||
|
* decompress a file from its start, the starting cabinet
|
||
|
* is what is important!
|
||
|
*
|
||
|
* ifoldCONTINUED_TO_NEXT
|
||
|
* This file starts in this cabinet, but is continued to the next
|
||
|
* cabinet. Therfore, this file must start in the *last* folder
|
||
|
* in this cabinet.
|
||
|
*
|
||
|
* ifoldCONTINUED_PREV_AND_NEXT
|
||
|
* This file is the *middle* portion of a file that started in a
|
||
|
* previous cabinet and is continued in the next cabinet. Since
|
||
|
* this cabinet only contain this piece of a single file, there
|
||
|
* is only a single folder fragment in this cabinet.
|
||
|
*/
|
||
|
typedef struct {
|
||
|
long cbFile; // Uncompressed size of file
|
||
|
|
||
|
UOFF uoffFolderStart; // Offset in folder IN UNCOMPRESSED BYTES
|
||
|
// of the start of this file
|
||
|
|
||
|
USHORT iFolder; // Index of folder containing this file;
|
||
|
// 0 is first folder in this cabinet.
|
||
|
// See ifoldCONTINUED_XXXX values above
|
||
|
// for treatment of continuation files.
|
||
|
|
||
|
USHORT date; // Date stamp in FAT file system format
|
||
|
|
||
|
USHORT time; // Time stamp in FAT file system format
|
||
|
|
||
|
USHORT attribs; // Attribute in FAT file system format
|
||
|
|
||
|
// char szName[]; // File name (may include path characters)
|
||
|
} CFFILE; /* cffile */
|
||
|
|
||
|
|
||
|
/*** CFDATA - Cabinet File structure describing a data block
|
||
|
*
|
||
|
*/
|
||
|
typedef struct {
|
||
|
CHECKSUM csum; // Checksum (excluding this field itself!)
|
||
|
// of this structure and the data that
|
||
|
// follows. If this CFDATA structure is
|
||
|
// continued to the next cabinet, then
|
||
|
// the value of this field is ignored
|
||
|
// (and set to zero).
|
||
|
|
||
|
USHORT cbData; // Size of ab[] data that resides in the
|
||
|
// current cabinet. A CFDATA may be split
|
||
|
// across a cabinet boundary, so this
|
||
|
// value indicates only the amount of data
|
||
|
// store in this cabinet.
|
||
|
|
||
|
USHORT cbUncomp; // Uncompressed size of ab[] data; if this
|
||
|
// CFDATA block is continued to the next
|
||
|
// cabinet, then this value is zero!
|
||
|
// If this CFDATA block the remainder of
|
||
|
// of a CFDATA block that started in the
|
||
|
// previous cabinet, then this value is
|
||
|
// the total size of the uncompressed data
|
||
|
// represented by the two CFDATA blocks!
|
||
|
|
||
|
//** If CFHEADER.flags has the cfhdrRESERVE_PRESENT bit set, and
|
||
|
// CFRESERVE.cbCFData is non-zero, then abReserve[] appears here.
|
||
|
//
|
||
|
// BYTE abReserve[]; // Reserved data space
|
||
|
//
|
||
|
|
||
|
//** The actual data follows here, cbData bytes in length.
|
||
|
//
|
||
|
// BYTE ab[]; // Data
|
||
|
//
|
||
|
} CFDATA; /* cfdata */
|
||
|
|
||
|
|
||
|
|
||
|
//** Attribute Bit to use for Run after extract
|
||
|
#define RUNATTRIB 0x40
|
||
|
|
||
|
|
||
|
//** Revert to default structure packing!
|
||
|
#pragma pack()
|
||
|
|
||
|
#endif // !INCLUDED_CABINET
|