xref: /reactos/sdk/tools/cabman/cabinet.h (revision 58588b76)
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