2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS cabinet manager
4 * FILE: tools/cabman/main.cpp
5 * PURPOSE: Main program
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 21/03-2001 Created
9 * CSH 15/08-2003 Made it portable
20 unsigned long DebugTraceLevel = MIN_TRACE;
21 //unsigned long DebugTraceLevel = MID_TRACE;
22 //unsigned long DebugTraceLevel = MAX_TRACE;
27 #define CM_VERSION "0.9"
30 char* Pad(char* Str, char PadChar, unsigned int Length)
32 * FUNCTION: Pads a string with a character to make a given length
34 * Str = Pointer to string to pad
35 * PadChar = Character to pad with
36 * Length = Disired length of string
40 * Str must be at least Length + 1 bytes
48 memcpy(&Str[Length - Len], Str, Len + 1);
49 memset(Str, PadChar, Length - Len);
55 char* Date2Str(char* Str, unsigned short 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, unsigned short 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, unsigned short 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;
178 CCABManager::~CCABManager()
180 * FUNCTION: Default destructor
186 void CCABManager::Usage()
188 * FUNCTION: Display usage information on screen
191 printf("ReactOS Cabinet Manager - Version %s\n\n", CM_VERSION);
192 printf("CABMAN [/D | /E] [/A] [/L dir] cabinet [filename ...]\n");
193 printf("CABMAN /C dirfile [/I] [/RC file]\n");
194 printf("CABMAN /S cabinet filename\n");
195 printf(" cabinet Cabinet file.\n");
196 printf(" filename Name of the file to extract from the cabinet.\n");
197 printf(" Wild cards and multiple filenames\n");
198 printf(" (separated by blanks) may be used.\n\n");
200 printf(" dirfile Name of the directive file to use.\n");
202 printf(" /A Process ALL cabinets. Follows cabinet chain\n");
203 printf(" starting in first cabinet mentioned.\n");
204 printf(" /C Create cabinet.\n");
205 printf(" /D Display cabinet directory.\n");
206 printf(" /E Extract files from cabinet.\n");
207 printf(" /I Don't create the cabinet, only the .inf file.\n");
208 printf(" /L dir Location to place extracted or generated files\n");
209 printf(" (default is current directory).\n");
210 printf(" /N Don't create the .inf file, only the cabinet.\n");
211 printf(" /RC Specify file to put in cabinet reserved area\n");
212 printf(" (size must be less than 64KB).\n");
213 printf(" /S Create simple cabinet.\n");
216 bool CCABManager::ParseCmdline(int argc, char* argv[])
218 * FUNCTION: Parse command line arguments
220 * argc = Number of arguments on command line
221 * argv = Pointer to list of command line arguments
223 * true if command line arguments was successfully parsed, false if not
228 bool FoundCabinet = false;
230 ShowUsage = (argc < 2);
232 for (i = 1; i < argc; i++) {
233 if (argv[i][0] == '/') {
234 switch (argv[i][1]) {
236 case 'A': ProcessAll = true; break;
238 case 'C': Mode = CM_MODE_CREATE; break;
240 case 'D': Mode = CM_MODE_DISPLAY; break;
242 case 'E': Mode = CM_MODE_EXTRACT; break;
244 case 'I': InfFileOnly = true; break;
247 if (argv[i][2] == 0) {
249 SetDestinationPath((char*)&argv[i][0]);
251 SetDestinationPath((char*)&argv[i][1]);
255 case 'N': DontGenerateInf = true; break;
257 switch (argv[i][2]) {
258 case 'C': /* File to put in cabinet reserved area */
259 if (argv[i][3] == 0) {
261 if (!SetCabinetReservedFile((char*)&argv[i][0])) {
262 printf("Cannot open cabinet reserved area file.\n");
266 if (!SetCabinetReservedFile((char*)&argv[i][3])) {
267 printf("Cannot open cabinet reserved area file.\n");
273 printf("Bad parameter %s.\n", argv[i]);
278 case 'S': Mode = CM_MODE_CREATE_SIMPLE; break;
280 printf("Bad parameter %s.\n", argv[i]);
284 if ((FoundCabinet) || (Mode == CM_MODE_CREATE)) {
285 /* FIXME: There may be many of these if Mode != CM_MODE_CREATE */
286 strcpy((char*)FileName, argv[i]);
288 SetCabinetName(argv[i]);
300 SelectCodec(CAB_CODEC_MSZIP);
306 bool CCABManager::CreateCabinet()
308 * FUNCTION: Create cabinet
311 unsigned long Status;
313 Status = Load((char*)&FileName);
314 if (Status != CAB_STATUS_SUCCESS) {
315 printf("Specified directive file could not be found: %s.\n", (char*)&FileName);
325 bool CCABManager::CreateSimpleCabinet()
327 * FUNCTION: Create cabinet
330 unsigned long Status;
332 Status = NewCabinet();
333 if (Status != CAB_STATUS_SUCCESS) {
334 DPRINT(MIN_TRACE, ("Cannot create cabinet (%d).\n", (unsigned int)Status));
338 Status = AddFile(FileName);
339 if (Status != CAB_STATUS_SUCCESS) {
340 DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%d).\n", (unsigned int)Status));
344 Status = WriteDisk(false);
345 if (Status == CAB_STATUS_SUCCESS)
346 Status = CloseDisk();
347 if (Status != CAB_STATUS_SUCCESS) {
348 DPRINT(MIN_TRACE, ("Cannot write disk (%d).\n", (unsigned int)Status));
358 bool CCABManager::DisplayCabinet()
360 * FUNCTION: Display cabinet contents
365 unsigned long FileCount = 0;
366 unsigned long ByteCount = 0;
368 if (Open() == CAB_STATUS_SUCCESS) {
369 printf("Cabinet %s\n\n", GetCabinetName());
371 if (FindFirst("", &Search) == CAB_STATUS_SUCCESS) {
373 if (Search.File->FileControlID != CAB_FILE_CONTINUED) {
374 printf("%s ", Date2Str((char*)&Str, Search.File->FileDate));
375 printf("%s ", Time2Str((char*)&Str, Search.File->FileTime));
376 printf("%s ", Attr2Str((char*)&Str, Search.File->Attributes));
377 sprintf(Str, "%d", Search.File->FileSize);
378 printf("%s ", Pad(Str, ' ', 13));
379 printf("%s\n", Search.FileName);
382 ByteCount += Search.File->FileSize;
384 } while (FindNext(&Search) == CAB_STATUS_SUCCESS);
391 sprintf(Str, "%d", FileCount);
392 printf(" %s files ", Pad(Str, ' ', 12));
398 sprintf(Str, "%d", ByteCount);
399 printf("%s bytes\n", Pad(Str, ' ', 12));
402 /* There should be at least one file in a cabinet */
403 printf("No files in cabinet.");
407 printf("Cannot not open file: %s\n", GetCabinetName());
413 bool CCABManager::ExtractFromCabinet()
415 * FUNCTION: Extract file(s) from cabinet
419 unsigned long Status;
421 if (Open() == CAB_STATUS_SUCCESS) {
422 printf("Cabinet %s\n\n", GetCabinetName());
424 if (FindFirst("", &Search) == CAB_STATUS_SUCCESS) {
426 switch (Status = ExtractFile(Search.FileName)) {
427 case CAB_STATUS_SUCCESS:
429 case CAB_STATUS_INVALID_CAB:
430 printf("Cabinet contains errors.\n");
432 case CAB_STATUS_UNSUPPCOMP:
433 printf("Cabinet uses unsupported compression type.\n");
435 case CAB_STATUS_CANNOT_WRITE:
436 printf("You've run out of free space on the destination volume or the volume is damaged.\n");
439 printf("Unspecified error code (%d).\n", (unsigned int)Status);
442 } while (FindNext(&Search) == CAB_STATUS_SUCCESS);
446 printf("Cannot not open file: %s.\n", GetCabinetName());
452 bool CCABManager::Run()
454 * FUNCTION: Process cabinet
457 printf("ReactOS Cabinet Manager - Version %s\n\n", CM_VERSION);
460 case CM_MODE_CREATE: return CreateCabinet(); break;
461 case CM_MODE_DISPLAY: return DisplayCabinet(); break;
462 case CM_MODE_EXTRACT: return ExtractFromCabinet(); break;
463 case CM_MODE_CREATE_SIMPLE: return CreateSimpleCabinet(); break;
473 bool CCABManager::OnOverwrite(PCFFILE File,
476 * FUNCTION: Called when extracting a file and it already exists
478 * File = Pointer to CFFILE for file being extracted
479 * Filename = Pointer to buffer with name of file (full path)
481 * true if the file should be overwritten, false if not
486 if (Mode == CM_MODE_CREATE)
489 /* Always overwrite */
494 void CCABManager::OnExtract(PCFFILE File,
497 * FUNCTION: Called just before extracting a file
499 * File = Pointer to CFFILE for file being extracted
500 * FileName = Pointer to buffer with name of file (full path)
503 printf("Extracting %s\n", GetFileName(FileName));
508 void CCABManager::OnDiskChange(char* CabinetName,
511 * FUNCTION: Called when a new disk is to be processed
513 * CabinetName = Pointer to buffer with name of cabinet
514 * DiskLabel = Pointer to buffer with label of disk
517 printf("\nChanging to cabinet %s - %s\n\n", CabinetName, DiskLabel);
521 void CCABManager::OnAdd(PCFFILE File,
524 * FUNCTION: Called just before adding a file to a cabinet
526 * File = Pointer to CFFILE for file being added
527 * FileName = Pointer to buffer with name of file (full path)
530 printf("Adding %s\n", GetFileName(FileName));
534 int main(int argc, char * argv[])
536 * FUNCTION: Main entry point
538 * argc = Number of arguments on command line
539 * argv = Pointer to list of command line arguments
545 if (CABMgr.ParseCmdline(argc, argv)) {
546 status = CABMgr.Run();