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