2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS cabinet manager
4 * FILE: tools/cabman/cabinet.h
5 * PURPOSE: Cabinet definitions
15 #include <sys/types.h>
27 #define DIR_SEPARATOR_CHAR '\\'
28 #define DIR_SEPARATOR_STRING "\\"
30 #define strcasecmp strcmpi
31 #define AllocateMemory(size) HeapAlloc(GetProcessHeap(), 0, size)
32 #define FreeMemory(buffer) HeapFree(GetProcessHeap(), 0, buffer)
33 #define FILEHANDLE HANDLE
34 #define CloseFile(handle) CloseHandle(handle)
35 #define GetSizeOfFile(handle) _GetSizeOfFile(handle)
36 static long _GetSizeOfFile(FILEHANDLE handle)
38 long size = GetFileSize(handle, NULL);
39 if (size == INVALID_FILE_SIZE)
45 #define ReadFileData(handle, buffer, size, bytesread) _ReadFileData(handle, buffer, size, bytesread)
46 static bool _ReadFileData(FILEHANDLE handle, void* buffer, unsigned long size, unsigned long* bytesread)
48 return ReadFile(handle, buffer, size, bytesread, NULL);
51 #define DIR_SEPARATOR_CHAR '/'
52 #define DIR_SEPARATOR_STRING "/"
54 #define AllocateMemory(size) malloc(size)
55 #define FreeMemory(buffer) free(buffer)
56 #define CloseFile(handle) fclose(handle)
57 #define FILEHANDLE FILE*
58 #define GetSizeOfFile(handle) _GetSizeOfFile(handle)
59 static long _GetSizeOfFile(FILEHANDLE handle)
62 fseek(handle, 0, SEEK_END);
64 fseek(handle, 0, SEEK_SET);
67 #define ReadFileData(handle, buffer, size, bytesread) _ReadFileData(handle, buffer, size, bytesread)
68 static bool _ReadFileData(FILEHANDLE handle, void* buffer, unsigned long size, unsigned long* bytesread)
70 *bytesread = fread(buffer, 1, size, handle);
71 return *bytesread == size;
79 #define NORMAL_MASK 0x000000FF
80 #define SPECIAL_MASK 0xFFFFFF00
81 #define MIN_TRACE 0x00000001
82 #define MID_TRACE 0x00000002
83 #define MAX_TRACE 0x00000003
85 #define DEBUG_MEMORY 0x00000100
89 extern unsigned long DebugTraceLevel;
91 #define DPRINT(_t_, _x_) \
92 if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
93 ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
94 printf("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
98 #define ASSERT(_b_) { \
100 printf("(%s:%d)(%s) ASSERTION: ", __FILE__, __LINE__, __FUNCTION__); \
108 #define DPRINT(_t_, _x_)
115 /* Cabinet constants */
117 #define CAB_SIGNATURE 0x4643534D // "MSCF"
118 #define CAB_VERSION 0x0103
119 #define CAB_BLOCKSIZE 32768
121 #define CAB_COMP_MASK 0x00FF
122 #define CAB_COMP_NONE 0x0000
123 #define CAB_COMP_MSZIP 0x0001
124 #define CAB_COMP_QUANTUM 0x0002
125 #define CAB_COMP_LZX 0x0003
127 #define CAB_FLAG_HASPREV 0x0001
128 #define CAB_FLAG_HASNEXT 0x0002
129 #define CAB_FLAG_RESERVE 0x0004
131 #define CAB_ATTRIB_READONLY 0x0001
132 #define CAB_ATTRIB_HIDDEN 0x0002
133 #define CAB_ATTRIB_SYSTEM 0x0004
134 #define CAB_ATTRIB_VOLUME 0x0008
135 #define CAB_ATTRIB_DIRECTORY 0x0010
136 #define CAB_ATTRIB_ARCHIVE 0x0020
137 #define CAB_ATTRIB_EXECUTE 0x0040
138 #define CAB_ATTRIB_UTF_NAME 0x0080
140 #define CAB_FILE_MAX_FOLDER 0xFFFC
141 #define CAB_FILE_CONTINUED 0xFFFD
142 #define CAB_FILE_SPLIT 0xFFFE
143 #define CAB_FILE_PREV_NEXT 0xFFFF
146 /* Cabinet structures */
148 typedef struct _CFHEADER
150 unsigned long Signature; // File signature 'MSCF' (CAB_SIGNATURE)
151 unsigned long Reserved1; // Reserved field
152 unsigned long CabinetSize; // Cabinet file size
153 unsigned long Reserved2; // Reserved field
154 unsigned long FileTableOffset; // Offset of first CFFILE
155 unsigned long Reserved3; // Reserved field
156 unsigned short Version; // Cabinet version (CAB_VERSION)
157 unsigned short FolderCount; // Number of folders
158 unsigned short FileCount; // Number of files
159 unsigned short Flags; // Cabinet flags (CAB_FLAG_*)
160 unsigned short SetID; // Cabinet set id
161 unsigned short CabinetNumber; // Zero-based cabinet number
162 /* Optional fields (depends on Flags)
163 unsigned short CabinetResSize // Per-cabinet reserved area size
164 char FolderResSize // Per-folder reserved area size
165 char FileResSize // Per-file reserved area size
166 char CabinetReserved[] // Per-cabinet reserved area
167 char CabinetPrev[] // Name of previous cabinet file
168 char DiskPrev[] // Name of previous disk
169 char CabinetNext[] // Name of next cabinet file
170 char DiskNext[] // Name of next disk
172 } CFHEADER, *PCFHEADER;
175 typedef struct _CFFOLDER
177 unsigned long DataOffset; // Absolute offset of first CFDATA block in this folder
178 unsigned short DataBlockCount; // Number of CFDATA blocks in this folder in this cabinet
179 unsigned short CompressionType; // Type of compression used for all CFDATA blocks in this folder
180 /* Optional fields (depends on Flags)
181 char FolderReserved[] // Per-folder reserved area
183 } CFFOLDER, *PCFFOLDER;
186 typedef struct _CFFILE
188 unsigned long FileSize; // Uncompressed file size in bytes
189 unsigned long FileOffset; // Uncompressed offset of file in the folder
190 unsigned short FileControlID; // File control ID (CAB_FILE_*)
191 unsigned short FileDate; // File date stamp, as used by DOS
192 unsigned short FileTime; // File time stamp, as used by DOS
193 unsigned short Attributes; // File attributes (CAB_ATTRIB_*)
194 /* After this is the NULL terminated filename */
198 typedef struct _CFDATA
200 unsigned long Checksum; // Checksum of CFDATA entry
201 unsigned short CompSize; // Number of compressed bytes in this block
202 unsigned short UncompSize; // Number of uncompressed bytes in this block
203 /* Optional fields (depends on Flags)
204 char DataReserved[] // Per-datablock reserved area
208 typedef struct _CFDATA_NODE
210 struct _CFDATA_NODE *Next;
211 struct _CFDATA_NODE *Prev;
212 unsigned long ScratchFilePosition; // Absolute offset in scratch file
213 unsigned long AbsoluteOffset; // Absolute offset in cabinet
214 unsigned long UncompOffset; // Uncompressed offset in folder
216 } CFDATA_NODE, *PCFDATA_NODE;
218 typedef struct _CFFOLDER_NODE
220 struct _CFFOLDER_NODE *Next;
221 struct _CFFOLDER_NODE *Prev;
222 unsigned long UncompOffset; // File size accumulator
223 unsigned long AbsoluteOffset;
224 unsigned long TotalFolderSize; // Total size of folder in current disk
225 PCFDATA_NODE DataListHead;
226 PCFDATA_NODE DataListTail;
228 bool Commit; // true if the folder should be committed
229 bool Delete; // true if marked for deletion
231 } CFFOLDER_NODE, *PCFFOLDER_NODE;
233 typedef struct _CFFILE_NODE
235 struct _CFFILE_NODE *Next;
236 struct _CFFILE_NODE *Prev;
239 PCFDATA_NODE DataBlock; // First data block of file. NULL if not known
240 bool Commit; // true if the file data should be committed
241 bool Delete; // true if marked for deletion
242 PCFFOLDER_NODE FolderNode; // Folder this file belong to
243 } CFFILE_NODE, *PCFFILE_NODE;
246 typedef struct _CAB_SEARCH
248 char Search[MAX_PATH]; // Search criteria
249 PCFFILE_NODE Next; // Pointer to next node
250 PCFFILE File; // Pointer to current CFFILE
251 char* FileName; // Current filename
252 } CAB_SEARCH, *PCAB_SEARCH;
258 #define CAB_STATUS_SUCCESS 0x00000000
259 #define CAB_STATUS_FAILURE 0x00000001
260 #define CAB_STATUS_NOMEMORY 0x00000002
261 #define CAB_STATUS_CANNOT_OPEN 0x00000003
262 #define CAB_STATUS_CANNOT_CREATE 0x00000004
263 #define CAB_STATUS_CANNOT_READ 0x00000005
264 #define CAB_STATUS_CANNOT_WRITE 0x00000006
265 #define CAB_STATUS_FILE_EXISTS 0x00000007
266 #define CAB_STATUS_INVALID_CAB 0x00000008
267 #define CAB_STATUS_NOFILE 0x00000009
268 #define CAB_STATUS_UNSUPPCOMP 0x0000000A
276 /* Default constructor */
278 /* Default destructor */
279 virtual ~CCABCodec() {};
280 /* Compresses a data block */
281 virtual unsigned long Compress(void* OutputBuffer,
283 unsigned long InputLength,
284 unsigned long* OutputLength) = 0;
285 /* Uncompresses a data block */
286 virtual unsigned long Uncompress(void* OutputBuffer,
288 unsigned long InputLength,
289 unsigned long* OutputLength) = 0;
293 /* Codec status codes */
294 #define CS_SUCCESS 0x0000 /* All data consumed */
295 #define CS_NOMEMORY 0x0001 /* Not enough free memory */
296 #define CS_BADSTREAM 0x0002 /* Bad data stream */
299 /* Codec indentifiers */
300 #define CAB_CODEC_RAW 0x00
301 #define CAB_CODEC_LZX 0x01
302 #define CAB_CODEC_MSZIP 0x02
308 #ifndef CAB_READ_ONLY
310 class CCFDATAStorage {
312 /* Default constructor */
314 /* Default destructor */
315 virtual ~CCFDATAStorage();
316 unsigned long Create(char* FileName);
317 unsigned long Destroy();
318 unsigned long Truncate();
319 unsigned long Position();
320 unsigned long Seek(long Position);
321 unsigned long ReadBlock(PCFDATA Data, void* Buffer, unsigned long* BytesRead);
322 unsigned long WriteBlock(PCFDATA Data, void* Buffer, unsigned long* BytesWritten);
324 char FullName[MAX_PATH];
326 FILEHANDLE FileHandle;
329 #endif /* CAB_READ_ONLY */
333 /* Default constructor */
335 /* Default destructor */
337 /* Determines if a character is a separator */
338 bool CCabinet::IsSeparator(char Char);
339 /* Replaces \ or / with the one used be the host environment */
340 char* CCabinet::ConvertPath(char* Path, bool Allocate);
341 /* Returns a pointer to the filename part of a fully qualified filename */
342 char* GetFileName(char* Path);
343 /* Removes a filename from a fully qualified filename */
344 void RemoveFileName(char* Path);
345 /* Normalizes a path */
346 bool NormalizePath(char* Path, unsigned long Length);
347 /* Returns name of cabinet file */
348 char* GetCabinetName();
349 /* Sets the name of the cabinet file */
350 void SetCabinetName(char* FileName);
351 /* Sets destination path for extracted files */
352 void SetDestinationPath(char* DestinationPath);
353 /* Sets cabinet reserved file */
354 bool SetCabinetReservedFile(char* FileName);
355 /* Returns cabinet reserved file */
356 char* GetCabinetReservedFile();
357 /* Returns destination path */
358 char* GetDestinationPath();
359 /* Returns zero-based current disk number */
360 unsigned long GetCurrentDiskNumber();
361 /* Opens the current cabinet file */
362 unsigned long Open();
363 /* Closes the current open cabinet file */
365 /* Locates the first file in the current cabinet file that matches a search criteria */
366 unsigned long FindFirst(char* FileName, PCAB_SEARCH Search);
367 /* Locates the next file in the current cabinet file */
368 unsigned long FindNext(PCAB_SEARCH Search);
369 /* Extracts a file from the current cabinet file */
370 unsigned long ExtractFile(char* FileName);
371 /* Select codec engine to use */
372 void SelectCodec(unsigned long Id);
373 #ifndef CAB_READ_ONLY
374 /* Creates a new cabinet file */
375 unsigned long NewCabinet();
376 /* Forces a new disk to be created */
377 unsigned long NewDisk();
378 /* Forces a new folder to be created */
379 unsigned long NewFolder();
380 /* Writes a file to scratch storage */
381 unsigned long WriteFileToScratchStorage(PCFFILE_NODE FileNode);
382 /* Forces the current disk to be written */
383 unsigned long WriteDisk(unsigned long MoreDisks);
384 /* Commits the current disk */
385 unsigned long CommitDisk(unsigned long MoreDisks);
386 /* Closes the current disk */
387 unsigned long CloseDisk();
388 /* Closes the current cabinet */
389 unsigned long CloseCabinet();
390 /* Adds a file to the current disk */
391 unsigned long AddFile(char* FileName);
392 /* Sets the maximum size of the current disk */
393 void SetMaxDiskSize(unsigned long Size);
394 #endif /* CAB_READ_ONLY */
396 /* Default event handlers */
398 /* Handler called when a file is about to be overridden */
399 virtual bool OnOverwrite(PCFFILE Entry, char* FileName);
400 /* Handler called when a file is about to be extracted */
401 virtual void OnExtract(PCFFILE Entry, char* FileName);
402 /* Handler called when a new disk is to be processed */
403 virtual void OnDiskChange(char* CabinetName, char* DiskLabel);
404 #ifndef CAB_READ_ONLY
405 /* Handler called when a file is about to be added */
406 virtual void OnAdd(PCFFILE Entry, char* FileName);
407 /* Handler called when a cabinet need a name */
408 virtual bool OnCabinetName(unsigned long Number, char* Name);
409 /* Handler called when a disk needs a label */
410 virtual bool OnDiskLabel(unsigned long Number, char* Label);
411 #endif /* CAB_READ_ONLY */
413 PCFFOLDER_NODE LocateFolderNode(unsigned long Index);
414 unsigned long GetAbsoluteOffset(PCFFILE_NODE File);
415 unsigned long LocateFile(char* FileName, PCFFILE_NODE *File);
416 unsigned long ReadString(char* String, unsigned long MaxLength);
417 unsigned long ReadFileTable();
418 unsigned long ReadDataBlocks(PCFFOLDER_NODE FolderNode);
419 PCFFOLDER_NODE NewFolderNode();
420 PCFFILE_NODE NewFileNode();
421 PCFDATA_NODE NewDataNode(PCFFOLDER_NODE FolderNode);
422 void DestroyDataNodes(PCFFOLDER_NODE FolderNode);
423 void DestroyFileNodes();
424 void DestroyDeletedFileNodes();
425 void DestroyFolderNodes();
426 void DestroyDeletedFolderNodes();
427 unsigned long ComputeChecksum(void* Buffer, unsigned int Size, unsigned long Seed);
428 unsigned long ReadBlock(void* Buffer, unsigned long Size, unsigned long* BytesRead);
429 #ifndef CAB_READ_ONLY
430 unsigned long InitCabinetHeader();
431 unsigned long WriteCabinetHeader(bool MoreDisks);
432 unsigned long WriteFolderEntries();
433 unsigned long WriteFileEntries();
434 unsigned long CommitDataBlocks(PCFFOLDER_NODE FolderNode);
435 unsigned long WriteDataBlock();
436 unsigned long GetAttributesOnFile(PCFFILE_NODE File);
437 unsigned long SetAttributesOnFile(PCFFILE_NODE File);
438 unsigned long GetFileTimes(FILEHANDLE FileHandle, PCFFILE_NODE File);
440 void ConvertDateAndTime(time_t* Time, unsigned short* DosDate, unsigned short* DosTime);
442 #endif /* CAB_READ_ONLY */
443 unsigned long CurrentDiskNumber; // Zero based disk number
444 char CabinetName[256]; // Filename of current cabinet
445 char CabinetPrev[256]; // Filename of previous cabinet
446 char DiskPrev[256]; // Label of cabinet in file CabinetPrev
447 char CabinetNext[256]; // Filename of next cabinet
448 char DiskNext[256]; // Label of cabinet in file CabinetNext
449 unsigned long TotalHeaderSize; // Size of header and optional fields
450 unsigned long NextFieldsSize; // Size of next cabinet name and next disk label
451 unsigned long TotalFolderSize; // Size of all folder entries
452 unsigned long TotalFileSize; // Size of all file entries
453 unsigned long FolderUncompSize; // Uncompressed size of folder
454 unsigned long BytesLeftInBlock; // Number of bytes left in current block
456 char DestPath[MAX_PATH];
457 char CabinetReservedFile[MAX_PATH];
458 void* CabinetReservedFileBuffer;
459 unsigned long CabinetReservedFileSize;
460 FILEHANDLE FileHandle;
463 unsigned long CabinetReserved;
464 unsigned long FolderReserved;
465 unsigned long DataReserved;
466 PCFFOLDER_NODE FolderListHead;
467 PCFFOLDER_NODE FolderListTail;
468 PCFFOLDER_NODE CurrentFolderNode;
469 PCFDATA_NODE CurrentDataNode;
470 PCFFILE_NODE FileListHead;
471 PCFFILE_NODE FileListTail;
473 unsigned long CodecId;
476 void* CurrentIBuffer; // Current offset in input buffer
477 unsigned long CurrentIBufferSize; // Bytes left in input buffer
479 unsigned long TotalCompSize; // Total size of current CFDATA block
480 void* CurrentOBuffer; // Current offset in output buffer
481 unsigned long CurrentOBufferSize; // Bytes left in output buffer
482 unsigned long BytesLeftInCabinet;
484 unsigned long LastFileOffset; // Uncompressed offset of last extracted file
485 #ifndef CAB_READ_ONLY
486 unsigned long LastBlockStart; // Uncompressed offset of last block in folder
487 unsigned long MaxDiskSize;
488 unsigned long DiskSize;
489 unsigned long PrevCabinetNumber; // Previous cabinet number (where split file starts)
491 bool CreateNewFolder;
493 CCFDATAStorage *ScratchFile;
494 FILEHANDLE SourceFile;
496 unsigned long TotalBytesLeft;
497 bool BlockIsSplit; // true if current data block is split
498 unsigned long NextFolderNumber; // Zero based folder number
499 #endif /* CAB_READ_ONLY */
502 #endif /* __CABINET_H */