Patch by Jonathon Wilson:
[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 #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 #else
36 #define DIR_SEPARATOR_CHAR '/'
37 #define DIR_SEPARATOR_STRING "/"
38
39 #define AllocateMemory(size) malloc(size)
40 #define FreeMemory(buffer) free(buffer)
41 #define CloseFile(handle) fclose(handle)
42 #define FILEHANDLE FILE*
43 #endif
44
45 /* Debugging */
46
47 #define DBG
48
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
54
55 #define DEBUG_MEMORY 0x00000100
56
57 #ifdef DBG
58
59 extern unsigned long DebugTraceLevel;
60
61 #define DPRINT(_t_, _x_) \
62 if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
63 ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
64 printf("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
65 printf _x_ ; \
66 }
67
68 #define ASSERT(_b_) { \
69 if (!(_b_)) { \
70 printf("(%s:%d)(%s) ASSERTION: ", __FILE__, __LINE__, __FUNCTION__); \
71 printf(#_b_); \
72 exit(0); \
73 } \
74 }
75
76 #else /* DBG */
77
78 #define DPRINT(_t_, _x_)
79
80 #define ASSERT(_x_)
81
82 #endif /* DBG */
83
84
85 /* Cabinet constants */
86
87 #define CAB_SIGNATURE 0x4643534D // "MSCF"
88 #define CAB_VERSION 0x0103
89 #define CAB_BLOCKSIZE 32768
90
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
96
97 #define CAB_FLAG_HASPREV 0x0001
98 #define CAB_FLAG_HASNEXT 0x0002
99 #define CAB_FLAG_RESERVE 0x0004
100
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
109
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
114
115
116 /* Cabinet structures */
117
118 typedef struct _CFHEADER
119 {
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
141 */
142 } CFHEADER, *PCFHEADER;
143
144
145 typedef struct _CFFOLDER
146 {
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
152 */
153 } CFFOLDER, *PCFFOLDER;
154
155
156 typedef struct _CFFILE
157 {
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 */
165 } CFFILE, *PCFFILE;
166
167
168 typedef struct _CFDATA
169 {
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
175 */
176 } CFDATA, *PCFDATA;
177
178 typedef struct _CFDATA_NODE
179 {
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
185 CFDATA Data;
186 } CFDATA_NODE, *PCFDATA_NODE;
187
188 typedef struct _CFFOLDER_NODE
189 {
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;
197 unsigned long Index;
198 bool Commit; // true if the folder should be committed
199 bool Delete; // true if marked for deletion
200 CFFOLDER Folder;
201 } CFFOLDER_NODE, *PCFFOLDER_NODE;
202
203 typedef struct _CFFILE_NODE
204 {
205 struct _CFFILE_NODE *Next;
206 struct _CFFILE_NODE *Prev;
207 CFFILE File;
208 char* FileName;
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;
214
215
216 typedef struct _CAB_SEARCH
217 {
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;
223
224
225 /* Constants */
226
227 /* Status codes */
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
239
240
241
242 /* Codecs */
243
244 class CCABCodec {
245 public:
246 /* Default constructor */
247 CCABCodec() {};
248 /* Default destructor */
249 virtual ~CCABCodec() {};
250 /* Compresses a data block */
251 virtual unsigned long Compress(void* OutputBuffer,
252 void* InputBuffer,
253 unsigned long InputLength,
254 unsigned long* OutputLength) = 0;
255 /* Uncompresses a data block */
256 virtual unsigned long Uncompress(void* OutputBuffer,
257 void* InputBuffer,
258 unsigned long InputLength,
259 unsigned long* OutputLength) = 0;
260 };
261
262
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 */
267
268
269 /* Codec indentifiers */
270 #define CAB_CODEC_RAW 0x00
271 #define CAB_CODEC_LZX 0x01
272 #define CAB_CODEC_MSZIP 0x02
273
274
275
276 /* Classes */
277
278 #ifndef CAB_READ_ONLY
279
280 class CCFDATAStorage {
281 public:
282 /* Default constructor */
283 CCFDATAStorage();
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);
293 private:
294 char FullName[MAX_PATH];
295 bool FileCreated;
296 FILEHANDLE FileHandle;
297 };
298
299 #endif /* CAB_READ_ONLY */
300
301 class CCabinet {
302 public:
303 /* Default constructor */
304 CCabinet();
305 /* Default destructor */
306 virtual ~CCabinet();
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 */
334 void Close();
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 */
365
366 /* Default event handlers */
367
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 */
382 private:
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);
409 #if !defined(WIN32)
410 void ConvertDateAndTime(time_t* Time, unsigned short* DosDate, unsigned short* DosTime);
411 #endif
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
425 bool ReuseBlock;
426 char DestPath[MAX_PATH];
427 char CabinetReservedFile[MAX_PATH];
428 void* CabinetReservedFileBuffer;
429 unsigned long CabinetReservedFileSize;
430 FILEHANDLE FileHandle;
431 bool FileOpen;
432 CFHEADER CABHeader;
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;
442 CCABCodec *Codec;
443 unsigned long CodecId;
444 bool CodecSelected;
445 void* InputBuffer;
446 void* CurrentIBuffer; // Current offset in input buffer
447 unsigned long CurrentIBufferSize; // Bytes left in input buffer
448 void* OutputBuffer;
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;
453 bool RestartSearch;
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)
460 bool CreateNewDisk;
461 bool CreateNewFolder;
462
463 CCFDATAStorage *ScratchFile;
464 FILEHANDLE SourceFile;
465 bool ContinueFile;
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 */
470 };
471
472 #endif /* __CABINET_H */
473
474 /* EOF */