//+------------------------------------------------------------------------- // // 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