2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS cabinet manager
4 * FILE: tools/cabman/main.cxx
5 * PURPOSE: Main program
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Colin Finck <mail@colinfinck.de>
9 * CSH 21/03-2001 Created
10 * CSH 15/08-2003 Made it portable
11 * CF 04/05-2007 Made it compatible with 64-bit operating systems
22 ULONG DebugTraceLevel
= MIN_TRACE
;
23 //ULONG DebugTraceLevel = MID_TRACE;
24 //ULONG DebugTraceLevel = MAX_TRACE;
29 char* Pad(char* Str
, char PadChar
, ULONG Length
)
31 * FUNCTION: Pads a string with a character to make a given length
33 * Str = Pointer to string to pad
34 * PadChar = Character to pad with
35 * Length = Disired length of string
39 * Str must be at least Length + 1 bytes
44 Len
= (ULONG
)strlen(Str
);
48 memcpy(&Str
[Length
- Len
], Str
, Len
+ 1);
49 memset(Str
, PadChar
, Length
- Len
);
55 char* Date2Str(char* Str
, USHORT Date
)
57 * FUNCTION: Converts a DOS style date to a string
59 * Str = Pointer to destination string
60 * Date = DOS style date
68 Str
[0] = (char)('0' + ((Date
& 0x01E0) >> 5) / 10);
69 Str
[1] = (char)('0' + ((Date
& 0x01E0) >> 5) % 10);
72 Str
[3] = (char)('0' + (Date
& 0x001F) / 10);
73 Str
[4] = (char)('0' + (Date
& 0x001F) % 10);
76 dw
= 1980 + ((Date
& 0xFE00) >> 9);
77 Str
[6] = (char)('0' + dw
/ 1000); dw
%= 1000;
78 Str
[7] = (char)('0' + dw
/ 100); dw
%= 100;
79 Str
[8] = (char)('0' + dw
/ 10); dw
%= 10;
80 Str
[9] = (char)('0' + dw
% 10);
86 char* Time2Str(char* Str
, USHORT Time
)
88 * FUNCTION: Converts a DOS style time to a string
90 * Str = Pointer to destination string
91 * Time = DOS style time
100 Hour
= ((Time
& 0xF800) >> 11);
107 Str
[0] = (char)('0' + Hour
/ 10);
109 Str
[1] = (char)('0' + Hour
% 10);
112 Str
[3] = (char)('0' + ((Time
& 0x07E0) >> 5) / 10);
113 Str
[4] = (char)('0' + ((Time
& 0x07E0) >> 5) % 10);
116 dw
= 2 * (Time
& 0x001F);
117 Str
[6] = (char)('0' + dw
/ 10);
118 Str
[7] = (char)('0' + dw
% 10);
120 Str
[8] = PM
? 'p' : 'a';
126 char* Attr2Str(char* Str
, USHORT Attr
)
128 * FUNCTION: Converts attributes to a string
130 * Str = Pointer to destination string
137 if (Attr
& CAB_ATTRIB_ARCHIVE
)
143 if (Attr
& CAB_ATTRIB_HIDDEN
)
149 if (Attr
& CAB_ATTRIB_READONLY
)
155 if (Attr
& CAB_ATTRIB_SYSTEM
)
167 CCABManager::CCABManager()
169 * FUNCTION: Default constructor
174 Mode
= CM_MODE_DISPLAY
;
180 CCABManager::~CCABManager()
182 * FUNCTION: Default destructor
188 void CCABManager::Usage()
190 * FUNCTION: Display usage information on screen
193 printf("ReactOS Cabinet Manager\n\n");
194 printf("CABMAN [-D | -E] [-A] [-L dir] cabinet [filename ...]\n");
195 printf("CABMAN [-M mode] -C dirfile [-I] [-RC file] [-P dir]\n");
196 printf("CABMAN [-M mode] -S cabinet filename [...]\n");
197 printf(" cabinet Cabinet file.\n");
198 printf(" filename Name of the file to add to or extract from the cabinet.\n");
199 printf(" Wild cards and multiple filenames\n");
200 printf(" (separated by blanks) may be used.\n\n");
202 printf(" dirfile Name of the directive file to use.\n");
204 printf(" -A Process ALL cabinets. Follows cabinet chain\n");
205 printf(" starting in first cabinet mentioned.\n");
206 printf(" -C Create cabinet.\n");
207 printf(" -D Display cabinet directory.\n");
208 printf(" -E Extract files from cabinet.\n");
209 printf(" -I Don't create the cabinet, only the .inf file.\n");
210 printf(" -L dir Location to place extracted or generated files\n");
211 printf(" (default is current directory).\n");
212 printf(" -M mode Specify the compression method to use:\n");
213 printf(" raw - No compression\n");
214 printf(" mszip - MsZip compression (default)\n");
215 printf(" -N Don't create the .inf file, only the cabinet.\n");
216 printf(" -RC Specify file to put in cabinet reserved area\n");
217 printf(" (size must be less than 64KB).\n");
218 printf(" -S Create simple cabinet.\n");
219 printf(" -P dir Files in the .dff are relative to this directory.\n");
220 printf(" -V Verbose mode (prints more messages).\n");
223 bool CCABManager::ParseCmdline(int argc
, char* argv
[])
225 * FUNCTION: Parse command line arguments
227 * argc = Number of arguments on command line
228 * argv = Pointer to list of command line arguments
230 * true if command line arguments was successfully parsed, false if not
235 bool FoundCabinet
= false;
237 ShowUsage
= (argc
< 2);
239 for (i
= 1; i
< argc
; i
++)
241 if (argv
[i
][0] == '-')
252 Mode
= CM_MODE_CREATE
;
257 Mode
= CM_MODE_DISPLAY
;
262 Mode
= CM_MODE_EXTRACT
;
275 SetDestinationPath(&argv
[i
][0]);
278 SetDestinationPath(&argv
[i
][2]);
284 // Set the compression codec (only affects compression, not decompression)
289 if( !SetCompressionCodec(&argv
[i
][0]) )
294 if( !SetCompressionCodec(&argv
[i
][2]) )
302 DontGenerateInf
= true;
308 case 'C': /* File to put in cabinet reserved area */
312 if (!SetCabinetReservedFile(&argv
[i
][0]))
314 printf("ERROR: Cannot open cabinet reserved area file.\n");
320 if (!SetCabinetReservedFile(&argv
[i
][3]))
322 printf("ERROR: Cannot open cabinet reserved area file.\n");
329 printf("ERROR: Bad parameter %s.\n", argv
[i
]);
336 Mode
= CM_MODE_CREATE_SIMPLE
;
343 SetFileRelativePath(&argv
[i
][0]);
346 SetFileRelativePath(&argv
[i
][2]);
355 printf("ERROR: Bad parameter %s.\n", argv
[i
]);
361 if(Mode
== CM_MODE_CREATE
)
365 printf("ERROR: You may only specify one directive file!\n");
370 // For creating cabinets, this argument is the path to the directive file
371 strcpy(FileName
, argv
[i
]);
374 else if(FoundCabinet
)
376 // For creating simple cabinets, displaying or extracting them, add the argument as a search criteria
377 AddSearchCriteria(argv
[i
]);
381 SetCabinetName(argv
[i
]);
393 // Select MsZip by default for creating cabinets
394 if( (Mode
== CM_MODE_CREATE
|| Mode
== CM_MODE_CREATE_SIMPLE
) && !IsCodecSelected() )
395 SelectCodec(CAB_CODEC_MSZIP
);
397 // Search criteria (= the filename argument) is necessary for creating a simple cabinet
398 if( Mode
== CM_MODE_CREATE_SIMPLE
&& !HasSearchCriteria())
400 printf("ERROR: You have to enter input file names!\n");
408 bool CCABManager::CreateCabinet()
410 * FUNCTION: Create cabinet
415 Status
= Load(FileName
);
416 if (Status
!= CAB_STATUS_SUCCESS
)
418 printf("ERROR: Specified directive file could not be found: %s.\n", FileName
);
424 return (Status
== CAB_STATUS_SUCCESS
? true : false);
427 bool CCABManager::DisplayCabinet()
429 * FUNCTION: Display cabinet contents
437 if (Open() == CAB_STATUS_SUCCESS
)
441 printf("Cabinet %s\n\n", GetCabinetName());
444 if (FindFirst(&Search
) == CAB_STATUS_SUCCESS
)
448 if (Search
.File
->FileControlID
!= CAB_FILE_CONTINUED
)
450 printf("%s ", Date2Str(Str
, Search
.File
->FileDate
));
451 printf("%s ", Time2Str(Str
, Search
.File
->FileTime
));
452 printf("%s ", Attr2Str(Str
, Search
.File
->Attributes
));
453 sprintf(Str
, "%u", (UINT
)Search
.File
->FileSize
);
454 printf("%s ", Pad(Str
, ' ', 13));
455 printf("%s\n", Search
.FileName
);
458 ByteCount
+= Search
.File
->FileSize
;
460 } while (FindNext(&Search
) == CAB_STATUS_SUCCESS
);
463 DestroySearchCriteria();
470 sprintf(Str
, "%u", (UINT
)FileCount
);
471 printf(" %s files ", Pad(Str
, ' ', 12));
478 sprintf(Str
, "%u", (UINT
)ByteCount
);
479 printf("%s bytes\n", Pad(Str
, ' ', 12));
484 /* There should be at least one file in a cabinet */
485 printf("WARNING: No files in cabinet.");
490 printf("ERROR: Cannot open file: %s\n", GetCabinetName());
496 bool CCABManager::ExtractFromCabinet()
498 * FUNCTION: Extract file(s) from cabinet
505 if (Open() == CAB_STATUS_SUCCESS
)
509 printf("Cabinet %s\n\n", GetCabinetName());
512 if (FindFirst(&Search
) == CAB_STATUS_SUCCESS
)
516 switch (Status
= ExtractFile(Search
.FileName
))
518 case CAB_STATUS_SUCCESS
:
521 case CAB_STATUS_INVALID_CAB
:
522 printf("ERROR: Cabinet contains errors.\n");
526 case CAB_STATUS_UNSUPPCOMP
:
527 printf("ERROR: Cabinet uses unsupported compression type.\n");
531 case CAB_STATUS_CANNOT_WRITE
:
532 printf("ERROR: You've run out of free space on the destination volume or the volume is damaged.\n");
537 printf("ERROR: Unspecified error code (%u).\n", (UINT
)Status
);
544 } while (FindNext(&Search
) == CAB_STATUS_SUCCESS
);
546 DestroySearchCriteria();
552 printf("ERROR: Cannot open file: %s.\n", GetCabinetName());
558 bool CCABManager::Run()
560 * FUNCTION: Process cabinet
565 printf("ReactOS Cabinet Manager\n\n");
571 return CreateCabinet();
573 case CM_MODE_DISPLAY
:
574 return DisplayCabinet();
576 case CM_MODE_EXTRACT
:
577 return ExtractFromCabinet();
579 case CM_MODE_CREATE_SIMPLE
:
580 return CreateSimpleCabinet();
591 bool CCABManager::OnOverwrite(PCFFILE File
,
594 * FUNCTION: Called when extracting a file and it already exists
596 * File = Pointer to CFFILE for file being extracted
597 * Filename = Pointer to buffer with name of file (full path)
599 * true if the file should be overwritten, false if not
602 if (Mode
== CM_MODE_CREATE
)
605 /* Always overwrite */
610 void CCABManager::OnExtract(PCFFILE File
,
613 * FUNCTION: Called just before extracting a file
615 * File = Pointer to CFFILE for file being extracted
616 * FileName = Pointer to buffer with name of file (full path)
621 printf("Extracting %s\n", GetFileName(FileName
));
627 void CCABManager::OnDiskChange(char* CabinetName
,
630 * FUNCTION: Called when a new disk is to be processed
632 * CabinetName = Pointer to buffer with name of cabinet
633 * DiskLabel = Pointer to buffer with label of disk
638 printf("\nChanging to cabinet %s - %s\n\n", CabinetName
, DiskLabel
);
643 void CCABManager::OnAdd(PCFFILE File
,
646 * FUNCTION: Called just before adding a file to a cabinet
648 * File = Pointer to CFFILE for file being added
649 * FileName = Pointer to buffer with name of file (full path)
654 printf("Adding %s\n", GetFileName(FileName
));
660 int main(int argc
, char * argv
[])
662 * FUNCTION: Main entry point
664 * argc = Number of arguments on command line
665 * argv = Pointer to list of command line arguments
670 if (CABMgr
.ParseCmdline(argc
, argv
)) status
= CABMgr
.Run();
672 return (status
? 0 : 1);