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