2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS cabinet manager
4 * FILE: apps/cabman/dfp.cpp
5 * PURPOSE: Directive file parser
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * NOTES: The directive file format is similar to the
8 * directive file format used by Microsoft's MAKECAB
10 * CSH 21/03-2001 Created
21 CDFParser::CDFParser()
23 * FUNCTION: Default constructor
30 CabinetCreated
= FALSE
;
32 FolderCreated
= FALSE
;
37 MaxDiskSizeAllSet
= FALSE
;
38 CabinetNameTemplateSet
= FALSE
;
39 DiskLabelTemplateSet
= FALSE
;
43 CDFParser::~CDFParser()
45 * FUNCTION: Default destructor
54 HeapFree(GetProcessHeap(), 0, FileBuffer
);
56 while (CNNext
!= NULL
) {
57 CNPrev
= CNNext
->Next
;
58 HeapFree(GetProcessHeap(), 0, CNNext
);
62 while (CNNext
!= NULL
) {
63 CNPrev
= CNNext
->Next
;
64 HeapFree(GetProcessHeap(), 0, CNNext
);
68 while (DNNext
!= NULL
) {
69 DNPrev
= DNNext
->Next
;
70 HeapFree(GetProcessHeap(), 0, DNNext
);
76 ULONG
CDFParser::Load(LPTSTR FileName
)
78 * FUNCTION: Loads a directive file into memory
80 * FileName = Pointer to name of directive file
89 return CAB_STATUS_SUCCESS
;
91 /* Create cabinet file, overwrite if it already exists */
92 FileHandle
= CreateFile(FileName
, // Create this file
93 GENERIC_READ
, // Open for reading
96 OPEN_EXISTING
, // Open the file
97 FILE_ATTRIBUTE_NORMAL
, // Normal file
98 NULL
); // No attribute template
99 if (FileHandle
== INVALID_HANDLE_VALUE
)
100 return CAB_STATUS_CANNOT_OPEN
;
102 FileSize
= GetFileSize(FileHandle
, NULL
);
104 CloseHandle(FileHandle
);
105 return CAB_STATUS_CANNOT_OPEN
;
108 FileBufferSize
= (ULONG
)FileSize
;
110 FileBuffer
= (PCHAR
)HeapAlloc(GetProcessHeap(), 0, FileBufferSize
);
112 CloseHandle(FileHandle
);
113 return CAB_STATUS_NOMEMORY
;
116 if (!ReadFile(FileHandle
, FileBuffer
, FileBufferSize
, &BytesRead
, NULL
)) {
117 CloseHandle(FileHandle
);
118 HeapFree(GetProcessHeap(), 0, FileBuffer
);
120 return CAB_STATUS_CANNOT_READ
;
123 CloseHandle(FileHandle
);
127 DPRINT(MAX_TRACE
, ("File (%d bytes)\n", FileBufferSize
));
129 return CAB_STATUS_SUCCESS
;
133 ULONG
CDFParser::Parse()
135 * FUNCTION: Parses a loaded directive file
137 * Status of operation
144 return CAB_STATUS_NOFILE
;
149 while (CurrentToken
!= TokenEnd
) {
150 switch (CurrentToken
) {
152 itoa(CurrentInteger
, (LPTSTR
)&CurrentString
, 10);
153 case TokenIdentifier
:
156 Status
= PerformCommand();
158 if (Status
== CAB_STATUS_FAILURE
) {
159 printf("Directive file contains errors at line %d.\n", (UINT
)CurrentLine
);
160 DPRINT(MID_TRACE
, ("Error while executing command.\n"));
163 if (Status
!= CAB_STATUS_SUCCESS
)
167 Status
= PerformFileCopy();
169 if (Status
== CAB_STATUS_FAILURE
) {
170 printf("Directive file contains errors at line %d.\n", (UINT
)CurrentLine
);
171 DPRINT(MID_TRACE
, ("Error while copying file.\n"));
174 if (Status
!= CAB_STATUS_SUCCESS
)
181 CurrentToken
= TokenEnd
;
187 printf("Directive file contains errors at line %d.\n", (UINT
)CurrentLine
);
188 DPRINT(MIN_TRACE
, ("Token is (%d).\n", (UINT
)CurrentToken
));
189 return CAB_STATUS_SUCCESS
;
195 printf("\nWriting cabinet. This may take a while...\n\n");
198 Status
= WriteDisk(FALSE
);
199 if (Status
== CAB_STATUS_SUCCESS
)
200 Status
= CloseDisk();
201 if (Status
!= CAB_STATUS_SUCCESS
) {
202 DPRINT(MIN_TRACE
, ("Cannot write disk (%d).\n", (UINT
)Status
));
207 if (CabinetCreated
) {
208 Status
= CloseCabinet();
209 if (Status
!= CAB_STATUS_SUCCESS
) {
210 DPRINT(MIN_TRACE
, ("Cannot close cabinet (%d).\n", (UINT
)Status
));
217 return CAB_STATUS_SUCCESS
;
221 BOOL
CDFParser::OnDiskLabel(ULONG Number
, LPTSTR Label
)
223 * FUNCTION: Called when a disk needs a label
225 * Number = Cabinet number that needs a label
226 * Label = Pointer to buffer to place label of disk
228 * TRUE if a disk label was returned, FALSE if not
237 DPRINT(MID_TRACE
, ("Giving disk (%d) a label...\n", (UINT
)Number
));
239 if (GetDiskName(&DiskLabel
, Number
, Label
))
242 if (DiskLabelTemplateSet
) {
245 for (i
= 0; i
< lstrlen(DiskLabelTemplate
); i
++) {
246 ch
= DiskLabelTemplate
[i
];
248 lstrcat(Label
, itoa(Number
, Buffer
, 10));
249 j
+= lstrlen(Buffer
);
257 DPRINT(MID_TRACE
, ("Giving disk (%s) as a label...\n", Label
));
265 BOOL
CDFParser::OnCabinetName(ULONG Number
, LPTSTR Name
)
267 * FUNCTION: Called when a cabinet needs a name
269 * Number = Disk number that needs a name
270 * Name = Pointer to buffer to place name of cabinet
272 * TRUE if a cabinet name was returned, FALSE if not
281 DPRINT(MID_TRACE
, ("Giving cabinet (%d) a name...\n", (UINT
)Number
));
283 if (GetDiskName(&CabinetName
, Number
, Name
))
286 if (CabinetNameTemplateSet
) {
289 for (i
= 0; i
< lstrlen(CabinetNameTemplate
); i
++) {
290 ch
= CabinetNameTemplate
[i
];
292 lstrcat(Name
, itoa(Number
, Buffer
, 10));
293 j
+= lstrlen(Buffer
);
301 DPRINT(MID_TRACE
, ("Giving cabinet (%s) as a name...\n", Name
));
309 BOOL
CDFParser::SetDiskName(PCABINET_NAME
*List
, ULONG Number
, LPTSTR String
)
311 * FUNCTION: Sets an entry in a list
313 * List = Address of pointer to list
314 * Number = Disk number
315 * String = Pointer to string
317 * FALSE if there was not enough free memory available
324 if (CN
->DiskNumber
== Number
) {
325 lstrcpy(CN
->Name
, String
);
331 CN
= (PCABINET_NAME
)HeapAlloc(GetProcessHeap(), 0, sizeof(CABINET_NAME
));
335 CN
->DiskNumber
= Number
;
336 lstrcpy(CN
->Name
, String
);
345 BOOL
CDFParser::GetDiskName(PCABINET_NAME
*List
, ULONG Number
, LPTSTR String
)
347 * FUNCTION: Returns an entry in a list
349 * List = Address of pointer to list
350 * Number = Disk number
351 * String = Address of buffer to copy string to
353 * FALSE if there was not enough free memory available
360 if (CN
->DiskNumber
== Number
) {
361 lstrcpy(String
, CN
->Name
);
371 BOOL
CDFParser::SetDiskNumber(PDISK_NUMBER
*List
, ULONG Number
, ULONG Value
)
373 * FUNCTION: Sets an entry in a list
375 * List = Address of pointer to list
376 * Number = Disk number
377 * Value = Value to set
379 * FALSE if there was not enough free memory available
386 if (DN
->DiskNumber
== Number
) {
393 DN
= (PDISK_NUMBER
)HeapAlloc(GetProcessHeap(), 0, sizeof(DISK_NUMBER
));
397 DN
->DiskNumber
= Number
;
407 BOOL
CDFParser::GetDiskNumber(PDISK_NUMBER
*List
, ULONG Number
, PULONG Value
)
409 * FUNCTION: Returns an entry in a list
411 * List = Address of pointer to list
412 * Number = Disk number
413 * Value = Address of buffer to place value
415 * TRUE if the entry was found
422 if (DN
->DiskNumber
== Number
) {
433 BOOL
CDFParser::DoDiskLabel(ULONG Number
, LPTSTR Label
)
435 * FUNCTION: Sets the label of a disk
437 * Number = Disk number
438 * Label = Pointer to label of disk
440 * FALSE if there was not enough free memory available
443 DPRINT(MID_TRACE
, ("Setting label of disk (%d) to '%s'\n", (UINT
)Number
, Label
));
445 return SetDiskName(&DiskLabel
, Number
, Label
);
449 VOID
CDFParser::DoDiskLabelTemplate(LPTSTR Template
)
451 * FUNCTION: Sets a disk label template to use
453 * Template = Pointer to disk label template
456 DPRINT(MID_TRACE
, ("Setting disk label template to '%s'\n", Template
));
458 lstrcpy(DiskLabelTemplate
, Template
);
459 DiskLabelTemplateSet
= TRUE
;
463 BOOL
CDFParser::DoCabinetName(ULONG Number
, LPTSTR Name
)
465 * FUNCTION: Sets the name of a cabinet
467 * Number = Disk number
468 * Name = Pointer to name of cabinet
470 * FALSE if there was not enough free memory available
473 DPRINT(MID_TRACE
, ("Setting name of cabinet (%d) to '%s'\n", (UINT
)Number
, Name
));
475 return SetDiskName(&CabinetName
, Number
, Name
);
479 VOID
CDFParser::DoCabinetNameTemplate(LPTSTR Template
)
481 * FUNCTION: Sets a cabinet name template to use
483 * Template = Pointer to cabinet name template
486 DPRINT(MID_TRACE
, ("Setting cabinet name template to '%s'\n", Template
));
488 lstrcpy(CabinetNameTemplate
, Template
);
489 CabinetNameTemplateSet
= TRUE
;
493 ULONG
CDFParser::DoMaxDiskSize(BOOL NumberValid
, ULONG Number
)
495 * FUNCTION: Sets the maximum disk size
497 * NumberValid = TRUE if disk number is valid
498 * Number = Disk number
500 * Status of operation
502 * Standard sizes are 2.88M, 1.44M, 1.25M, 1.2M, 720K, 360K, and CDROM
507 if (IsNextToken(TokenInteger
, TRUE
)) {
511 if (IsNextToken(TokenPeriod
, FALSE
)) {
512 if (!IsNextToken(TokenInteger
, FALSE
))
513 return CAB_STATUS_FAILURE
;
520 if (CurrentToken
== TokenIdentifier
) {
521 switch (CurrentString
[0]) {
524 return CAB_STATUS_FAILURE
;
533 return CAB_STATUS_FAILURE
;
542 Value
= 1300000; // FIXME: Value?
547 return CAB_STATUS_FAILURE
;
553 return CAB_STATUS_FAILURE
;
555 return CAB_STATUS_FAILURE
;
558 DPRINT(MID_TRACE
, ("Bad suffix (%c)\n", CurrentString
[0]));
559 return CAB_STATUS_FAILURE
;
564 if ((CurrentToken
!= TokenString
) &&
565 (strcmpi(CurrentString
, "CDROM") != 0))
566 return CAB_STATUS_FAILURE
;
568 Value
= 640*1024*1024; // FIXME: Correct size for CDROM?
572 return (SetDiskNumber(&MaxDiskSize
, Number
, Value
)?
573 CAB_STATUS_SUCCESS
: CAB_STATUS_FAILURE
);
575 MaxDiskSizeAll
= Value
;
576 MaxDiskSizeAllSet
= TRUE
;
578 SetMaxDiskSize(Value
);
580 return CAB_STATUS_SUCCESS
;
584 ULONG
CDFParser::SetupNewDisk()
586 * FUNCTION: Sets up parameters for a new disk
588 * Status of operation
593 if (!GetDiskNumber(&MaxDiskSize
, GetCurrentDiskNumber(), &Value
)) {
594 if (MaxDiskSizeAllSet
)
595 Value
= MaxDiskSizeAll
;
599 SetMaxDiskSize(Value
);
601 return CAB_STATUS_SUCCESS
;
605 ULONG
CDFParser::PerformSetCommand()
607 * FUNCTION: Performs a set variable command
609 * Status of operation
613 BOOL NumberValid
= FALSE
;
616 if (!IsNextToken(TokenIdentifier
, TRUE
))
617 return CAB_STATUS_FAILURE
;
619 if (strcmpi(CurrentString
, "DiskLabel") == 0)
620 SetType
= stDiskLabel
;
621 else if (strcmpi(CurrentString
, "DiskLabelTemplate") == 0)
622 SetType
= stDiskLabelTemplate
;
623 else if (strcmpi(CurrentString
, "CabinetName") == 0)
624 SetType
= stCabinetName
;
625 else if (strcmpi(CurrentString
, "CabinetNameTemplate") == 0)
626 SetType
= stCabinetNameTemplate
;
627 else if (strcmpi(CurrentString
, "MaxDiskSize") == 0)
628 SetType
= stMaxDiskSize
;
630 return CAB_STATUS_FAILURE
;
632 if ((SetType
== stDiskLabel
) || (SetType
== stCabinetName
)) {
633 if (!IsNextToken(TokenInteger
, FALSE
))
634 return CAB_STATUS_FAILURE
;
635 Number
= CurrentInteger
;
637 if (!IsNextToken(TokenEqual
, TRUE
))
638 return CAB_STATUS_FAILURE
;
639 } else if (SetType
== stMaxDiskSize
) {
640 if (IsNextToken(TokenInteger
, FALSE
)) {
642 Number
= CurrentInteger
;
645 while (CurrentToken
== TokenSpace
)
647 if (CurrentToken
!= TokenEqual
)
648 return CAB_STATUS_FAILURE
;
650 } else if (!IsNextToken(TokenEqual
, TRUE
))
651 return CAB_STATUS_FAILURE
;
653 if (SetType
!= stMaxDiskSize
) {
654 if (!IsNextToken(TokenString
, TRUE
))
655 return CAB_STATUS_FAILURE
;
660 if (!DoDiskLabel(Number
, CurrentString
))
661 DPRINT(MIN_TRACE
, ("Not enough available free memory.\n"));
662 return CAB_STATUS_SUCCESS
;
664 if (!DoCabinetName(Number
, CurrentString
))
665 DPRINT(MIN_TRACE
, ("Not enough available free memory.\n"));
666 return CAB_STATUS_SUCCESS
;
667 case stDiskLabelTemplate
:
668 DoDiskLabelTemplate(CurrentString
);
669 return CAB_STATUS_SUCCESS
;
670 case stCabinetNameTemplate
:
671 DoCabinetNameTemplate(CurrentString
);
672 return CAB_STATUS_SUCCESS
;
674 return DoMaxDiskSize(NumberValid
, Number
);
676 return CAB_STATUS_FAILURE
;
681 ULONG
CDFParser::PerformNewCommand()
683 * FUNCTION: Performs a new disk|cabinet|folder command
685 * Status of operation
691 if (!IsNextToken(TokenIdentifier
, TRUE
))
692 return CAB_STATUS_FAILURE
;
694 if (strcmpi(CurrentString
, "Disk") == 0)
696 else if (strcmpi(CurrentString
, "Cabinet") == 0)
698 else if (strcmpi(CurrentString
, "Folder") == 0)
701 return CAB_STATUS_FAILURE
;
706 Status
= WriteDisk(TRUE
);
707 if (Status
== CAB_STATUS_SUCCESS
)
708 Status
= CloseDisk();
709 if (Status
!= CAB_STATUS_SUCCESS
) {
710 DPRINT(MIN_TRACE
, ("Cannot write disk (%d).\n", (UINT
)Status
));
711 return CAB_STATUS_SUCCESS
;
717 if (Status
!= CAB_STATUS_SUCCESS
) {
718 DPRINT(MIN_TRACE
, ("Cannot create disk (%d).\n", (UINT
)Status
));
719 return CAB_STATUS_SUCCESS
;
723 return CAB_STATUS_SUCCESS
;
726 Status
= WriteDisk(TRUE
);
727 if (Status
== CAB_STATUS_SUCCESS
)
728 Status
= CloseDisk();
729 if (Status
!= CAB_STATUS_SUCCESS
) {
730 DPRINT(MIN_TRACE
, ("Cannot write disk (%d).\n", (UINT
)Status
));
731 return CAB_STATUS_SUCCESS
;
736 Status
= NewCabinet();
737 if (Status
!= CAB_STATUS_SUCCESS
) {
738 DPRINT(MIN_TRACE
, ("Cannot create cabinet (%d).\n", (UINT
)Status
));
739 return CAB_STATUS_SUCCESS
;
743 return CAB_STATUS_SUCCESS
;
745 Status
= NewFolder();
746 ASSERT(Status
== CAB_STATUS_SUCCESS
);
747 return CAB_STATUS_SUCCESS
;
749 return CAB_STATUS_FAILURE
;
754 ULONG
CDFParser::PerformCommand()
756 * FUNCTION: Performs a command
758 * Status of operation
761 if (strcmpi(CurrentString
, "Set") == 0)
762 return PerformSetCommand();
763 if (strcmpi(CurrentString
, "New") == 0)
764 return PerformNewCommand();
766 return CAB_STATUS_FAILURE
;
770 ULONG
CDFParser::PerformFileCopy()
772 * FUNCTION: Performs a file copy
774 * Status of operation
780 TCHAR SrcName
[MAX_PATH
];
781 TCHAR DstName
[MAX_PATH
];
783 lstrcpy(SrcName
, "");
784 lstrcpy(DstName
, "");
786 i
= lstrlen(CurrentString
);
787 while ((i
< LineLength
) &&
788 ((ch
= Line
[i
]) != ' ') &&
791 CurrentString
[i
] = ch
;
794 CurrentString
[i
] = '\0';
795 CurrentToken
= TokenString
;
797 lstrcpy(SrcName
, CurrentString
);
801 if (CurrentToken
!= TokenEnd
) {
802 j
= lstrlen(CurrentString
); i
= 0;
803 while ((CurrentChar
+ i
< LineLength
) &&
804 ((ch
= Line
[CurrentChar
+ i
]) != ' ') &&
807 CurrentString
[j
+ i
] = ch
;
810 CurrentString
[j
+ i
] = '\0';
811 CurrentToken
= TokenString
;
812 CurrentChar
+= i
+ 1;
813 lstrcpy(DstName
, CurrentString
);
816 if (!CabinetCreated
) {
818 DPRINT(MID_TRACE
, ("Creating cabinet.\n"));
820 Status
= NewCabinet();
821 if (Status
!= CAB_STATUS_SUCCESS
) {
822 DPRINT(MIN_TRACE
, ("Cannot create cabinet (%d).\n", (UINT
)Status
));
823 printf("Cannot create cabinet.\n");
824 return CAB_STATUS_FAILURE
;
826 CabinetCreated
= TRUE
;
828 DPRINT(MID_TRACE
, ("Creating disk.\n"));
831 if (Status
!= CAB_STATUS_SUCCESS
) {
832 DPRINT(MIN_TRACE
, ("Cannot create disk (%d).\n", (UINT
)Status
));
833 printf("Cannot create disk.\n");
834 return CAB_STATUS_FAILURE
;
840 DPRINT(MID_TRACE
, ("Adding file: '%s' destination: '%s'.\n", SrcName
, DstName
));
842 Status
= AddFile(SrcName
);
843 if (Status
!= CAB_STATUS_SUCCESS
) {
844 if (Status
== CAB_STATUS_CANNOT_OPEN
)
845 printf("File does not exist: %s.\n", SrcName
);
846 else if (Status
== CAB_STATUS_NOMEMORY
)
847 printf("Insufficient memory to add file: %s.\n", SrcName
);
849 printf("Cannot add file: %s (%d).\n", SrcName
, Status
);
853 return CAB_STATUS_SUCCESS
;
857 VOID
CDFParser::SkipSpaces()
859 * FUNCTION: Skips any spaces in the current line
863 while (CurrentToken
== TokenSpace
)
868 BOOL
CDFParser::IsNextToken(TOKEN Token
, BOOL NoSpaces
)
870 * FUNCTION: Checks if next token equals Token
872 * Token = Token to compare with
873 * SkipSp = TRUE if spaces should be skipped
875 * FALSE if next token is diffrent from Token
882 return (CurrentToken
== Token
);
886 BOOL
CDFParser::ReadLine()
888 * FUNCTION: Reads the next line into the line buffer
890 * TRUE if there is a new line, FALSE if not
896 if (CurrentOffset
>= FileBufferSize
)
900 while (((j
= CurrentOffset
+ i
) < FileBufferSize
) && (i
< 127) &&
901 ((ch
= FileBuffer
[j
]) != 0x0D)) {
909 if (FileBuffer
[CurrentOffset
+ i
+ 1] == 0x0A)
912 CurrentOffset
+= i
+ 1;
924 VOID
CDFParser::NextToken()
926 * FUNCTION: Reads the next token from the current line
932 if (CurrentChar
>= LineLength
) {
933 CurrentToken
= TokenEnd
;
937 switch (Line
[CurrentChar
]) {
939 case 0x09: CurrentToken
= TokenSpace
;
941 case ';': CurrentToken
= TokenSemi
;
943 case '=': CurrentToken
= TokenEqual
;
945 case '.': CurrentToken
= TokenPeriod
;
947 case '\\': CurrentToken
= TokenBackslash
;
951 while ((CurrentChar
+ i
+ 1 < LineLength
) &&
952 ((ch
= Line
[CurrentChar
+ i
+ 1]) != '"')) {
953 CurrentString
[i
] = ch
;
956 CurrentString
[i
] = '\0';
957 CurrentToken
= TokenString
;
958 CurrentChar
+= i
+ 2;
962 while ((CurrentChar
+ i
< LineLength
) &&
963 ((ch
= Line
[CurrentChar
+ i
]) >= '0') && (ch
<= '9')) {
964 CurrentString
[i
] = ch
;
968 CurrentString
[i
] = '\0';
969 CurrentInteger
= atoi((PCHAR
)CurrentString
);
970 CurrentToken
= TokenInteger
;
975 while (((CurrentChar
+ i
< LineLength
) &&
976 (((ch
= Line
[CurrentChar
+ i
]) >= 'a') && (ch
<= 'z')) ||
977 ((ch
>= 'A') && (ch
<= 'Z')) || (ch
== '_'))) {
978 CurrentString
[i
] = ch
;
982 CurrentString
[i
] = '\0';
983 CurrentToken
= TokenIdentifier
;
987 CurrentToken
= TokenUnknown
;