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;