1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS cabinet manager 4 * FILE: tools/cabman/cabinet.h 5 * PURPOSE: Cabinet definitions 6 */ 7 8 #pragma once 9 10 #if defined(_WIN32) 11 #define WIN32_LEAN_AND_MEAN 12 #include <windows.h> 13 #else 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <sys/types.h> 17 #include <time.h> 18 #include <typedefs.h> 19 #include <unistd.h> 20 #endif 21 22 #include <stdlib.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <limits.h> 26 27 #ifndef PATH_MAX 28 #define PATH_MAX MAX_PATH 29 #endif 30 31 #if defined(_WIN32) 32 #define DIR_SEPARATOR_CHAR '\\' 33 #define DIR_SEPARATOR_STRING "\\" 34 35 #define strcasecmp _stricmp 36 #define strdup _strdup 37 38 #define AllocateMemory(size) HeapAlloc(GetProcessHeap(), 0, size) 39 #define FreeMemory(buffer) HeapFree(GetProcessHeap(), 0, buffer) 40 #define FILEHANDLE HANDLE 41 #define CloseFile(handle) CloseHandle(handle) 42 #else 43 #define DIR_SEPARATOR_CHAR '/' 44 #define DIR_SEPARATOR_STRING "/" 45 46 #define AllocateMemory(size) malloc(size) 47 #define FreeMemory(buffer) free(buffer) 48 #define CloseFile(handle) fclose(handle) 49 #define FILEHANDLE FILE* 50 #endif 51 52 /* Debugging */ 53 54 #define NORMAL_MASK 0x000000FF 55 #define SPECIAL_MASK 0xFFFFFF00 56 #define MIN_TRACE 0x00000001 57 #define MID_TRACE 0x00000002 58 #define MAX_TRACE 0x00000003 59 60 #define DEBUG_MEMORY 0x00000100 61 62 #if DBG 63 64 extern ULONG DebugTraceLevel; 65 66 #undef DPRINT 67 #define DPRINT(_t_, _x_) \ 68 if ((_t_ > NORMAL_MASK) \ 69 ? (DebugTraceLevel & _t_) > NORMAL_MASK \ 70 : (DebugTraceLevel & NORMAL_MASK) >= _t_) { \ 71 printf("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \ 72 printf _x_ ; \ 73 } 74 75 #undef ASSERT 76 #define ASSERT(_b_) { \ 77 if (!(_b_)) { \ 78 printf("(%s:%d)(%s) ASSERTION: ", __FILE__, __LINE__, __FUNCTION__); \ 79 printf(#_b_); \ 80 exit(0); \ 81 } \ 82 } 83 84 #else /* DBG */ 85 86 #undef DPRINT 87 #define DPRINT(_t_, _x_) do { } while(0) 88 89 #undef ASSERT 90 #define ASSERT(_x_) 91 92 #endif /* DBG */ 93 94 95 /* Cabinet constants */ 96 97 #define CAB_SIGNATURE 0x4643534D // "MSCF" 98 #define CAB_VERSION 0x0103 99 #define CAB_BLOCKSIZE 32768 100 101 #define CAB_COMP_MASK 0x00FF 102 #define CAB_COMP_NONE 0x0000 103 #define CAB_COMP_MSZIP 0x0001 104 #define CAB_COMP_QUANTUM 0x0002 105 #define CAB_COMP_LZX 0x0003 106 107 #define CAB_FLAG_HASPREV 0x0001 108 #define CAB_FLAG_HASNEXT 0x0002 109 #define CAB_FLAG_RESERVE 0x0004 110 111 #define CAB_ATTRIB_READONLY 0x0001 112 #define CAB_ATTRIB_HIDDEN 0x0002 113 #define CAB_ATTRIB_SYSTEM 0x0004 114 #define CAB_ATTRIB_VOLUME 0x0008 115 #define CAB_ATTRIB_DIRECTORY 0x0010 116 #define CAB_ATTRIB_ARCHIVE 0x0020 117 #define CAB_ATTRIB_EXECUTE 0x0040 118 #define CAB_ATTRIB_UTF_NAME 0x0080 119 120 #define CAB_FILE_MAX_FOLDER 0xFFFC 121 #define CAB_FILE_CONTINUED 0xFFFD 122 #define CAB_FILE_SPLIT 0xFFFE 123 #define CAB_FILE_PREV_NEXT 0xFFFF 124 125 126 /* Cabinet structures */ 127 128 typedef struct _CFHEADER 129 { 130 ULONG Signature; // File signature 'MSCF' (CAB_SIGNATURE) 131 ULONG Reserved1; // Reserved field 132 ULONG CabinetSize; // Cabinet file size 133 ULONG Reserved2; // Reserved field 134 ULONG FileTableOffset; // Offset of first CFFILE 135 ULONG Reserved3; // Reserved field 136 USHORT Version; // Cabinet version (CAB_VERSION) 137 USHORT FolderCount; // Number of folders 138 USHORT FileCount; // Number of files 139 USHORT Flags; // Cabinet flags (CAB_FLAG_*) 140 USHORT SetID; // Cabinet set id 141 USHORT CabinetNumber; // Zero-based cabinet number 142 /* Optional fields (depends on Flags) 143 USHORT CabinetResSize // Per-cabinet reserved area size 144 char FolderResSize // Per-folder reserved area size 145 char FileResSize // Per-file reserved area size 146 char CabinetReserved[] // Per-cabinet reserved area 147 char CabinetPrev[] // Name of previous cabinet file 148 char DiskPrev[] // Name of previous disk 149 char CabinetNext[] // Name of next cabinet file 150 char DiskNext[] // Name of next disk 151 */ 152 } CFHEADER, *PCFHEADER; 153 154 155 typedef struct _CFFOLDER 156 { 157 ULONG DataOffset; // Absolute offset of first CFDATA block in this folder 158 USHORT DataBlockCount; // Number of CFDATA blocks in this folder in this cabinet 159 USHORT CompressionType; // Type of compression used for all CFDATA blocks in this folder 160 /* Optional fields (depends on Flags) 161 char FolderReserved[] // Per-folder reserved area 162 */ 163 } CFFOLDER, *PCFFOLDER; 164 165 166 typedef struct _CFFILE 167 { 168 ULONG FileSize; // Uncompressed file size in bytes 169 ULONG FileOffset; // Uncompressed offset of file in the folder 170 USHORT FileControlID; // File control ID (CAB_FILE_*) 171 USHORT FileDate; // File date stamp, as used by DOS 172 USHORT FileTime; // File time stamp, as used by DOS 173 USHORT Attributes; // File attributes (CAB_ATTRIB_*) 174 /* After this is the NULL terminated filename */ 175 } CFFILE, *PCFFILE; 176 177 178 typedef struct _CFDATA 179 { 180 ULONG Checksum; // Checksum of CFDATA entry 181 USHORT CompSize; // Number of compressed bytes in this block 182 USHORT UncompSize; // Number of uncompressed bytes in this block 183 /* Optional fields (depends on Flags) 184 char DataReserved[] // Per-datablock reserved area 185 */ 186 } CFDATA, *PCFDATA; 187 188 typedef struct _CFDATA_NODE 189 { 190 struct _CFDATA_NODE *Next; 191 struct _CFDATA_NODE *Prev; 192 ULONG ScratchFilePosition; // Absolute offset in scratch file 193 ULONG AbsoluteOffset; // Absolute offset in cabinet 194 ULONG UncompOffset; // Uncompressed offset in folder 195 CFDATA Data; 196 } CFDATA_NODE, *PCFDATA_NODE; 197 198 typedef struct _CFFOLDER_NODE 199 { 200 struct _CFFOLDER_NODE *Next; 201 struct _CFFOLDER_NODE *Prev; 202 ULONG UncompOffset; // File size accumulator 203 ULONG AbsoluteOffset; 204 ULONG TotalFolderSize; // Total size of folder in current disk 205 PCFDATA_NODE DataListHead; 206 PCFDATA_NODE DataListTail; 207 ULONG Index; 208 bool Commit; // true if the folder should be committed 209 bool Delete; // true if marked for deletion 210 CFFOLDER Folder; 211 } CFFOLDER_NODE, *PCFFOLDER_NODE; 212 213 typedef struct _CFFILE_NODE 214 { 215 struct _CFFILE_NODE *Next; 216 struct _CFFILE_NODE *Prev; 217 CFFILE File; 218 char* FileName; 219 PCFDATA_NODE DataBlock; // First data block of file. NULL if not known 220 bool Commit; // true if the file data should be committed 221 bool Delete; // true if marked for deletion 222 PCFFOLDER_NODE FolderNode; // Folder this file belong to 223 } CFFILE_NODE, *PCFFILE_NODE; 224 225 typedef struct _SEARCH_CRITERIA 226 { 227 struct _SEARCH_CRITERIA *Next; // Pointer to next search criteria 228 struct _SEARCH_CRITERIA *Prev; // Pointer to previous search criteria 229 char* Search; // The actual search criteria 230 } SEARCH_CRITERIA, *PSEARCH_CRITERIA; 231 232 typedef struct _CAB_SEARCH 233 { 234 PCFFILE_NODE Next; // Pointer to next node 235 PCFFILE File; // Pointer to current CFFILE 236 char* FileName; // Current filename 237 } CAB_SEARCH, *PCAB_SEARCH; 238 239 240 /* Constants */ 241 242 /* Status codes */ 243 #define CAB_STATUS_SUCCESS 0x00000000 244 #define CAB_STATUS_FAILURE 0x00000001 245 #define CAB_STATUS_NOMEMORY 0x00000002 246 #define CAB_STATUS_CANNOT_OPEN 0x00000003 247 #define CAB_STATUS_CANNOT_CREATE 0x00000004 248 #define CAB_STATUS_CANNOT_READ 0x00000005 249 #define CAB_STATUS_CANNOT_WRITE 0x00000006 250 #define CAB_STATUS_FILE_EXISTS 0x00000007 251 #define CAB_STATUS_INVALID_CAB 0x00000008 252 #define CAB_STATUS_NOFILE 0x00000009 253 #define CAB_STATUS_UNSUPPCOMP 0x0000000A 254 255 256 257 /* Codecs */ 258 259 class CCABCodec 260 { 261 public: 262 /* Default constructor */ 263 CCABCodec() {}; 264 /* Default destructor */ 265 virtual ~CCABCodec() {}; 266 /* Compresses a data block */ 267 virtual ULONG Compress(void* OutputBuffer, 268 void* InputBuffer, 269 ULONG InputLength, 270 PULONG OutputLength) = 0; 271 /* Uncompresses a data block */ 272 virtual ULONG Uncompress(void* OutputBuffer, 273 void* InputBuffer, 274 ULONG InputLength, 275 PULONG OutputLength) = 0; 276 }; 277 278 279 /* Codec status codes */ 280 #define CS_SUCCESS 0x0000 /* All data consumed */ 281 #define CS_NOMEMORY 0x0001 /* Not enough free memory */ 282 #define CS_BADSTREAM 0x0002 /* Bad data stream */ 283 284 285 /* Codec indentifiers */ 286 #define CAB_CODEC_RAW 0x00 287 #define CAB_CODEC_LZX 0x01 288 #define CAB_CODEC_MSZIP 0x02 289 290 291 292 /* Classes */ 293 294 #ifndef CAB_READ_ONLY 295 296 class CCFDATAStorage 297 { 298 public: 299 /* Default constructor */ 300 CCFDATAStorage(); 301 /* Default destructor */ 302 virtual ~CCFDATAStorage(); 303 ULONG Create(); 304 ULONG Destroy(); 305 ULONG Truncate(); 306 ULONG Position(); 307 ULONG Seek(LONG Position); 308 ULONG ReadBlock(PCFDATA Data, void* Buffer, PULONG BytesRead); 309 ULONG WriteBlock(PCFDATA Data, void* Buffer, PULONG BytesWritten); 310 private: 311 char FullName[PATH_MAX]; 312 bool FileCreated; 313 FILEHANDLE FileHandle; 314 }; 315 316 #endif /* CAB_READ_ONLY */ 317 318 class CCabinet 319 { 320 public: 321 /* Default constructor */ 322 CCabinet(); 323 /* Default destructor */ 324 virtual ~CCabinet(); 325 /* Determines if a character is a separator */ 326 bool IsSeparator(char Char); 327 /* Replaces \ or / with the one used be the host environment */ 328 char* ConvertPath(char* Path, bool Allocate); 329 /* Returns a pointer to the filename part of a fully qualified filename */ 330 char* GetFileName(char* Path); 331 /* Removes a filename from a fully qualified filename */ 332 void RemoveFileName(char* Path); 333 /* Normalizes a path */ 334 bool NormalizePath(char* Path, ULONG Length); 335 /* Returns name of cabinet file */ 336 char* GetCabinetName(); 337 /* Sets the name of the cabinet file */ 338 void SetCabinetName(char* FileName); 339 /* Sets destination path for extracted files */ 340 void SetDestinationPath(char* DestinationPath); 341 /* Sets cabinet reserved file */ 342 bool SetCabinetReservedFile(char* FileName); 343 /* Returns cabinet reserved file */ 344 char* GetCabinetReservedFile(); 345 /* Returns destination path */ 346 char* GetDestinationPath(); 347 /* Returns zero-based current disk number */ 348 ULONG GetCurrentDiskNumber(); 349 /* Opens the current cabinet file */ 350 ULONG Open(); 351 /* Closes the current open cabinet file */ 352 void Close(); 353 /* Locates the first file in the current cabinet file that matches a search criteria */ 354 ULONG FindFirst(PCAB_SEARCH Search); 355 /* Locates the next file in the current cabinet file */ 356 ULONG FindNext(PCAB_SEARCH Search); 357 /* Extracts a file from the current cabinet file */ 358 ULONG ExtractFile(char* FileName); 359 /* Select codec engine to use */ 360 void SelectCodec(LONG Id); 361 /* Returns whether a codec engine is selected */ 362 bool IsCodecSelected(); 363 /* Adds a search criteria for adding files to a simple cabinet, displaying files in a cabinet or extracting them */ 364 ULONG AddSearchCriteria(char* SearchCriteria); 365 /* Destroys the search criteria list */ 366 void DestroySearchCriteria(); 367 /* Returns whether we have search criteria */ 368 bool HasSearchCriteria(); 369 370 #ifndef CAB_READ_ONLY 371 /* Creates a simple cabinet based on the search criteria data */ 372 bool CreateSimpleCabinet(); 373 /* Sets the codec to use for compression (based on a string value) */ 374 bool SetCompressionCodec(char* CodecName); 375 /* Creates a new cabinet file */ 376 ULONG NewCabinet(); 377 /* Forces a new disk to be created */ 378 ULONG NewDisk(); 379 /* Forces a new folder to be created */ 380 ULONG NewFolder(); 381 /* Writes a file to scratch storage */ 382 ULONG WriteFileToScratchStorage(PCFFILE_NODE FileNode); 383 /* Forces the current disk to be written */ 384 ULONG WriteDisk(ULONG MoreDisks); 385 /* Commits the current disk */ 386 ULONG CommitDisk(ULONG MoreDisks); 387 /* Closes the current disk */ 388 ULONG CloseDisk(); 389 /* Closes the current cabinet */ 390 ULONG CloseCabinet(); 391 /* Adds a file to the current disk */ 392 ULONG AddFile(char* FileName); 393 /* Sets the maximum size of the current disk */ 394 void SetMaxDiskSize(ULONG Size); 395 #endif /* CAB_READ_ONLY */ 396 397 /* Default event handlers */ 398 399 /* Handler called when a file is about to be overridden */ 400 virtual bool OnOverwrite(PCFFILE Entry, char* FileName); 401 /* Handler called when a file is about to be extracted */ 402 virtual void OnExtract(PCFFILE Entry, char* FileName); 403 /* Handler called when a new disk is to be processed */ 404 virtual void OnDiskChange(char* CabinetName, char* DiskLabel); 405 #ifndef CAB_READ_ONLY 406 /* Handler called when a file is about to be added */ 407 virtual void OnAdd(PCFFILE Entry, char* FileName); 408 /* Handler called when a cabinet need a name */ 409 virtual bool OnCabinetName(ULONG Number, char* Name); 410 /* Handler called when a disk needs a label */ 411 virtual bool OnDiskLabel(ULONG Number, char* Label); 412 #endif /* CAB_READ_ONLY */ 413 private: 414 PCFFOLDER_NODE LocateFolderNode(ULONG Index); 415 ULONG GetAbsoluteOffset(PCFFILE_NODE File); 416 ULONG LocateFile(char* FileName, PCFFILE_NODE *File); 417 ULONG ReadString(char* String, LONG MaxLength); 418 ULONG ReadFileTable(); 419 ULONG ReadDataBlocks(PCFFOLDER_NODE FolderNode); 420 PCFFOLDER_NODE NewFolderNode(); 421 PCFFILE_NODE NewFileNode(); 422 PCFDATA_NODE NewDataNode(PCFFOLDER_NODE FolderNode); 423 void DestroyDataNodes(PCFFOLDER_NODE FolderNode); 424 void DestroyFileNodes(); 425 void DestroyDeletedFileNodes(); 426 void DestroyFolderNodes(); 427 void DestroyDeletedFolderNodes(); 428 ULONG ComputeChecksum(void* Buffer, ULONG Size, ULONG Seed); 429 ULONG ReadBlock(void* Buffer, ULONG Size, PULONG BytesRead); 430 bool MatchFileNamePattern(char* FileName, char* Pattern); 431 #ifndef CAB_READ_ONLY 432 ULONG InitCabinetHeader(); 433 ULONG WriteCabinetHeader(bool MoreDisks); 434 ULONG WriteFolderEntries(); 435 ULONG WriteFileEntries(); 436 ULONG CommitDataBlocks(PCFFOLDER_NODE FolderNode); 437 ULONG WriteDataBlock(); 438 ULONG GetAttributesOnFile(PCFFILE_NODE File); 439 ULONG SetAttributesOnFile(char* FileName, USHORT FileAttributes); 440 ULONG GetFileTimes(FILEHANDLE FileHandle, PCFFILE_NODE File); 441 #if !defined(_WIN32) 442 void ConvertDateAndTime(time_t* Time, PUSHORT DosDate, PUSHORT DosTime); 443 #endif 444 #endif /* CAB_READ_ONLY */ 445 ULONG CurrentDiskNumber; // Zero based disk number 446 char CabinetName[256]; // Filename of current cabinet 447 char CabinetPrev[256]; // Filename of previous cabinet 448 char DiskPrev[256]; // Label of cabinet in file CabinetPrev 449 char CabinetNext[256]; // Filename of next cabinet 450 char DiskNext[256]; // Label of cabinet in file CabinetNext 451 ULONG TotalHeaderSize; // Size of header and optional fields 452 ULONG NextFieldsSize; // Size of next cabinet name and next disk label 453 ULONG TotalFolderSize; // Size of all folder entries 454 ULONG TotalFileSize; // Size of all file entries 455 ULONG FolderUncompSize; // Uncompressed size of folder 456 ULONG BytesLeftInBlock; // Number of bytes left in current block 457 bool ReuseBlock; 458 char DestPath[PATH_MAX]; 459 char CabinetReservedFile[PATH_MAX]; 460 void* CabinetReservedFileBuffer; 461 ULONG CabinetReservedFileSize; 462 FILEHANDLE FileHandle; 463 bool FileOpen; 464 CFHEADER CABHeader; 465 ULONG CabinetReserved; 466 ULONG FolderReserved; 467 ULONG DataReserved; 468 PCFFOLDER_NODE FolderListHead; 469 PCFFOLDER_NODE FolderListTail; 470 PCFFOLDER_NODE CurrentFolderNode; 471 PCFDATA_NODE CurrentDataNode; 472 PCFFILE_NODE FileListHead; 473 PCFFILE_NODE FileListTail; 474 PSEARCH_CRITERIA CriteriaListHead; 475 PSEARCH_CRITERIA CriteriaListTail; 476 CCABCodec *Codec; 477 LONG CodecId; 478 bool CodecSelected; 479 void* InputBuffer; 480 void* CurrentIBuffer; // Current offset in input buffer 481 ULONG CurrentIBufferSize; // Bytes left in input buffer 482 void* OutputBuffer; 483 ULONG TotalCompSize; // Total size of current CFDATA block 484 void* CurrentOBuffer; // Current offset in output buffer 485 ULONG CurrentOBufferSize; // Bytes left in output buffer 486 ULONG BytesLeftInCabinet; 487 bool RestartSearch; 488 ULONG LastFileOffset; // Uncompressed offset of last extracted file 489 #ifndef CAB_READ_ONLY 490 ULONG LastBlockStart; // Uncompressed offset of last block in folder 491 ULONG MaxDiskSize; 492 ULONG DiskSize; 493 ULONG PrevCabinetNumber; // Previous cabinet number (where split file starts) 494 bool CreateNewDisk; 495 bool CreateNewFolder; 496 497 CCFDATAStorage *ScratchFile; 498 FILEHANDLE SourceFile; 499 bool ContinueFile; 500 ULONG TotalBytesLeft; 501 bool BlockIsSplit; // true if current data block is split 502 ULONG NextFolderNumber; // Zero based folder number 503 #endif /* CAB_READ_ONLY */ 504 }; 505 506 /* EOF */ 507