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)
36 #define DIR_SEPARATOR_CHAR '/'
37 #define DIR_SEPARATOR_STRING "/"
39 #define AllocateMemory(size) malloc(size)
40 #define FreeMemory(buffer) free(buffer)
41 #define CloseFile(handle) fclose(handle)
42 #define FILEHANDLE FILE*
49 #define NORMAL_MASK 0x000000FF
50 #define SPECIAL_MASK 0xFFFFFF00
51 #define MIN_TRACE 0x00000001
52 #define MID_TRACE 0x00000002
53 #define MAX_TRACE 0x00000003
55 #define DEBUG_MEMORY 0x00000100
59 extern unsigned long DebugTraceLevel
;
61 #define DPRINT(_t_, _x_) \
62 if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
63 ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
64 printf("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
68 #define ASSERT(_b_) { \
70 printf("(%s:%d)(%s) ASSERTION: ", __FILE__, __LINE__, __FUNCTION__); \
78 #define DPRINT(_t_, _x_)
85 /* Cabinet constants */
87 #define CAB_SIGNATURE 0x4643534D // "MSCF"
88 #define CAB_VERSION 0x0103
89 #define CAB_BLOCKSIZE 32768
91 #define CAB_COMP_MASK 0x00FF
92 #define CAB_COMP_NONE 0x0000
93 #define CAB_COMP_MSZIP 0x0001
94 #define CAB_COMP_QUANTUM 0x0002
95 #define CAB_COMP_LZX 0x0003
97 #define CAB_FLAG_HASPREV 0x0001
98 #define CAB_FLAG_HASNEXT 0x0002
99 #define CAB_FLAG_RESERVE 0x0004
101 #define CAB_ATTRIB_READONLY 0x0001
102 #define CAB_ATTRIB_HIDDEN 0x0002
103 #define CAB_ATTRIB_SYSTEM 0x0004
104 #define CAB_ATTRIB_VOLUME 0x0008
105 #define CAB_ATTRIB_DIRECTORY 0x0010
106 #define CAB_ATTRIB_ARCHIVE 0x0020
107 #define CAB_ATTRIB_EXECUTE 0x0040
108 #define CAB_ATTRIB_UTF_NAME 0x0080
110 #define CAB_FILE_MAX_FOLDER 0xFFFC
111 #define CAB_FILE_CONTINUED 0xFFFD
112 #define CAB_FILE_SPLIT 0xFFFE
113 #define CAB_FILE_PREV_NEXT 0xFFFF
116 /* Cabinet structures */
118 typedef struct _CFHEADER
120 unsigned long Signature
; // File signature 'MSCF' (CAB_SIGNATURE)
121 unsigned long Reserved1
; // Reserved field
122 unsigned long CabinetSize
; // Cabinet file size
123 unsigned long Reserved2
; // Reserved field
124 unsigned long FileTableOffset
; // Offset of first CFFILE
125 unsigned long Reserved3
; // Reserved field
126 unsigned short Version
; // Cabinet version (CAB_VERSION)
127 unsigned short FolderCount
; // Number of folders
128 unsigned short FileCount
; // Number of files
129 unsigned short Flags
; // Cabinet flags (CAB_FLAG_*)
130 unsigned short SetID
; // Cabinet set id
131 unsigned short CabinetNumber
; // Zero-based cabinet number
132 /* Optional fields (depends on Flags)
133 unsigned short CabinetResSize // Per-cabinet reserved area size
134 char FolderResSize // Per-folder reserved area size
135 char FileResSize // Per-file reserved area size
136 char CabinetReserved[] // Per-cabinet reserved area
137 char CabinetPrev[] // Name of previous cabinet file
138 char DiskPrev[] // Name of previous disk
139 char CabinetNext[] // Name of next cabinet file
140 char DiskNext[] // Name of next disk
142 } CFHEADER
, *PCFHEADER
;
145 typedef struct _CFFOLDER
147 unsigned long DataOffset
; // Absolute offset of first CFDATA block in this folder
148 unsigned short DataBlockCount
; // Number of CFDATA blocks in this folder in this cabinet
149 unsigned short CompressionType
; // Type of compression used for all CFDATA blocks in this folder
150 /* Optional fields (depends on Flags)
151 char FolderReserved[] // Per-folder reserved area
153 } CFFOLDER
, *PCFFOLDER
;
156 typedef struct _CFFILE
158 unsigned long FileSize
; // Uncompressed file size in bytes
159 unsigned long FileOffset
; // Uncompressed offset of file in the folder
160 unsigned short FileControlID
; // File control ID (CAB_FILE_*)
161 unsigned short FileDate
; // File date stamp, as used by DOS
162 unsigned short FileTime
; // File time stamp, as used by DOS
163 unsigned short Attributes
; // File attributes (CAB_ATTRIB_*)
164 /* After this is the NULL terminated filename */
168 typedef struct _CFDATA
170 unsigned long Checksum
; // Checksum of CFDATA entry
171 unsigned short CompSize
; // Number of compressed bytes in this block
172 unsigned short UncompSize
; // Number of uncompressed bytes in this block
173 /* Optional fields (depends on Flags)
174 char DataReserved[] // Per-datablock reserved area
178 typedef struct _CFDATA_NODE
180 struct _CFDATA_NODE
*Next
;
181 struct _CFDATA_NODE
*Prev
;
182 unsigned long ScratchFilePosition
; // Absolute offset in scratch file
183 unsigned long AbsoluteOffset
; // Absolute offset in cabinet
184 unsigned long UncompOffset
; // Uncompressed offset in folder
186 } CFDATA_NODE
, *PCFDATA_NODE
;
188 typedef struct _CFFOLDER_NODE
190 struct _CFFOLDER_NODE
*Next
;
191 struct _CFFOLDER_NODE
*Prev
;
192 unsigned long UncompOffset
; // File size accumulator
193 unsigned long AbsoluteOffset
;
194 unsigned long TotalFolderSize
; // Total size of folder in current disk
195 PCFDATA_NODE DataListHead
;
196 PCFDATA_NODE DataListTail
;
198 bool Commit
; // true if the folder should be committed
199 bool Delete
; // true if marked for deletion
201 } CFFOLDER_NODE
, *PCFFOLDER_NODE
;
203 typedef struct _CFFILE_NODE
205 struct _CFFILE_NODE
*Next
;
206 struct _CFFILE_NODE
*Prev
;
209 PCFDATA_NODE DataBlock
; // First data block of file. NULL if not known
210 bool Commit
; // true if the file data should be committed
211 bool Delete
; // true if marked for deletion
212 PCFFOLDER_NODE FolderNode
; // Folder this file belong to
213 } CFFILE_NODE
, *PCFFILE_NODE
;
216 typedef struct _CAB_SEARCH
218 char Search
[MAX_PATH
]; // Search criteria
219 PCFFILE_NODE Next
; // Pointer to next node
220 PCFFILE File
; // Pointer to current CFFILE
221 char* FileName
; // Current filename
222 } CAB_SEARCH
, *PCAB_SEARCH
;
228 #define CAB_STATUS_SUCCESS 0x00000000
229 #define CAB_STATUS_FAILURE 0x00000001
230 #define CAB_STATUS_NOMEMORY 0x00000002
231 #define CAB_STATUS_CANNOT_OPEN 0x00000003
232 #define CAB_STATUS_CANNOT_CREATE 0x00000004
233 #define CAB_STATUS_CANNOT_READ 0x00000005
234 #define CAB_STATUS_CANNOT_WRITE 0x00000006
235 #define CAB_STATUS_FILE_EXISTS 0x00000007
236 #define CAB_STATUS_INVALID_CAB 0x00000008
237 #define CAB_STATUS_NOFILE 0x00000009
238 #define CAB_STATUS_UNSUPPCOMP 0x0000000A
246 /* Default constructor */
248 /* Default destructor */
249 virtual ~CCABCodec() {};
250 /* Compresses a data block */
251 virtual unsigned long Compress(void* OutputBuffer
,
253 unsigned long InputLength
,
254 unsigned long* OutputLength
) = 0;
255 /* Uncompresses a data block */
256 virtual unsigned long Uncompress(void* OutputBuffer
,
258 unsigned long InputLength
,
259 unsigned long* OutputLength
) = 0;
263 /* Codec status codes */
264 #define CS_SUCCESS 0x0000 /* All data consumed */
265 #define CS_NOMEMORY 0x0001 /* Not enough free memory */
266 #define CS_BADSTREAM 0x0002 /* Bad data stream */
269 /* Codec indentifiers */
270 #define CAB_CODEC_RAW 0x00
271 #define CAB_CODEC_LZX 0x01
272 #define CAB_CODEC_MSZIP 0x02
278 #ifndef CAB_READ_ONLY
280 class CCFDATAStorage
{
282 /* Default constructor */
284 /* Default destructor */
285 virtual ~CCFDATAStorage();
286 unsigned long Create(char* FileName
);
287 unsigned long Destroy();
288 unsigned long Truncate();
289 unsigned long Position();
290 unsigned long Seek(long Position
);
291 unsigned long ReadBlock(PCFDATA Data
, void* Buffer
, unsigned long* BytesRead
);
292 unsigned long WriteBlock(PCFDATA Data
, void* Buffer
, unsigned long* BytesWritten
);
294 char FullName
[MAX_PATH
];
296 FILEHANDLE FileHandle
;
299 #endif /* CAB_READ_ONLY */
303 /* Default constructor */
305 /* Default destructor */
307 /* Determines if a character is a separator */
308 bool CCabinet::IsSeparator(char Char
);
309 /* Replaces \ or / with the one used be the host environment */
310 char* CCabinet::ConvertPath(char* Path
, bool Allocate
);
311 /* Returns a pointer to the filename part of a fully qualified filename */
312 char* GetFileName(char* Path
);
313 /* Removes a filename from a fully qualified filename */
314 void RemoveFileName(char* Path
);
315 /* Normalizes a path */
316 bool NormalizePath(char* Path
, unsigned long Length
);
317 /* Returns name of cabinet file */
318 char* GetCabinetName();
319 /* Sets the name of the cabinet file */
320 void SetCabinetName(char* FileName
);
321 /* Sets destination path for extracted files */
322 void SetDestinationPath(char* DestinationPath
);
323 /* Sets cabinet reserved file */
324 bool SetCabinetReservedFile(char* FileName
);
325 /* Returns cabinet reserved file */
326 char* GetCabinetReservedFile();
327 /* Returns destination path */
328 char* GetDestinationPath();
329 /* Returns zero-based current disk number */
330 unsigned long GetCurrentDiskNumber();
331 /* Opens the current cabinet file */
332 unsigned long Open();
333 /* Closes the current open cabinet file */
335 /* Locates the first file in the current cabinet file that matches a search criteria */
336 unsigned long FindFirst(char* FileName
, PCAB_SEARCH Search
);
337 /* Locates the next file in the current cabinet file */
338 unsigned long FindNext(PCAB_SEARCH Search
);
339 /* Extracts a file from the current cabinet file */
340 unsigned long ExtractFile(char* FileName
);
341 /* Select codec engine to use */
342 void SelectCodec(unsigned long Id
);
343 #ifndef CAB_READ_ONLY
344 /* Creates a new cabinet file */
345 unsigned long NewCabinet();
346 /* Forces a new disk to be created */
347 unsigned long NewDisk();
348 /* Forces a new folder to be created */
349 unsigned long NewFolder();
350 /* Writes a file to scratch storage */
351 unsigned long WriteFileToScratchStorage(PCFFILE_NODE FileNode
);
352 /* Forces the current disk to be written */
353 unsigned long WriteDisk(unsigned long MoreDisks
);
354 /* Commits the current disk */
355 unsigned long CommitDisk(unsigned long MoreDisks
);
356 /* Closes the current disk */
357 unsigned long CloseDisk();
358 /* Closes the current cabinet */
359 unsigned long CloseCabinet();
360 /* Adds a file to the current disk */
361 unsigned long AddFile(char* FileName
);
362 /* Sets the maximum size of the current disk */
363 void SetMaxDiskSize(unsigned long Size
);
364 #endif /* CAB_READ_ONLY */
366 /* Default event handlers */
368 /* Handler called when a file is about to be overridden */
369 virtual bool OnOverwrite(PCFFILE Entry
, char* FileName
);
370 /* Handler called when a file is about to be extracted */
371 virtual void OnExtract(PCFFILE Entry
, char* FileName
);
372 /* Handler called when a new disk is to be processed */
373 virtual void OnDiskChange(char* CabinetName
, char* DiskLabel
);
374 #ifndef CAB_READ_ONLY
375 /* Handler called when a file is about to be added */
376 virtual void OnAdd(PCFFILE Entry
, char* FileName
);
377 /* Handler called when a cabinet need a name */
378 virtual bool OnCabinetName(unsigned long Number
, char* Name
);
379 /* Handler called when a disk needs a label */
380 virtual bool OnDiskLabel(unsigned long Number
, char* Label
);
381 #endif /* CAB_READ_ONLY */
383 PCFFOLDER_NODE
LocateFolderNode(unsigned long Index
);
384 unsigned long GetAbsoluteOffset(PCFFILE_NODE File
);
385 unsigned long LocateFile(char* FileName
, PCFFILE_NODE
*File
);
386 unsigned long ReadString(char* String
, unsigned long MaxLength
);
387 unsigned long ReadFileTable();
388 unsigned long ReadDataBlocks(PCFFOLDER_NODE FolderNode
);
389 PCFFOLDER_NODE
NewFolderNode();
390 PCFFILE_NODE
NewFileNode();
391 PCFDATA_NODE
NewDataNode(PCFFOLDER_NODE FolderNode
);
392 void DestroyDataNodes(PCFFOLDER_NODE FolderNode
);
393 void DestroyFileNodes();
394 void DestroyDeletedFileNodes();
395 void DestroyFolderNodes();
396 void DestroyDeletedFolderNodes();
397 unsigned long ComputeChecksum(void* Buffer
, unsigned int Size
, unsigned long Seed
);
398 unsigned long ReadBlock(void* Buffer
, unsigned long Size
, unsigned long* BytesRead
);
399 #ifndef CAB_READ_ONLY
400 unsigned long InitCabinetHeader();
401 unsigned long WriteCabinetHeader(bool MoreDisks
);
402 unsigned long WriteFolderEntries();
403 unsigned long WriteFileEntries();
404 unsigned long CommitDataBlocks(PCFFOLDER_NODE FolderNode
);
405 unsigned long WriteDataBlock();
406 unsigned long GetAttributesOnFile(PCFFILE_NODE File
);
407 unsigned long SetAttributesOnFile(PCFFILE_NODE File
);
408 unsigned long GetFileTimes(FILEHANDLE FileHandle
, PCFFILE_NODE File
);
410 void ConvertDateAndTime(time_t* Time
, unsigned short* DosDate
, unsigned short* DosTime
);
412 #endif /* CAB_READ_ONLY */
413 unsigned long CurrentDiskNumber
; // Zero based disk number
414 char CabinetName
[256]; // Filename of current cabinet
415 char CabinetPrev
[256]; // Filename of previous cabinet
416 char DiskPrev
[256]; // Label of cabinet in file CabinetPrev
417 char CabinetNext
[256]; // Filename of next cabinet
418 char DiskNext
[256]; // Label of cabinet in file CabinetNext
419 unsigned long TotalHeaderSize
; // Size of header and optional fields
420 unsigned long NextFieldsSize
; // Size of next cabinet name and next disk label
421 unsigned long TotalFolderSize
; // Size of all folder entries
422 unsigned long TotalFileSize
; // Size of all file entries
423 unsigned long FolderUncompSize
; // Uncompressed size of folder
424 unsigned long BytesLeftInBlock
; // Number of bytes left in current block
426 char DestPath
[MAX_PATH
];
427 char CabinetReservedFile
[MAX_PATH
];
428 void* CabinetReservedFileBuffer
;
429 unsigned long CabinetReservedFileSize
;
430 FILEHANDLE FileHandle
;
433 unsigned long CabinetReserved
;
434 unsigned long FolderReserved
;
435 unsigned long DataReserved
;
436 PCFFOLDER_NODE FolderListHead
;
437 PCFFOLDER_NODE FolderListTail
;
438 PCFFOLDER_NODE CurrentFolderNode
;
439 PCFDATA_NODE CurrentDataNode
;
440 PCFFILE_NODE FileListHead
;
441 PCFFILE_NODE FileListTail
;
443 unsigned long CodecId
;
446 void* CurrentIBuffer
; // Current offset in input buffer
447 unsigned long CurrentIBufferSize
; // Bytes left in input buffer
449 unsigned long TotalCompSize
; // Total size of current CFDATA block
450 void* CurrentOBuffer
; // Current offset in output buffer
451 unsigned long CurrentOBufferSize
; // Bytes left in output buffer
452 unsigned long BytesLeftInCabinet
;
454 unsigned long LastFileOffset
; // Uncompressed offset of last extracted file
455 #ifndef CAB_READ_ONLY
456 unsigned long LastBlockStart
; // Uncompressed offset of last block in folder
457 unsigned long MaxDiskSize
;
458 unsigned long DiskSize
;
459 unsigned long PrevCabinetNumber
; // Previous cabinet number (where split file starts)
461 bool CreateNewFolder
;
463 CCFDATAStorage
*ScratchFile
;
464 FILEHANDLE SourceFile
;
466 unsigned long TotalBytesLeft
;
467 bool BlockIsSplit
; // true if current data block is split
468 unsigned long NextFolderNumber
; // Zero based folder number
469 #endif /* CAB_READ_ONLY */
472 #endif /* __CABINET_H */