Files
XBDM/xbdm/imp/xcabinet.h
2025-11-06 15:36:24 -05:00

363 lines
11 KiB
C

// ---------------------------------------------------------------------------------------
// xcabinet.h
//
// Copyright (C) Microsoft Corporation
// ---------------------------------------------------------------------------------------
#ifndef __XCABINET_H__
#define __XCABINET_H__
// ---------------------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
#include "xecrypt.h"
#include "cabinet.h"
#ifdef __cplusplus
}
#endif
#pragma pack(push, 1)
// ---------------------------------------------------------------------------------------
//
// Define the real RC4 SHA1 structures and functions
//
#define RC4_CONFOUNDER_LEN 8
typedef struct _RC4_SHA_HEADER {
BYTE Checksum[XECRYPT_SHA_DIGEST_SIZE];
BYTE Confounder[RC4_CONFOUNDER_LEN];
} RC4_SHA_HEADER, *PRC4_SHA_HEADER;
//
// Define a structure that describes an extended CFFOLDER entry
// that also has an associated HMAC (per-folder reserved data)
//
typedef struct
{
CFFOLDER cffolder; // CFFOLDER
RC4_SHA_HEADER hmac; // RC4 SHA1 Hmac
} CFFOLDER_HMAC, *PCFFOLDER_HMAC;
//
// Define a union of all known CAB flags
//
#define cfhdrFLAGS_ALL (cfhdrPREV_CABINET | \
cfhdrNEXT_CABINET | \
cfhdrRESERVE_PRESENT)
//
// Define our header cache structure
//
typedef struct
{
CFHEADER cfheader; // Cabinet file header
CFRESERVE cfreserve; // Reserved data specification
RC4_SHA_HEADER digestFolders; // CFFOLDERS digest
RC4_SHA_HEADER digestFiles; // CFFILES digest
} XONLINECONTENT_HEADER, *PXONLINECONTENT_HEADER;
//
// Define sizes related to the fixed header
//
#define XONLINECONTENT_FIXED_HEADER_SIZE \
(sizeof(XONLINECONTENT_HEADER))
#define XONLINECONTENT_FIXED_HEADER_SIZE_WITH_HMAC \
(XONLINECONTENT_FIXED_HEADER_SIZE + \
sizeof(RC4_SHA_HEADER))
#define XONLINECONTENT_FIXED_HEADER_SIZE_WITH_HMAC_AND_CHECKPOINT \
(XONLINECONTENT_FIXED_HEADER_SIZE + \
sizeof(RC4_SHA_HEADER) + sizeof(DWORD))
#define XONLINECONTENT_COMPLETE_HEADER_SIZE \
(XONLINECONTENT_FIXED_HEADER_SIZE_WITH_HMAC_AND_CHECKPOINT + \
XONLINECONTENT_PK_SIGNATURE_SIZE)
#define XONLINECONTENT_CHECKPOINT \
(XONLINECONTENT_FIXED_HEADER_SIZE + \
sizeof(RC4_SHA_HEADER))
//
// Define the maximum number of CFFOLDER entries allowed in a content package.
//
#define XONLINECONTENT_MAX_CFFOLDER ((DWORD)100)
//
// Define a threshold size for the minimum folder size to justify the
// additional folder overhead.
//
#define XONLINECONTENT_MIN_FOLDER_SIZE ((DWORD)(5 * 1024)) // 5KB
//
// Define the "attribute" flag to indicate that the current folder is a
// continuation from the same file in the previous folder.
//
#define XONLINECONTENT_FOLDER_CONTINUATION ((WORD)0x8000)
//
// Define the minimum size for a CFFILE entry (+ 2 == one character name + NULL
// terminator).
//
#define XONLINECONTENT_MIN_CFFILE_SIZE ((DWORD)(sizeof(CFFILE) + 2))
//
// Define the maximum number of CFFILE entries allowed in a content package.
//
#define XONLINECONTENT_MAX_CFFILE ((DWORD)1000000)
C_ASSERT(XONLINECONTENT_MAX_CFFILE <= (0xFFFFFFFF / XONLINECONTENT_MIN_CFFILE_SIZE));
//
// Define the size of a PK signature.
//
#define XONLINECONTENT_PK_SIGNATURE_SIZE 256
#ifndef BSAFE_PUB_KEY
//
// BUGBUG:
//
// BSAFE_PUB_KEY not defined in XeCrypt yet, so we define it here
//
typedef struct {
DWORD magic; /* Should always be RSA1 */
DWORD keylen; // size of modulus buffer
DWORD bitlen; // # of bits in modulus
DWORD datalen; // max number of bytes to be encoded
DWORD pubexp; //public exponent
} BSAFE_PUB_KEY, FAR *LPBSAFE_PUB_KEY;
#endif
//
// Define the max size of a public key
//
#define XONLINECONTENT_MAX_PUBLIC_KEY_SIZE \
(XONLINECONTENT_PK_SIGNATURE_SIZE + \
sizeof(BSAFE_PUB_KEY) + \
(sizeof(DWORD) * 4))
//
// Define the various reserve values
//
#define XONLINECONTENT_HEADER_RESERVE_SIZE \
((sizeof(RC4_SHA_HEADER) * 3) + sizeof(DWORD) + \
XONLINECONTENT_PK_SIGNATURE_SIZE)
#define XONLINECONTENT_PERFOLDER_RESERVE_SIZE \
(sizeof(RC4_SHA_HEADER))
//
// Define the smallest possible size for a content package
//
#define XONLINECONTENT_MIN_CONTENT_SIZE \
(sizeof(CFHEADER) + sizeof(CFRESERVE) + \
XONLINECONTENT_HEADER_RESERVE_SIZE)
//
// Define a confounder for the version stamp
//
#define XONLINECONTENT_CHECKPOINT_CONFOUNDER ((DWORD)0x5aef320b)
//
// Define the prefix for files with special installation meaning
//
#define XINSTALLER_SPECIAL_NAME_PREFIX "$install_"
//
// Define the fixed name of the package within the CAB
//
#define XINSTALLER_PACKAGE_FILE_NAME "$package"
//
// Define the installation extender prefix and suffix
//
#define XINSTALLER_EXTENDER_FILE_NAME_PREFIX XINSTALLER_SPECIAL_NAME_PREFIX
#define XINSTALLER_EXTENDER_FILE_NAME_SUFFIX ".xex"
//
// We deal with clusters a lot, so define the size of a cluster
//
#define XBOX_CLUSTER_SIZE (1 << 14)
// ---------------------------------------------------------------------------------------
typedef enum _XONLINECONTENT_RESUME_STATE
{
XONLINECONTENT_RESUME_STATE_FILE_HEADERS_NOT_READY = 'FILH',
XONLINECONTENT_RESUME_STATE_NEW_FOLDER = 'FOLD',
XONLINECONTENT_RESUME_STATE_NEW_FOLDER_RESUME_ATTEMPT_2 = 'FOL2',
XONLINECONTENT_RESUME_STATE_NEW_FOLDER_RESUME_ATTEMPT_3 = 'FOL3',
} XONLINECONTENT_RESUME_STATE;
typedef struct _XONLINECONTENT_RESUME_HEADER {
//
// Resume state identifier.
//
XONLINECONTENT_RESUME_STATE ResumeState;
//
// Index of current file being downloaded/processed.
//
DWORD dwCurrentFileIndex;
//
// Offset into current file being downloaded/processed.
//
LARGE_INTEGER liCurrentFileOffset;
//
// Number of bytes successfully downloaded/processed.
//
LARGE_INTEGER liBytesProcessed;
//
// Last-modified timestamp for resuming download/processing.
//
LARGE_INTEGER liLastModified;
} XONLINECONTENT_RESUME_HEADER;
#define XONLINECONTENT_MAX_SINGLE_FILE_RESUME_DATA_SIZE \
(XONLINECONTENT_COMPLETE_HEADER_SIZE + \
(XONLINECONTENT_MAX_CFFOLDER * sizeof(CFFOLDER_HMAC)) + \
(XONLINECONTENT_MAX_CFFOLDER * sizeof(CFFILE)))
// ---------------------------------------------------------------------------------------
//
// Content delivery
//
//
// The CFFILE structure has a WORD field for the file time which
// we will hijack for our special flags. Xbox content will use thie
// field to indicate special options instead of the file time.
// The following bits are defined for the time field, and honored
// by the content installation API.
//
// This flag indicates that the file should be copied to the
// user partition rather than the title area
#define XONLINECONTENT_A_USER_DATA (0x0001)
// This flag indicates that this file is a continuation of
// a file in the previous folder. The data in this file should
// be appended to the previous file. This file must be the first
// file in the folder.
#define XONLINECONTENT_A_CONTINUED_FROM_PREV (0x0002)
// This flag indicates that this file will be continued into the
// next folder. The data in the next folder should be appended to
// this file. This file must be the last file in the folder.
#define XONLINECONTENT_A_CONTINUED_INTO_NEXT (0x0004)
//
// Define the size of the download buffer. This cannot be
// less than XONLINECONTENT_LZX_OUTPUT_SIZE
//
#define XONLINECONTENT_DL_BUFFER_SIZE (1024 * 64)
//
// Define the LZX decoder history window size, this should be no
// less than 32k (ROM decompressor uses 128k)
//
#define XONLINECONTENT_LZX_WINDOW_SIZE CHUNK_SIZE
//
// Define the output buffer for decompress. This must not be
// less than 32k
//#define XONLINECONTENT_LZX_OUTPUT_SIZE \
// ((CHUNK_SIZE) + XBOX_HD_SECTOR_SIZE)
#define XONLINECONTENT_LZX_OUTPUT_SIZE \
(CHUNK_SIZE)
//
// TODO: From \public\i386\sdk\inc\fdi.h. Need byte reversal?
//
/*** tcompXXX - Diamond compression types
*
* These are passed to FCIAddFile(), and are also stored in the CFFOLDER
* structures in cabinet files.
*
* NOTE: We reserve bits for the TYPE, QUANTUM_LEVEL, and QUANTUM_MEM
* to provide room for future expansion. Since this value is stored
* in the CFDATA records in the cabinet file, we don't want to
* have to change the format for existing compression configurations
* if we add new ones in the future. This will allows us to read
* old cabinet files in the future.
*/
typedef unsigned short TCOMP; /* tcomp */
#define tcompMASK_TYPE 0x000F // Mask for compression type
#define tcompTYPE_NONE 0x0000 // No compression
#define tcompTYPE_MSZIP 0x0001 // MSZIP
#define tcompTYPE_QUANTUM 0x0002 // Quantum
#define tcompTYPE_LZX 0x0003 // LZX
#define tcompBAD 0x000F // Unspecified compression type
#define tcompMASK_LZX_WINDOW 0x1F00 // Mask for LZX Compression Memory
#define tcompLZX_WINDOW_LO 0x0F00 // Lowest LZX Memory (15)
#define tcompLZX_WINDOW_HI 0x1500 // Highest LZX Memory (21)
#define tcompSHIFT_LZX_WINDOW 8 // Amount to shift over to get int
#define tcompMASK_QUANTUM_LEVEL 0x00F0 // Mask for Quantum Compression Level
#define tcompQUANTUM_LEVEL_LO 0x0010 // Lowest Quantum Level (1)
#define tcompQUANTUM_LEVEL_HI 0x0070 // Highest Quantum Level (7)
#define tcompSHIFT_QUANTUM_LEVEL 4 // Amount to shift over to get int
#define tcompMASK_QUANTUM_MEM 0x1F00 // Mask for Quantum Compression Memory
#define tcompQUANTUM_MEM_LO 0x0A00 // Lowest Quantum Memory (10)
#define tcompQUANTUM_MEM_HI 0x1500 // Highest Quantum Memory (21)
#define tcompSHIFT_QUANTUM_MEM 8 // Amount to shift over to get int
#define tcompMASK_RESERVED 0xE000 // Reserved bits (high 3 bits)
#define CompressionTypeFromTCOMP(tc) \
((tc) & tcompMASK_TYPE)
#define CompressionLevelFromTCOMP(tc) \
(((tc) & tcompMASK_QUANTUM_LEVEL) >> tcompSHIFT_QUANTUM_LEVEL)
#define CompressionMemoryFromTCOMP(tc) \
(((tc) & tcompMASK_QUANTUM_MEM) >> tcompSHIFT_QUANTUM_MEM)
#define TCOMPfromTypeLevelMemory(t,l,m) \
(((m) << tcompSHIFT_QUANTUM_MEM ) | \
((l) << tcompSHIFT_QUANTUM_LEVEL) | \
( t ))
#define LZXCompressionWindowFromTCOMP(tc) \
(((tc) & tcompMASK_LZX_WINDOW) >> tcompSHIFT_LZX_WINDOW)
#define TCOMPfromLZXWindow(w) \
(((w) << tcompSHIFT_LZX_WINDOW ) | \
( tcompTYPE_LZX ))
#pragma pack(pop)
#endif // ! defined __XCABINET_H__