faede8131d7717b1aee846166584b0f771444eda
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
, "%lu", 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
, "%lu", FileCount
);
392 printf(" %s files ", Pad(Str
, ' ', 12));
398 sprintf(Str
, "%lu", 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
484 if (Mode
== CM_MODE_CREATE
)
487 /* Always overwrite */
492 void CCABManager::OnExtract(PCFFILE File
,
495 * FUNCTION: Called just before extracting a file
497 * File = Pointer to CFFILE for file being extracted
498 * FileName = Pointer to buffer with name of file (full path)
501 printf("Extracting %s\n", GetFileName(FileName
));
506 void CCABManager::OnDiskChange(char* CabinetName
,
509 * FUNCTION: Called when a new disk is to be processed
511 * CabinetName = Pointer to buffer with name of cabinet
512 * DiskLabel = Pointer to buffer with label of disk
515 printf("\nChanging to cabinet %s - %s\n\n", CabinetName
, DiskLabel
);
519 void CCABManager::OnAdd(PCFFILE File
,
522 * FUNCTION: Called just before adding a file to a cabinet
524 * File = Pointer to CFFILE for file being added
525 * FileName = Pointer to buffer with name of file (full path)
528 printf("Adding %s\n", GetFileName(FileName
));
532 int main(int argc
, char * argv
[])
534 * FUNCTION: Main entry point
536 * argc = Number of arguments on command line
537 * argv = Pointer to list of command line arguments
543 if (CABMgr
.ParseCmdline(argc
, argv
)) {
544 status
= CABMgr
.Run();