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