This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / 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 #ifndef __CABINET_H
8 #define __CABINET_H
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 <unistd.h>
18 #ifndef MAX_PATH
19 #define MAX_PATH 260
20 #endif
21 #endif
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #if defined(WIN32)
27 #define DIR_SEPARATOR_CHAR '\\'
28 #define DIR_SEPARATOR_STRING "\\"
29
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)
37 {
38     long size = GetFileSize(handle, NULL);
39     if (size == INVALID_FILE_SIZE)
40       {
41         return -1;
42       }
43     return size;
44 }
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)
47 {
48     return ReadFile(handle, buffer, size, bytesread, NULL);
49 }
50 #else
51 #define DIR_SEPARATOR_CHAR '/'
52 #define DIR_SEPARATOR_STRING "/"
53
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)
60 {
61     long size;
62     fseek(handle, 0, SEEK_END);
63     size = ftell(handle);
64     fseek(handle, 0, SEEK_SET);
65     return size;
66 }
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)
69 {
70     *bytesread = fread(buffer, 1, size, handle);
71     return *bytesread == size;
72 }
73 #endif
74
75 /* Debugging */
76
77 #define DBG
78
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
84
85 #define DEBUG_MEMORY   0x00000100
86
87 #ifdef DBG
88
89 extern unsigned long DebugTraceLevel;
90
91 #define DPRINT(_t_, _x_) \
92     if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
93         ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
94         printf("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
95         printf _x_ ; \
96     }
97
98 #define ASSERT(_b_) { \
99     if (!(_b_)) { \
100         printf("(%s:%d)(%s) ASSERTION: ", __FILE__, __LINE__, __FUNCTION__); \
101         printf(#_b_); \
102         exit(0); \
103     } \
104 }
105
106 #else /* DBG */
107
108 #define DPRINT(_t_, _x_)
109
110 #define ASSERT(_x_)
111
112 #endif /* DBG */
113
114
115 /* Cabinet constants */
116
117 #define CAB_SIGNATURE        0x4643534D // "MSCF"
118 #define CAB_VERSION          0x0103
119 #define CAB_BLOCKSIZE        32768
120
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
126
127 #define CAB_FLAG_HASPREV     0x0001
128 #define CAB_FLAG_HASNEXT     0x0002
129 #define CAB_FLAG_RESERVE     0x0004
130
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
139
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
144
145
146 /* Cabinet structures */
147
148 typedef struct _CFHEADER
149 {
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
171  */
172 } CFHEADER, *PCFHEADER;
173
174
175 typedef struct _CFFOLDER
176 {
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
182  */
183 } CFFOLDER, *PCFFOLDER;
184
185
186 typedef struct _CFFILE
187 {
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 */
195 } CFFILE, *PCFFILE;
196
197
198 typedef struct _CFDATA
199 {
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
205  */
206 } CFDATA, *PCFDATA;
207
208 typedef struct _CFDATA_NODE
209 {
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
215     CFDATA              Data;
216 } CFDATA_NODE, *PCFDATA_NODE;
217
218 typedef struct _CFFOLDER_NODE
219 {
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;
227     unsigned long         Index;
228     bool                  Commit;           // true if the folder should be committed
229     bool                  Delete;           // true if marked for deletion
230     CFFOLDER              Folder;
231 } CFFOLDER_NODE, *PCFFOLDER_NODE;
232
233 typedef struct _CFFILE_NODE
234 {
235     struct _CFFILE_NODE *Next;
236     struct _CFFILE_NODE *Prev;
237     CFFILE              File;
238     char*               FileName;
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;
244
245
246 typedef struct _CAB_SEARCH
247 {
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;
253
254
255 /* Constants */
256
257 /* Status codes */
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
269
270
271
272 /* Codecs */
273
274 class CCABCodec {
275 public:
276     /* Default constructor */
277     CCABCodec() {};
278     /* Default destructor */
279     virtual ~CCABCodec() {};
280     /* Compresses a data block */
281     virtual unsigned long Compress(void* OutputBuffer,
282                            void* InputBuffer,
283                            unsigned long InputLength,
284                            unsigned long* OutputLength) = 0;
285     /* Uncompresses a data block */
286     virtual unsigned long Uncompress(void* OutputBuffer,
287                              void* InputBuffer,
288                              unsigned long InputLength,
289                              unsigned long* OutputLength) = 0;
290 };
291
292
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 */
297
298
299 /* Codec indentifiers */
300 #define CAB_CODEC_RAW   0x00
301 #define CAB_CODEC_LZX   0x01
302 #define CAB_CODEC_MSZIP 0x02
303
304
305
306 /* Classes */
307
308 #ifndef CAB_READ_ONLY
309
310 class CCFDATAStorage {
311 public:
312     /* Default constructor */
313     CCFDATAStorage();
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);
323 private:
324     char FullName[MAX_PATH];
325     bool FileCreated;
326     FILEHANDLE FileHandle;
327 };
328
329 #endif /* CAB_READ_ONLY */
330
331 class CCabinet {
332 public:
333     /* Default constructor */
334     CCabinet();
335     /* Default destructor */
336     virtual ~CCabinet();
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 */
364     void Close();
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 */
395
396     /* Default event handlers */
397
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 */
412 private:
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);
439 #if !defined(WIN32)
440     void ConvertDateAndTime(time_t* Time, unsigned short* DosDate, unsigned short* DosTime);
441 #endif
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
455     bool ReuseBlock;
456     char DestPath[MAX_PATH];
457     char CabinetReservedFile[MAX_PATH];
458     void* CabinetReservedFileBuffer;
459     unsigned long CabinetReservedFileSize;
460     FILEHANDLE FileHandle;
461     bool FileOpen;
462     CFHEADER CABHeader;
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;
472     CCABCodec *Codec;
473     unsigned long CodecId;
474     bool CodecSelected;
475     void* InputBuffer;
476     void* CurrentIBuffer;               // Current offset in input buffer
477     unsigned long CurrentIBufferSize;   // Bytes left in input buffer
478     void* OutputBuffer;
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;
483     bool RestartSearch;
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)
490     bool CreateNewDisk;
491     bool CreateNewFolder;
492
493     CCFDATAStorage *ScratchFile;
494     FILEHANDLE SourceFile;
495     bool ContinueFile;
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 */
500 };
501
502 #endif /* __CABINET_H */
503
504 /* EOF */