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