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