xref: /reactos/sdk/tools/cabman/dfp.cxx (revision cc439606)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS cabinet manager
4  * FILE:        tools/cabman/dfp.cxx
5  * PURPOSE:     Directive file parser
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Colin Finck <mail@colinfinck.de>
8  * NOTES:       The directive file format is similar to the
9  *              directive file format used by Microsoft's MAKECAB
10  * REVISIONS:
11  *   CSH 21/03-2001 Created
12  *   CSH 15/08-2003 Made it portable
13  *   CF  04/05-2007 Made it compatible with 64-bit operating systems
14  */
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include "cabman.h"
18 #include "dfp.h"
19 
20 /* CDFParser */
21 
22 CDFParser::CDFParser()
23 /*
24  * FUNCTION: Default constructor
25  */
26 {
27     InfFileOnly     = false;
28     DontGenerateInf = false;
29 
30     FileBuffer     = NULL;
31     FileLoaded     = false;
32     CurrentOffset  = 0;
33     CurrentLine    = 0;
34     CabinetCreated = false;
35     DiskCreated    = false;
36     FolderCreated  = false;
37     CabinetName    = NULL;
38     DiskLabel      = NULL;
39     MaxDiskSize    = NULL;
40 
41     MaxDiskSizeAllSet      = false;
42     CabinetNameTemplateSet = false;
43     DiskLabelTemplateSet   = false;
44     InfFileNameSet         = false;
45 
46     InfModeEnabled = false;
47     InfFileHandle = NULL;
48 
49     strcpy(FileRelativePath, "");
50 }
51 
52 CDFParser::~CDFParser()
53 /*
54  * FUNCTION: Default destructor
55  */
56 {
57     PCABINET_NAME CNPrev;
58     PCABINET_NAME CNNext;
59     PDISK_NUMBER DNPrev;
60     PDISK_NUMBER DNNext;
61 
62     if (FileBuffer)
63         free(FileBuffer);
64     CNNext = CabinetName;
65     while (CNNext != NULL)
66     {
67         CNPrev = CNNext->Next;
68         free(CNNext);
69         CNNext = CNPrev;
70     }
71     CNNext = DiskLabel;
72     while (CNNext != NULL)
73     {
74         CNPrev = CNNext->Next;
75         free(CNNext);
76         CNNext = CNPrev;
77     }
78     DNNext = MaxDiskSize;
79     while (DNNext != NULL)
80     {
81         DNPrev = DNNext->Next;
82         free(DNNext);
83         DNNext = DNPrev;
84     }
85 
86     if (InfFileHandle != NULL)
87         fclose(InfFileHandle);
88 }
89 
90 void CDFParser::WriteInfLine(char* InfLine)
91 {
92     char buf[PATH_MAX];
93     char eolbuf[2];
94     char* destpath;
95 
96     if (DontGenerateInf)
97         return;
98 
99     if (InfFileHandle == NULL)
100     {
101         if (!InfFileNameSet)
102             /* FIXME: Use cabinet name with extension .inf */
103             return;
104 
105         destpath = GetDestinationPath();
106         if (strlen(destpath) > 0)
107         {
108             strcpy(buf, destpath);
109             strcat(buf, InfFileName);
110         }
111         else
112             strcpy(buf, InfFileName);
113 
114         /* Create .inf file, overwrite if it already exists */
115         InfFileHandle = fopen(buf, "wb");
116         if (InfFileHandle == NULL)
117         {
118             DPRINT(MID_TRACE, ("Error creating INF file.\n"));
119             return;
120         }
121     }
122 
123     if (fwrite(InfLine, strlen(InfLine), 1, InfFileHandle) < 1)
124     {
125         DPRINT(MID_TRACE, ("Error writing INF file.\n"));
126         return;
127     }
128 
129     eolbuf[0] = 0x0d;
130     eolbuf[1] = 0x0a;
131 
132     if (fwrite(eolbuf, sizeof(eolbuf), 1, InfFileHandle) < 1)
133     {
134         DPRINT(MID_TRACE, ("Error writing INF file.\n"));
135         return;
136     }
137 }
138 
139 
140 ULONG CDFParser::Load(char* FileName)
141 /*
142  * FUNCTION: Loads a directive file into memory
143  * ARGUMENTS:
144  *     FileName = Pointer to name of directive file
145  * RETURNS:
146  *     Status of operation
147  */
148 {
149     LONG FileSize;
150 
151     if (FileLoaded)
152         return CAB_STATUS_SUCCESS;
153 
154     /* Open the directive file */
155     FileHandle = fopen(FileName, "rb");
156     if (FileHandle == NULL)
157     {
158         return CAB_STATUS_CANNOT_OPEN;
159     }
160 
161     FileSize = GetSizeOfFile(FileHandle);
162     if (FileSize == -1)
163     {
164         fclose(FileHandle);
165         return CAB_STATUS_CANNOT_OPEN;
166     }
167 
168     FileBufferSize = (ULONG)FileSize;
169 
170     FileBuffer = (char*)malloc(FileBufferSize);
171     if (!FileBuffer)
172     {
173         fclose(FileHandle);
174         return CAB_STATUS_NOMEMORY;
175     }
176 
177     if ( fread(FileBuffer, FileBufferSize, 1, FileHandle) < 1 )
178     {
179         fclose(FileHandle);
180         free(FileBuffer);
181         FileBuffer = NULL;
182         return CAB_STATUS_CANNOT_READ;
183     }
184 
185     fclose(FileHandle);
186 
187     FileLoaded = true;
188 
189     DPRINT(MAX_TRACE, ("File (%u bytes)\n", (UINT)FileBufferSize));
190 
191     return CAB_STATUS_SUCCESS;
192 }
193 
194 
195 ULONG CDFParser::Parse()
196 /*
197  * FUNCTION: Parses a loaded directive file
198  * RETURNS:
199  *     Status of operation
200  */
201 {
202     bool Command;
203     ULONG Status;
204 
205     if (!FileLoaded)
206         return CAB_STATUS_NOFILE;
207 
208     while (ReadLine())
209     {
210         Command = false;
211 
212         if (InfModeEnabled)
213         {
214             bool WriteLine = true;
215             while (CurrentToken != TokenEnd)
216             {
217                 switch (CurrentToken)
218                 {
219                     case TokenIdentifier:
220                         if (Command)
221                         {
222                             /* Command */
223                             Status = PerformCommand();
224                             if (Status == CAB_STATUS_FAILURE)
225                                 WriteLine = true;
226                             else
227                                 if (!InfModeEnabled)
228                                     WriteLine = false;
229 
230                             CurrentToken = TokenEnd;
231                             continue;
232                         }
233                         else
234                         {
235                             WriteLine = true;
236                             CurrentToken = TokenEnd;
237                             continue;
238                         }
239                         break;
240 
241                     case TokenSpace:
242                         break;
243 
244                     case TokenPeriod:
245                         Command = true;
246                         break;
247 
248                     default:
249                         WriteLine = true;
250                         CurrentToken = TokenEnd;
251                         continue;
252                 }
253                 NextToken();
254             }
255             if (WriteLine)
256                 WriteInfLine(Line);
257         }
258         else
259         {
260             while (CurrentToken != TokenEnd)
261             {
262                 switch (CurrentToken)
263                 {
264                     case TokenInteger:
265                         sprintf(CurrentString, "%u", (UINT)CurrentInteger);
266                     case TokenIdentifier:
267                     case TokenString:
268                         if (Command)
269                         {
270                             /* Command */
271                             Status = PerformCommand();
272 
273                             if (Status == CAB_STATUS_FAILURE)
274                             {
275                                 printf("ERROR: Directive file contains errors at line %u.\n", (UINT)CurrentLine);
276                                 DPRINT(MID_TRACE, ("Error while executing command.\n"));
277                             }
278 
279                             if (Status != CAB_STATUS_SUCCESS)
280                                 return Status;
281                         }
282                         else
283                         {
284                             /* File copy */
285                             Status = PerformFileCopy();
286 
287                             if (Status != CAB_STATUS_SUCCESS)
288                             {
289                                 printf("ERROR: Directive file contains errors at line %u.\n", (UINT)CurrentLine);
290                                 DPRINT(MID_TRACE, ("Error while copying file.\n"));
291                                 return Status;
292                             }
293                         }
294                         break;
295 
296                     case TokenSpace:
297                         break;
298 
299                     case TokenSemi:
300                         CurrentToken = TokenEnd;
301                         continue;
302 
303                     case TokenPeriod:
304                         Command = true;
305                         break;
306 
307                     default:
308                         printf("ERROR: Directive file contains errors at line %u.\n", (UINT)CurrentLine);
309                         DPRINT(MID_TRACE, ("Token is (%u).\n", (UINT)CurrentToken));
310                         return CAB_STATUS_SUCCESS;
311                     }
312                     NextToken();
313             }
314         }
315     }
316 
317     if (!InfFileOnly)
318     {
319         if (CABMgr.IsVerbose())
320         {
321             printf("Writing cabinet. This may take a while...\n");
322         }
323 
324         if (DiskCreated)
325         {
326             Status = WriteDisk(false);
327             if (Status == CAB_STATUS_SUCCESS)
328                 Status = CloseDisk();
329             if (Status != CAB_STATUS_SUCCESS)
330             {
331                 DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
332                 return Status;
333             }
334         }
335 
336         if (CabinetCreated)
337         {
338             Status = CloseCabinet();
339             if (Status != CAB_STATUS_SUCCESS)
340             {
341                 DPRINT(MIN_TRACE, ("Cannot close cabinet (%u).\n", (UINT)Status));
342                 return Status;
343             }
344         }
345 
346         if (CABMgr.IsVerbose())
347         {
348             printf("Done.\n");
349         }
350     }
351 
352     return CAB_STATUS_SUCCESS;
353 }
354 
355 
356 void CDFParser::SetFileRelativePath(char* Path)
357 /*
358  * FUNCTION: Sets path where files in the .dff is assumed relative to
359  * ARGUMENTS:
360  *    Path = Pointer to string with path
361  */
362 {
363     strcpy(FileRelativePath, Path);
364     ConvertPath(FileRelativePath, false);
365     if (strlen(FileRelativePath) > 0)
366         NormalizePath(FileRelativePath, PATH_MAX);
367 }
368 
369 
370 bool CDFParser::OnDiskLabel(ULONG Number, char* Label)
371 /*
372  * FUNCTION: Called when a disk needs a label
373  * ARGUMENTS:
374  *     Number = Cabinet number that needs a label
375  *     Label  = Pointer to buffer to place label of disk
376  * RETURNS:
377  *     true if a disk label was returned, false if not
378  */
379 {
380     char Buffer[20];
381     ULONG i;
382     int j;
383     char ch;
384 
385     Number += 1;
386 
387     DPRINT(MID_TRACE, ("Giving disk (%u) a label...\n", (UINT)Number));
388 
389     if (GetDiskName(&DiskLabel, Number, Label))
390         return true;
391 
392     if (DiskLabelTemplateSet)
393     {
394         j = 0;
395         strcpy(Label, "");
396         for (i = 0; i < strlen(DiskLabelTemplate); i++)
397         {
398             ch = DiskLabelTemplate[i];
399             if (ch == '*')
400             {
401                 sprintf(Buffer, "%u", (UINT)Number);
402                 strcat(Label, Buffer);
403                 j += (LONG)strlen(Buffer);
404             }
405             else
406             {
407                 Label[j] = ch;
408                 j++;
409             }
410             Label[j] = '\0';
411         }
412 
413         DPRINT(MID_TRACE, ("Giving disk (%s) as a label...\n", Label));
414 
415         return true;
416     }
417     else
418         return false;
419 }
420 
421 
422 bool CDFParser::OnCabinetName(ULONG Number, char* Name)
423 /*
424  * FUNCTION: Called when a cabinet needs a name
425  * ARGUMENTS:
426  *     Number = Disk number that needs a name
427  *     Name   = Pointer to buffer to place name of cabinet
428  * RETURNS:
429  *     true if a cabinet name was returned, false if not
430  */
431 {
432     char Buffer[PATH_MAX];
433     ULONG i;
434     int j;
435     char ch;
436 
437     Number += 1;
438 
439     DPRINT(MID_TRACE, ("Giving cabinet (%u) a name...\n", (UINT)Number));
440 
441     if (GetDiskName(&CabinetName, Number, Buffer))
442     {
443         strcpy(Name, GetDestinationPath());
444         strcat(Name, Buffer);
445         return true;
446     }
447 
448     if (CabinetNameTemplateSet)
449     {
450         strcpy(Name, GetDestinationPath());
451         j = (LONG)strlen(Name);
452         for (i = 0; i < strlen(CabinetNameTemplate); i++)
453         {
454             ch = CabinetNameTemplate[i];
455             if (ch == '*')
456             {
457                 sprintf(Buffer, "%u", (UINT)Number);
458                 strcat(Name, Buffer);
459                 j += (LONG)strlen(Buffer);
460             }
461             else
462             {
463                 Name[j] = ch;
464                 j++;
465             }
466             Name[j] = '\0';
467         }
468 
469         DPRINT(MID_TRACE, ("Giving cabinet (%s) as a name...\n", Name));
470         return true;
471     }
472     else
473         return false;
474 }
475 
476 
477 bool CDFParser::SetDiskName(PCABINET_NAME *List, ULONG Number, char* String)
478 /*
479  * FUNCTION: Sets an entry in a list
480  * ARGUMENTS:
481  *     List   = Address of pointer to list
482  *     Number = Disk number
483  *     String = Pointer to string
484  * RETURNS:
485  *     false if there was not enough free memory available
486  */
487 {
488     PCABINET_NAME CN;
489 
490     CN = *List;
491     while (CN != NULL)
492     {
493         if (CN->DiskNumber == Number)
494         {
495             strcpy(CN->Name, String);
496             return true;
497         }
498         CN = CN->Next;
499     }
500 
501     CN = (PCABINET_NAME)malloc(sizeof(CABINET_NAME));
502     if (!CN)
503         return false;
504 
505     CN->DiskNumber = Number;
506     strcpy(CN->Name, String);
507 
508     CN->Next = *List;
509     *List = CN;
510 
511     return true;
512 }
513 
514 
515 bool CDFParser::GetDiskName(PCABINET_NAME *List, ULONG Number, char* String)
516 /*
517  * FUNCTION: Returns an entry in a list
518  * ARGUMENTS:
519  *     List   = Address of pointer to list
520  *     Number = Disk number
521  *     String = Address of buffer to copy string to
522  * RETURNS:
523  *     false if there was not enough free memory available
524  */
525 {
526     PCABINET_NAME CN;
527 
528     CN = *List;
529     while (CN != NULL)
530     {
531         if (CN->DiskNumber == Number)
532         {
533             strcpy(String, CN->Name);
534             return true;
535         }
536         CN = CN->Next;
537     }
538 
539     return false;
540 }
541 
542 
543 bool CDFParser::SetDiskNumber(PDISK_NUMBER *List, ULONG Number, ULONG Value)
544 /*
545  * FUNCTION: Sets an entry in a list
546  * ARGUMENTS:
547  *     List   = Address of pointer to list
548  *     Number = Disk number
549  *     Value  = Value to set
550  * RETURNS:
551  *     false if there was not enough free memory available
552  */
553 {
554     PDISK_NUMBER DN;
555 
556     DN = *List;
557     while (DN != NULL)
558     {
559         if (DN->DiskNumber == Number)
560         {
561             DN->Number = Value;
562             return true;
563         }
564         DN = DN->Next;
565     }
566 
567     DN = (PDISK_NUMBER)malloc(sizeof(DISK_NUMBER));
568     if (!DN)
569         return false;
570 
571     DN->DiskNumber = Number;
572     DN->Number = Value;
573 
574     DN->Next = *List;
575     *List = DN;
576 
577     return true;
578 }
579 
580 
581 bool CDFParser::GetDiskNumber(PDISK_NUMBER *List, ULONG Number, PULONG Value)
582 /*
583  * FUNCTION: Returns an entry in a list
584  * ARGUMENTS:
585  *     List   = Address of pointer to list
586  *     Number = Disk number
587  *     Value  = Address of buffer to place value
588  * RETURNS:
589  *     true if the entry was found
590  */
591 {
592     PDISK_NUMBER DN;
593 
594     DN = *List;
595     while (DN != NULL)
596     {
597         if (DN->DiskNumber == Number)
598         {
599             *Value = DN->Number;
600             return true;
601         }
602         DN = DN->Next;
603     }
604 
605     return false;
606 }
607 
608 
609 bool CDFParser::DoDiskLabel(ULONG Number, char* Label)
610 /*
611  * FUNCTION: Sets the label of a disk
612  * ARGUMENTS:
613  *     Number = Disk number
614  *     Label  = Pointer to label of disk
615  * RETURNS:
616  *     false if there was not enough free memory available
617  */
618 {
619     DPRINT(MID_TRACE, ("Setting label of disk (%u) to '%s'\n", (UINT)Number, Label));
620 
621     return SetDiskName(&DiskLabel, Number, Label);
622 }
623 
624 
625 void CDFParser::DoDiskLabelTemplate(char* Template)
626 /*
627  * FUNCTION: Sets a disk label template to use
628  * ARGUMENTS:
629  *     Template = Pointer to disk label template
630  */
631 {
632     DPRINT(MID_TRACE, ("Setting disk label template to '%s'\n", Template));
633 
634     strcpy(DiskLabelTemplate, Template);
635     DiskLabelTemplateSet = true;
636 }
637 
638 
639 bool CDFParser::DoCabinetName(ULONG Number, char* Name)
640 /*
641  * FUNCTION: Sets the name of a cabinet
642  * ARGUMENTS:
643  *     Number = Disk number
644  *     Name   = Pointer to name of cabinet
645  * RETURNS:
646  *     false if there was not enough free memory available
647  */
648 {
649     DPRINT(MID_TRACE, ("Setting name of cabinet (%u) to '%s'\n", (UINT)Number, Name));
650 
651     return SetDiskName(&CabinetName, Number, Name);
652 }
653 
654 
655 void CDFParser::DoCabinetNameTemplate(char* Template)
656 /*
657  * FUNCTION: Sets a cabinet name template to use
658  * ARGUMENTS:
659  *     Template = Pointer to cabinet name template
660  */
661 {
662     DPRINT(MID_TRACE, ("Setting cabinet name template to '%s'\n", Template));
663 
664     strcpy(CabinetNameTemplate, Template);
665     CabinetNameTemplateSet = true;
666 }
667 
668 
669 ULONG CDFParser::DoMaxDiskSize(bool NumberValid, ULONG Number)
670 /*
671  * FUNCTION: Sets the maximum disk size
672  * ARGUMENTS:
673  *     NumberValid = true if disk number is valid
674  *     Number      = Disk number
675  * RETURNS:
676  *     Status of operation
677  * NOTES:
678  *     Standard sizes are 2.88M, 1.44M, 1.25M, 1.2M, 720K, 360K, and CDROM
679  */
680 {
681     ULONG A, B, Value;
682 
683     if (IsNextToken(TokenInteger, true))
684     {
685         A = CurrentInteger;
686 
687         if (IsNextToken(TokenPeriod, false))
688         {
689             if (!IsNextToken(TokenInteger, false))
690                 return CAB_STATUS_FAILURE;
691 
692             B = CurrentInteger;
693 
694         }
695         else
696             B = 0;
697 
698         if (CurrentToken == TokenIdentifier)
699         {
700             switch (CurrentString[0])
701             {
702                 case 'K':
703                     if (B != 0)
704                         return CAB_STATUS_FAILURE;
705 
706                     if (A == 720)
707                         /* 720K disk */
708                         Value = 730112;
709                     else if (A == 360)
710                         /* 360K disk */
711                         Value = 362496;
712                     else
713                         return CAB_STATUS_FAILURE;
714                     break;
715 
716                 case 'M':
717                     if (A == 1)
718                     {
719                         if (B == 44)
720                             /* 1.44M disk */
721                             Value = 1457664;
722                         else if (B == 25)
723                             /* 1.25M disk */
724                             Value = 1300000; // FIXME: Value?
725                         else if (B == 2)
726                             /* 1.2M disk */
727                             Value = 1213952;
728                         else
729                             return CAB_STATUS_FAILURE;
730                     }
731                     else if (A == 2)
732                     {
733                         if (B == 88)
734                             /* 2.88M disk */
735                             Value = 2915328;
736                         else
737                             return CAB_STATUS_FAILURE;
738                     }
739                     else
740                         return CAB_STATUS_FAILURE;
741                     break;
742 
743                 default:
744                     DPRINT(MID_TRACE, ("Bad suffix (%c)\n", CurrentString[0]));
745                     return CAB_STATUS_FAILURE;
746             }
747         }
748         else
749             Value = A;
750     }
751     else
752     {
753         if ((CurrentToken != TokenString) &&
754             (strcasecmp(CurrentString, "CDROM") != 0))
755             return CAB_STATUS_FAILURE;
756         /* CDROM */
757         Value = 640*1024*1024;  // FIXME: Correct size for CDROM?
758     }
759 
760     if (NumberValid)
761         return (SetDiskNumber(&MaxDiskSize, Number, Value)?
762             CAB_STATUS_SUCCESS : CAB_STATUS_FAILURE);
763 
764     MaxDiskSizeAll    = Value;
765     MaxDiskSizeAllSet = true;
766 
767     SetMaxDiskSize(Value);
768 
769     return CAB_STATUS_SUCCESS;
770 }
771 
772 
773 void CDFParser::DoInfFileName(char* FileName)
774 /*
775  * FUNCTION: Sets filename of the generated .inf file
776  * ARGUMENTS:
777  *     FileName = Pointer to .inf filename
778  */
779 {
780     DPRINT(MID_TRACE, ("Setting .inf filename to '%s'\n", FileName));
781 
782     strcpy(InfFileName, FileName);
783     InfFileNameSet = true;
784 }
785 
786 ULONG CDFParser::SetupNewDisk()
787 /*
788  * FUNCTION: Sets up parameters for a new disk
789  * RETURNS:
790  *     Status of operation
791  */
792 {
793     ULONG Value;
794 
795     if (!GetDiskNumber(&MaxDiskSize, GetCurrentDiskNumber(), &Value))
796     {
797         if (MaxDiskSizeAllSet)
798             Value = MaxDiskSizeAll;
799         else
800             Value = 0;
801     }
802     SetMaxDiskSize(Value);
803 
804     return CAB_STATUS_SUCCESS;
805 }
806 
807 
808 ULONG CDFParser::PerformSetCommand()
809 /*
810  * FUNCTION: Performs a set variable command
811  * RETURNS:
812  *     Status of operation
813  */
814 {
815     SETTYPE SetType;
816     bool NumberValid = false;
817     ULONG Number = 0;
818 
819     if (!IsNextToken(TokenIdentifier, true))
820         return CAB_STATUS_FAILURE;
821 
822     if (strcasecmp(CurrentString, "DiskLabel") == 0)
823         SetType = stDiskLabel;
824     else if (strcasecmp(CurrentString, "DiskLabelTemplate") == 0)
825         SetType = stDiskLabelTemplate;
826     else if (strcasecmp(CurrentString, "CabinetName") == 0)
827         SetType = stCabinetName;
828     else if (strcasecmp(CurrentString, "CabinetNameTemplate") == 0)
829         SetType = stCabinetNameTemplate;
830     else if (strcasecmp(CurrentString, "MaxDiskSize") == 0)
831         SetType = stMaxDiskSize;
832     else if (strcasecmp(CurrentString, "InfFileName") == 0)
833         SetType = stInfFileName;
834     else
835         return CAB_STATUS_FAILURE;
836 
837     if ((SetType == stDiskLabel) || (SetType == stCabinetName))
838     {
839         if (!IsNextToken(TokenInteger, false))
840             return CAB_STATUS_FAILURE;
841         Number = CurrentInteger;
842 
843         if (!IsNextToken(TokenEqual, true))
844             return CAB_STATUS_FAILURE;
845     }
846     else if (SetType == stMaxDiskSize)
847     {
848         if (IsNextToken(TokenInteger, false))
849         {
850             NumberValid = true;
851             Number = CurrentInteger;
852         }
853         else
854         {
855             NumberValid = false;
856             while (CurrentToken == TokenSpace)
857                 NextToken();
858             if (CurrentToken != TokenEqual)
859                 return CAB_STATUS_FAILURE;
860         }
861     }
862     else if (!IsNextToken(TokenEqual, true))
863             return CAB_STATUS_FAILURE;
864 
865     if (SetType != stMaxDiskSize)
866     {
867         if (!IsNextToken(TokenString, true))
868             return CAB_STATUS_FAILURE;
869     }
870 
871     switch (SetType)
872     {
873         case stDiskLabel:
874             if (!DoDiskLabel(Number, CurrentString))
875                 DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
876             return CAB_STATUS_SUCCESS;
877 
878         case stCabinetName:
879             if (!DoCabinetName(Number, CurrentString))
880                 DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
881             return CAB_STATUS_SUCCESS;
882 
883         case stDiskLabelTemplate:
884             DoDiskLabelTemplate(CurrentString);
885             return CAB_STATUS_SUCCESS;
886 
887         case stCabinetNameTemplate:
888             DoCabinetNameTemplate(CurrentString);
889             return CAB_STATUS_SUCCESS;
890 
891         case stMaxDiskSize:
892             return DoMaxDiskSize(NumberValid, Number);
893 
894         case stInfFileName:
895             DoInfFileName(CurrentString);
896             return CAB_STATUS_SUCCESS;
897 
898         default:
899             return CAB_STATUS_FAILURE;
900     }
901 }
902 
903 
904 ULONG CDFParser::PerformNewCommand()
905 /*
906  * FUNCTION: Performs a new disk|cabinet|folder command
907  * RETURNS:
908  *     Status of operation
909  */
910 {
911     NEWTYPE NewType;
912     ULONG Status;
913 
914     if (!IsNextToken(TokenIdentifier, true))
915         return CAB_STATUS_FAILURE;
916 
917     if (strcasecmp(CurrentString, "Disk") == 0)
918         NewType = ntDisk;
919     else if (strcasecmp(CurrentString, "Cabinet") == 0)
920         NewType = ntCabinet;
921     else if (strcasecmp(CurrentString, "Folder") == 0)
922         NewType = ntFolder;
923     else
924         return CAB_STATUS_FAILURE;
925 
926     switch (NewType)
927     {
928         case ntDisk:
929             if (DiskCreated)
930             {
931                 Status = WriteDisk(true);
932                 if (Status == CAB_STATUS_SUCCESS)
933                     Status = CloseDisk();
934                 if (Status != CAB_STATUS_SUCCESS)
935                 {
936                     DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
937                     return CAB_STATUS_SUCCESS;
938                 }
939                 DiskCreated = false;
940             }
941 
942             Status = NewDisk();
943             if (Status != CAB_STATUS_SUCCESS)
944             {
945                 DPRINT(MIN_TRACE, ("Cannot create disk (%u).\n", (UINT)Status));
946                 return CAB_STATUS_SUCCESS;
947             }
948             DiskCreated = true;
949             SetupNewDisk();
950             return CAB_STATUS_SUCCESS;
951 
952         case ntCabinet:
953             if (DiskCreated)
954             {
955                 Status = WriteDisk(true);
956                 if (Status == CAB_STATUS_SUCCESS)
957                     Status = CloseDisk();
958                 if (Status != CAB_STATUS_SUCCESS)
959                 {
960                     DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
961                     return CAB_STATUS_SUCCESS;
962                 }
963                 DiskCreated = false;
964             }
965 
966             Status = NewCabinet();
967             if (Status != CAB_STATUS_SUCCESS)
968             {
969                 DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
970                 return CAB_STATUS_SUCCESS;
971             }
972             DiskCreated = true;
973             SetupNewDisk();
974             return CAB_STATUS_SUCCESS;
975 
976         case ntFolder:
977             Status = NewFolder();
978             ASSERT(Status == CAB_STATUS_SUCCESS);
979             return CAB_STATUS_SUCCESS;
980 
981         default:
982             return CAB_STATUS_FAILURE;
983     }
984 }
985 
986 
987 ULONG CDFParser::PerformInfBeginCommand()
988 /*
989  * FUNCTION: Begins inf mode
990  * RETURNS:
991  *     Status of operation
992  */
993 {
994     InfModeEnabled = true;
995     return CAB_STATUS_SUCCESS;
996 }
997 
998 
999 ULONG CDFParser::PerformInfEndCommand()
1000 /*
1001  * FUNCTION: Begins inf mode
1002  * RETURNS:
1003  *     Status of operation
1004  */
1005 {
1006     InfModeEnabled = false;
1007     return CAB_STATUS_SUCCESS;
1008 }
1009 
1010 
1011 ULONG CDFParser::PerformCommand()
1012 /*
1013  * FUNCTION: Performs a command
1014  * RETURNS:
1015  *     Status of operation
1016  */
1017 {
1018     if (strcasecmp(CurrentString, "Set") == 0)
1019         return PerformSetCommand();
1020     if (strcasecmp(CurrentString, "New") == 0)
1021         return PerformNewCommand();
1022     if (strcasecmp(CurrentString, "InfBegin") == 0)
1023         return PerformInfBeginCommand();
1024     if (strcasecmp(CurrentString, "InfEnd") == 0)
1025         return PerformInfEndCommand();
1026 
1027     return CAB_STATUS_FAILURE;
1028 }
1029 
1030 
1031 ULONG CDFParser::PerformFileCopy()
1032 /*
1033  * FUNCTION: Performs a file copy
1034  * RETURNS:
1035  *     Status of operation
1036  */
1037 {
1038     ULONG Status;
1039     ULONG i, j;
1040     char ch;
1041     char SrcName[PATH_MAX];
1042     char DstName[PATH_MAX];
1043     char InfLine[PATH_MAX];
1044     char Options[128];
1045     char BaseFilename[PATH_MAX];
1046 
1047     *SrcName = '\0';
1048     *DstName = '\0';
1049     *Options = '\0';
1050 
1051     // source file
1052     i = CurrentChar;
1053     while ((i < LineLength) &&
1054         ((ch = Line[i]) != ' ') &&
1055          (ch != 0x09) &&
1056          (ch != ';'))
1057     {
1058         CurrentString[i] = ch;
1059         i++;
1060     }
1061     CurrentString[i] = '\0';
1062     CurrentToken = TokenString;
1063     CurrentChar  = i + 1;
1064     strcpy(BaseFilename, CurrentString);
1065     strcat(SrcName, BaseFilename);
1066 
1067     // destination
1068     SkipSpaces();
1069 
1070     if (CurrentToken != TokenEnd)
1071     {
1072         j = (ULONG)strlen(CurrentString); i = 0;
1073         while ((CurrentChar + i < LineLength) &&
1074             ((ch = Line[CurrentChar + i]) != ' ') &&
1075              (ch != 0x09) &&
1076              (ch != ';'))
1077         {
1078             CurrentString[j + i] = ch;
1079             i++;
1080         }
1081         CurrentString[j + i] = '\0';
1082         CurrentToken = TokenString;
1083         CurrentChar += i + 1;
1084         strcpy(DstName, CurrentString);
1085     }
1086 
1087     // options (it may be empty)
1088     SkipSpaces ();
1089 
1090     if (CurrentToken != TokenEnd)
1091     {
1092         j = (ULONG)strlen(CurrentString); i = 0;
1093         while ((CurrentChar + i < LineLength) &&
1094             ((ch = Line[CurrentChar + i]) != ' ') &&
1095              (ch != 0x09) &&
1096              (ch != ';'))
1097         {
1098             CurrentString[j + i] = ch;
1099             i++;
1100         }
1101         CurrentString[j + i] = '\0';
1102         CurrentToken = TokenString;
1103         CurrentChar += i + 1;
1104         strcpy(Options, CurrentString);
1105     }
1106 
1107     if (!CabinetCreated)
1108     {
1109         DPRINT(MID_TRACE, ("Creating cabinet.\n"));
1110 
1111         Status = NewCabinet();
1112         if (Status != CAB_STATUS_SUCCESS)
1113         {
1114             DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
1115             printf("ERROR: Cannot create cabinet.\n");
1116             return CAB_STATUS_FAILURE;
1117         }
1118         CabinetCreated = true;
1119 
1120         DPRINT(MID_TRACE, ("Creating disk.\n"));
1121 
1122         Status = NewDisk();
1123         if (Status != CAB_STATUS_SUCCESS)
1124         {
1125             DPRINT(MIN_TRACE, ("Cannot create disk (%u).\n", (UINT)Status));
1126             printf("ERROR: Cannot create disk.\n");
1127             return CAB_STATUS_FAILURE;
1128         }
1129         DiskCreated = true;
1130         SetupNewDisk();
1131     }
1132 
1133     DPRINT(MID_TRACE, ("Adding file: '%s'   destination: '%s'.\n", SrcName, DstName));
1134 
1135     Status = AddFile(SrcName);
1136     if (Status == CAB_STATUS_CANNOT_OPEN)
1137     {
1138         strcpy(SrcName, FileRelativePath);
1139         strcat(SrcName, BaseFilename);
1140         Status = AddFile(SrcName);
1141     }
1142     switch (Status)
1143     {
1144         case CAB_STATUS_SUCCESS:
1145             sprintf(InfLine, "%s=%s", GetFileName(SrcName), DstName);
1146             WriteInfLine(InfLine);
1147             break;
1148 
1149         case CAB_STATUS_CANNOT_OPEN:
1150             if (strstr(Options,"optional"))
1151             {
1152                 Status = CAB_STATUS_SUCCESS;
1153                 printf("Optional file skipped (does not exist): %s.\n", SrcName);
1154             }
1155             else
1156                 printf("ERROR: File not found: %s.\n", SrcName);
1157 
1158             break;
1159 
1160         case CAB_STATUS_NOMEMORY:
1161             printf("ERROR: Insufficient memory to add file: %s.\n", SrcName);
1162             break;
1163 
1164         default:
1165             printf("ERROR: Cannot add file: %s (%u).\n", SrcName, (UINT)Status);
1166             break;
1167     }
1168     return Status;
1169 }
1170 
1171 
1172 void CDFParser::SkipSpaces()
1173 /*
1174  * FUNCTION: Skips any spaces in the current line
1175  */
1176 {
1177     NextToken();
1178     while (CurrentToken == TokenSpace)
1179         NextToken();
1180 }
1181 
1182 
1183 bool CDFParser::IsNextToken(DFP_TOKEN Token, bool NoSpaces)
1184 /*
1185  * FUNCTION: Checks if next token equals Token
1186  * ARGUMENTS:
1187  *     Token  = Token to compare with
1188  *     SkipSp = true if spaces should be skipped
1189  * RETURNS:
1190  *     false if next token is diffrent from Token
1191  */
1192 {
1193     if (NoSpaces)
1194         SkipSpaces();
1195     else
1196         NextToken();
1197     return (CurrentToken == Token);
1198 }
1199 
1200 
1201 bool CDFParser::ReadLine()
1202 /*
1203  * FUNCTION: Reads the next line into the line buffer
1204  * RETURNS:
1205  *     true if there is a new line, false if not
1206  */
1207 {
1208     ULONG i, j;
1209     char ch;
1210 
1211     if (CurrentOffset >= FileBufferSize)
1212         return false;
1213 
1214     i = 0;
1215     while (((j = CurrentOffset + i) < FileBufferSize) && (i < sizeof(Line) - 1) &&
1216         ((ch = FileBuffer[j]) != 0x0D && (ch = FileBuffer[j]) != 0x0A))
1217     {
1218         Line[i] = ch;
1219         i++;
1220     }
1221 
1222     Line[i]    = '\0';
1223     LineLength = i;
1224 
1225     if ((FileBuffer[CurrentOffset + i] == 0x0D) && (FileBuffer[CurrentOffset + i + 1] == 0x0A))
1226         CurrentOffset++;
1227 
1228     CurrentOffset += i + 1;
1229 
1230     CurrentChar = 0;
1231 
1232     CurrentLine++;
1233 
1234     NextToken();
1235 
1236     return true;
1237 }
1238 
1239 
1240 void CDFParser::NextToken()
1241 /*
1242  * FUNCTION: Reads the next token from the current line
1243  */
1244 {
1245     ULONG i;
1246     char ch = ' ';
1247 
1248     if (CurrentChar >= LineLength)
1249     {
1250         CurrentToken = TokenEnd;
1251         return;
1252     }
1253 
1254     switch (Line[CurrentChar])
1255     {
1256         case ' ':
1257         case 0x09:
1258             CurrentToken = TokenSpace;
1259             break;
1260 
1261         case ';':
1262             CurrentToken = TokenSemi;
1263             break;
1264 
1265         case '=':
1266             CurrentToken = TokenEqual;
1267             break;
1268 
1269         case '.':
1270             CurrentToken = TokenPeriod;
1271             break;
1272 
1273         case '\\':
1274             CurrentToken = TokenBackslash;
1275             break;
1276 
1277         case '"':
1278             i = 0;
1279             while ((CurrentChar + i + 1 < LineLength) &&
1280                 ((ch = Line[CurrentChar + i + 1]) != '"'))
1281             {
1282                 CurrentString[i] = ch;
1283                 i++;
1284             }
1285             CurrentString[i] = '\0';
1286             CurrentToken = TokenString;
1287             CurrentChar += i + 2;
1288             return;
1289 
1290         default:
1291             i = 0;
1292             while ((CurrentChar + i < LineLength) &&
1293                 ((ch = Line[CurrentChar + i]) >= '0') && (ch <= '9'))
1294             {
1295                 CurrentString[i] = ch;
1296                 i++;
1297             }
1298             if (i > 0)
1299             {
1300                 CurrentString[i] = '\0';
1301                 CurrentInteger = atoi(CurrentString);
1302                 CurrentToken = TokenInteger;
1303                 CurrentChar += i;
1304                 return;
1305             }
1306             i = 0;
1307             while (((CurrentChar + i < LineLength) &&
1308                 (((ch = Line[CurrentChar + i]) >= 'a') && (ch <= 'z'))) ||
1309                 ((ch >= 'A') && (ch <= 'Z')) || (ch == '_'))
1310             {
1311                 CurrentString[i] = ch;
1312                 i++;
1313             }
1314             if (i > 0)
1315             {
1316                 CurrentString[i] = '\0';
1317                 CurrentToken = TokenIdentifier;
1318                 CurrentChar += i;
1319                 return;
1320             }
1321             CurrentToken = TokenEnd;
1322     }
1323     CurrentChar++;
1324 }
1325 
1326 /* EOF */
1327