:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / apps / utils / cabman / dfp.cpp
1 /*
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
9  * REVISIONS:
10  *   CSH 21/03-2001 Created
11  */
12 #include <windows.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include "cabinet.h"
16 #include "dfp.h"
17
18
19 /* CDFParser */
20
21 CDFParser::CDFParser()
22 /*
23  * FUNCTION: Default constructor
24  */
25 {
26     FileBuffer     = NULL;
27     FileLoaded     = FALSE;
28     CurrentOffset  = 0;
29     CurrentLine    = 0;
30     CabinetCreated = FALSE;
31     DiskCreated    = FALSE;
32     FolderCreated  = FALSE;
33     CabinetName    = NULL;
34     DiskLabel      = NULL;
35     MaxDiskSize    = NULL;
36
37     MaxDiskSizeAllSet      = FALSE;
38     CabinetNameTemplateSet = FALSE;
39     DiskLabelTemplateSet   = FALSE;
40 }
41
42
43 CDFParser::~CDFParser()
44 /*
45  * FUNCTION: Default destructor
46  */
47 {
48     PCABINET_NAME CNPrev;
49     PCABINET_NAME CNNext;
50     PDISK_NUMBER DNPrev;
51     PDISK_NUMBER DNNext;
52
53     if (FileBuffer)
54         HeapFree(GetProcessHeap(), 0, FileBuffer);
55     CNNext = CabinetName;
56     while (CNNext != NULL) {
57         CNPrev = CNNext->Next;
58         HeapFree(GetProcessHeap(), 0, CNNext);
59         CNNext = CNPrev;
60     }
61     CNNext = DiskLabel;
62     while (CNNext != NULL) {
63         CNPrev = CNNext->Next;
64         HeapFree(GetProcessHeap(), 0, CNNext);
65         CNNext = CNPrev;
66     }
67     DNNext = MaxDiskSize;
68     while (DNNext != NULL) {
69         DNPrev = DNNext->Next;
70         HeapFree(GetProcessHeap(), 0, DNNext);
71         DNNext = DNPrev;
72     }
73 }
74
75
76 ULONG CDFParser::Load(LPTSTR FileName)
77 /*
78  * FUNCTION: Loads a directive file into memory
79  * ARGUMENTS:
80  *     FileName = Pointer to name of directive file
81  * RETURNS:
82  *     Status of operation
83  */
84 {
85     DWORD BytesRead;
86     LONG FileSize;
87
88     if (FileLoaded)
89         return CAB_STATUS_SUCCESS;
90
91     /* Create cabinet file, overwrite if it already exists */
92     FileHandle = CreateFile(FileName, // Create this file
93         GENERIC_READ,                 // Open for reading
94         0,                            // No sharing
95         NULL,                         // No security
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;
101
102     FileSize = GetFileSize(FileHandle, NULL);
103     if (FileSize < 0) {
104         CloseHandle(FileHandle);
105         return CAB_STATUS_CANNOT_OPEN;
106     }
107
108     FileBufferSize = (ULONG)FileSize;
109
110     FileBuffer = (PCHAR)HeapAlloc(GetProcessHeap(), 0, FileBufferSize);
111     if (!FileBuffer) {
112         CloseHandle(FileHandle);
113         return CAB_STATUS_NOMEMORY;
114     }
115
116     if (!ReadFile(FileHandle, FileBuffer, FileBufferSize, &BytesRead, NULL)) {
117         CloseHandle(FileHandle);
118         HeapFree(GetProcessHeap(), 0, FileBuffer);
119         FileBuffer = NULL;
120         return CAB_STATUS_CANNOT_READ;
121     }
122
123     CloseHandle(FileHandle);
124
125     FileLoaded = TRUE;
126
127     DPRINT(MAX_TRACE, ("File (%d bytes)\n", FileBufferSize));
128
129     return CAB_STATUS_SUCCESS;
130 }
131
132
133 ULONG CDFParser::Parse()
134 /*
135  * FUNCTION: Parses a loaded directive file
136  * RETURNS:
137  *     Status of operation
138  */
139 {
140     BOOL Command;
141     ULONG Status;
142
143     if (!FileLoaded)
144         return CAB_STATUS_NOFILE;
145
146     while (ReadLine()) {
147         Command = FALSE;
148
149         while (CurrentToken != TokenEnd) {
150             switch (CurrentToken) {
151             case TokenInteger:
152                 itoa(CurrentInteger, (LPTSTR)&CurrentString, 10);
153             case TokenIdentifier:
154                 if (Command) {
155                     /* Command */
156                     Status = PerformCommand();
157
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"));
161                     }
162
163                     if (Status != CAB_STATUS_SUCCESS)
164                         return Status;
165                 } else {
166                     /* File copy */
167                     Status = PerformFileCopy();
168
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"));
172                     }
173
174                     if (Status != CAB_STATUS_SUCCESS)
175                         return Status;
176                 }
177                 break;
178             case TokenSpace:
179                 break;
180             case TokenSemi:
181                 CurrentToken = TokenEnd;
182                 continue;
183             case TokenPeriod:
184                 Command = TRUE;
185                 break;
186             default:
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;
190             }
191             NextToken();
192         }
193     }
194
195         printf("\nWriting cabinet. This may take a while...\n\n");
196
197     if (DiskCreated) {
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));
203             return Status;
204         }
205     }
206
207     if (CabinetCreated) {
208         Status = CloseCabinet();
209         if (Status != CAB_STATUS_SUCCESS) {
210             DPRINT(MIN_TRACE, ("Cannot close cabinet (%d).\n", (UINT)Status));
211             return Status;
212         }
213     }
214
215         printf("\nDone.\n");
216
217     return CAB_STATUS_SUCCESS;
218 }
219
220
221 BOOL CDFParser::OnDiskLabel(ULONG Number, LPTSTR Label)
222 /*
223  * FUNCTION: Called when a disk needs a label
224  * ARGUMENTS:
225  *     Number = Cabinet number that needs a label
226  *     Label  = Pointer to buffer to place label of disk
227  * RETURNS:
228  *     TRUE if a disk label was returned, FALSE if not
229  */
230 {
231     TCHAR Buffer[20];
232     INT i, j;
233     TCHAR ch;
234
235     Number += 1;
236
237     DPRINT(MID_TRACE, ("Giving disk (%d) a label...\n", (UINT)Number));
238
239     if (GetDiskName(&DiskLabel, Number, Label))
240         return TRUE;
241
242     if (DiskLabelTemplateSet) {
243         j = 0;
244         lstrcpy(Label, "");
245         for (i = 0; i < lstrlen(DiskLabelTemplate); i++) {
246             ch = DiskLabelTemplate[i];
247             if (ch == '*') {
248                 lstrcat(Label, itoa(Number, Buffer, 10));
249                 j += lstrlen(Buffer);
250             } else {
251                 Label[j] = ch;
252                 j++;
253             }
254             Label[j] = '\0';
255         }
256
257         DPRINT(MID_TRACE, ("Giving disk (%s) as a label...\n", Label));
258
259         return TRUE;
260     } else
261         return FALSE;
262 }
263
264
265 BOOL CDFParser::OnCabinetName(ULONG Number, LPTSTR Name)
266 /*
267  * FUNCTION: Called when a cabinet needs a name
268  * ARGUMENTS:
269  *     Number = Disk number that needs a name
270  *     Name   = Pointer to buffer to place name of cabinet
271  * RETURNS:
272  *     TRUE if a cabinet name was returned, FALSE if not
273  */
274 {
275     TCHAR Buffer[20];
276     INT i, j;
277     TCHAR ch;
278
279     Number += 1;
280
281     DPRINT(MID_TRACE, ("Giving cabinet (%d) a name...\n", (UINT)Number));
282
283     if (GetDiskName(&CabinetName, Number, Name))
284         return TRUE;
285
286     if (CabinetNameTemplateSet) {
287         j = 0;
288         lstrcpy(Name, "");
289         for (i = 0; i < lstrlen(CabinetNameTemplate); i++) {
290             ch = CabinetNameTemplate[i];
291             if (ch == '*') {
292                 lstrcat(Name, itoa(Number, Buffer, 10));
293                 j += lstrlen(Buffer);
294             } else {
295                 Name[j] = ch;
296                 j++;
297             }
298             Name[j] = '\0';
299         }
300
301         DPRINT(MID_TRACE, ("Giving cabinet (%s) as a name...\n", Name));
302
303         return TRUE;
304     } else
305         return FALSE;
306 }
307
308
309 BOOL CDFParser::SetDiskName(PCABINET_NAME *List, ULONG Number, LPTSTR String)
310 /*
311  * FUNCTION: Sets an entry in a list
312  * ARGUMENTS:
313  *     List   = Address of pointer to list
314  *     Number = Disk number
315  *     String = Pointer to string
316  * RETURNS:
317  *     FALSE if there was not enough free memory available
318  */
319 {
320     PCABINET_NAME CN;
321
322     CN = *List;
323     while (CN != NULL) {
324         if (CN->DiskNumber == Number) {
325             lstrcpy(CN->Name, String);
326             return TRUE;
327         }
328         CN = CN->Next;
329     }
330
331     CN = (PCABINET_NAME)HeapAlloc(GetProcessHeap(), 0, sizeof(CABINET_NAME));
332     if (!CN)
333         return FALSE;
334
335     CN->DiskNumber = Number;
336     lstrcpy(CN->Name, String);
337
338     CN->Next = *List;
339     *List = CN;
340
341     return TRUE;
342 }
343
344
345 BOOL CDFParser::GetDiskName(PCABINET_NAME *List, ULONG Number, LPTSTR String)
346 /*
347  * FUNCTION: Returns an entry in a list
348  * ARGUMENTS:
349  *     List   = Address of pointer to list
350  *     Number = Disk number
351  *     String = Address of buffer to copy string to
352  * RETURNS:
353  *     FALSE if there was not enough free memory available
354  */
355 {
356     PCABINET_NAME CN;
357
358     CN = *List;
359     while (CN != NULL) {
360         if (CN->DiskNumber == Number) {
361             lstrcpy(String, CN->Name);
362             return TRUE;
363         }
364         CN = CN->Next;
365     }
366
367     return FALSE;
368 }
369
370
371 BOOL CDFParser::SetDiskNumber(PDISK_NUMBER *List, ULONG Number, ULONG Value)
372 /*
373  * FUNCTION: Sets an entry in a list
374  * ARGUMENTS:
375  *     List   = Address of pointer to list
376  *     Number = Disk number
377  *     Value  = Value to set
378  * RETURNS:
379  *     FALSE if there was not enough free memory available
380  */
381 {
382     PDISK_NUMBER DN;
383
384     DN = *List;
385     while (DN != NULL) {
386         if (DN->DiskNumber == Number) {
387             DN->Number = Value;
388             return TRUE;
389         }
390         DN = DN->Next;
391     }
392
393     DN = (PDISK_NUMBER)HeapAlloc(GetProcessHeap(), 0, sizeof(DISK_NUMBER));
394     if (!DN)
395         return FALSE;
396
397     DN->DiskNumber = Number;
398     DN->Number = Value;
399
400     DN->Next = *List;
401     *List = DN;
402
403     return TRUE;
404 }
405
406
407 BOOL CDFParser::GetDiskNumber(PDISK_NUMBER *List, ULONG Number, PULONG Value)
408 /*
409  * FUNCTION: Returns an entry in a list
410  * ARGUMENTS:
411  *     List   = Address of pointer to list
412  *     Number = Disk number
413  *     Value  = Address of buffer to place value
414  * RETURNS:
415  *     TRUE if the entry was found
416  */
417 {
418     PDISK_NUMBER DN;
419
420     DN = *List;
421     while (DN != NULL) {
422         if (DN->DiskNumber == Number) {
423             *Value = DN->Number;
424             return TRUE;
425         }
426         DN = DN->Next;
427     }
428
429     return FALSE;
430 }
431
432
433 BOOL CDFParser::DoDiskLabel(ULONG Number, LPTSTR Label)
434 /*
435  * FUNCTION: Sets the label of a disk
436  * ARGUMENTS:
437  *     Number = Disk number
438  *     Label  = Pointer to label of disk
439  * RETURNS:
440  *     FALSE if there was not enough free memory available
441  */
442 {
443     DPRINT(MID_TRACE, ("Setting label of disk (%d) to '%s'\n", (UINT)Number, Label));
444
445     return SetDiskName(&DiskLabel, Number, Label);
446 }
447
448
449 VOID CDFParser::DoDiskLabelTemplate(LPTSTR Template)
450 /*
451  * FUNCTION: Sets a disk label template to use
452  * ARGUMENTS:
453  *     Template = Pointer to disk label template
454  */
455 {
456     DPRINT(MID_TRACE, ("Setting disk label template to '%s'\n", Template));
457
458     lstrcpy(DiskLabelTemplate, Template);
459     DiskLabelTemplateSet = TRUE;
460 }
461
462
463 BOOL CDFParser::DoCabinetName(ULONG Number, LPTSTR Name)
464 /*
465  * FUNCTION: Sets the name of a cabinet
466  * ARGUMENTS:
467  *     Number = Disk number
468  *     Name   = Pointer to name of cabinet
469  * RETURNS:
470  *     FALSE if there was not enough free memory available
471  */
472 {
473     DPRINT(MID_TRACE, ("Setting name of cabinet (%d) to '%s'\n", (UINT)Number, Name));
474
475     return SetDiskName(&CabinetName, Number, Name);
476 }
477
478
479 VOID CDFParser::DoCabinetNameTemplate(LPTSTR Template)
480 /*
481  * FUNCTION: Sets a cabinet name template to use
482  * ARGUMENTS:
483  *     Template = Pointer to cabinet name template
484  */
485 {
486     DPRINT(MID_TRACE, ("Setting cabinet name template to '%s'\n", Template));
487
488     lstrcpy(CabinetNameTemplate, Template);
489     CabinetNameTemplateSet = TRUE;
490 }
491
492
493 ULONG CDFParser::DoMaxDiskSize(BOOL NumberValid, ULONG Number)
494 /*
495  * FUNCTION: Sets the maximum disk size
496  * ARGUMENTS:
497  *     NumberValid = TRUE if disk number is valid
498  *     Number      = Disk number
499  * RETURNS:
500  *     Status of operation
501  * NOTES:
502  *     Standard sizes are 2.88M, 1.44M, 1.25M, 1.2M, 720K, 360K, and CDROM
503  */
504 {
505     ULONG A, B, Value;
506
507     if (IsNextToken(TokenInteger, TRUE)) {
508
509         A = CurrentInteger;
510
511         if (IsNextToken(TokenPeriod, FALSE)) {
512             if (!IsNextToken(TokenInteger, FALSE))
513                 return CAB_STATUS_FAILURE;
514
515             B = CurrentInteger;
516
517         } else
518             B = 0;
519
520         if (CurrentToken == TokenIdentifier) {
521             switch (CurrentString[0]) {
522             case 'K':
523                 if (B != 0)
524                     return CAB_STATUS_FAILURE;
525
526                 if (A == 720)
527                     /* 720K disk */
528                     Value = 730112;
529                 else if (A == 360)
530                     /* 360K disk */
531                     Value = 362496;
532                 else
533                     return CAB_STATUS_FAILURE;
534                 break;
535             case 'M':
536                 if (A == 1) {
537                     if (B == 44)
538                         /* 1.44M disk */
539                         Value = 1457664;
540                     else if (B == 25)
541                         /* 1.25M disk */
542                         Value = 1300000; // FIXME: Value?
543                     else if (B == 2)
544                         /* 1.2M disk */
545                         Value = 1213952;
546                     else
547                         return CAB_STATUS_FAILURE;
548                 } else if (A == 2) {
549                     if (B == 88)
550                         /* 2.88M disk */
551                         Value = 2915328;
552                     else
553                         return CAB_STATUS_FAILURE;
554                 } else
555                     return CAB_STATUS_FAILURE;
556                 break;
557             default:
558                 DPRINT(MID_TRACE, ("Bad suffix (%c)\n", CurrentString[0]));
559                 return CAB_STATUS_FAILURE;
560             }
561         } else
562             Value = A;
563     } else {
564         if ((CurrentToken != TokenString) &&
565             (strcmpi(CurrentString, "CDROM") != 0))
566             return CAB_STATUS_FAILURE;
567         /* CDROM */
568         Value = 640*1024*1024;  // FIXME: Correct size for CDROM?
569     }
570
571     if (NumberValid)
572         return (SetDiskNumber(&MaxDiskSize, Number, Value)?
573             CAB_STATUS_SUCCESS : CAB_STATUS_FAILURE);
574
575     MaxDiskSizeAll    = Value;
576     MaxDiskSizeAllSet = TRUE;
577
578     SetMaxDiskSize(Value);
579
580     return CAB_STATUS_SUCCESS;
581 }
582
583
584 ULONG CDFParser::SetupNewDisk()
585 /*
586  * FUNCTION: Sets up parameters for a new disk
587  * RETURNS:
588  *     Status of operation
589  */
590 {
591     ULONG Value;
592
593     if (!GetDiskNumber(&MaxDiskSize, GetCurrentDiskNumber(), &Value))  {
594         if (MaxDiskSizeAllSet)
595             Value = MaxDiskSizeAll;
596         else
597             Value = 0;
598     }
599     SetMaxDiskSize(Value);
600
601     return CAB_STATUS_SUCCESS;
602 }
603
604
605 ULONG CDFParser::PerformSetCommand()
606 /*
607  * FUNCTION: Performs a set variable command
608  * RETURNS:
609  *     Status of operation
610  */
611 {
612     SETTYPE SetType;
613     BOOL NumberValid = FALSE;
614     ULONG Number = 0;
615
616     if (!IsNextToken(TokenIdentifier, TRUE))
617         return CAB_STATUS_FAILURE;
618
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;
629     else
630         return CAB_STATUS_FAILURE;
631
632     if ((SetType == stDiskLabel) || (SetType == stCabinetName)) {
633         if (!IsNextToken(TokenInteger, FALSE))
634             return CAB_STATUS_FAILURE;
635         Number = CurrentInteger;
636
637         if (!IsNextToken(TokenEqual, TRUE))
638             return CAB_STATUS_FAILURE;
639     } else if (SetType == stMaxDiskSize) {
640         if (IsNextToken(TokenInteger, FALSE)) {
641             NumberValid = TRUE;
642             Number = CurrentInteger;
643         } else {
644             NumberValid = FALSE;
645             while (CurrentToken == TokenSpace)
646                 NextToken();
647             if (CurrentToken != TokenEqual)
648                 return CAB_STATUS_FAILURE;
649         }
650     } else if (!IsNextToken(TokenEqual, TRUE))
651             return CAB_STATUS_FAILURE;
652
653     if (SetType != stMaxDiskSize) {
654         if (!IsNextToken(TokenString, TRUE))
655             return CAB_STATUS_FAILURE;
656     }
657
658     switch (SetType) {
659     case stDiskLabel:
660         if (!DoDiskLabel(Number, CurrentString))
661             DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
662         return CAB_STATUS_SUCCESS;
663     case stCabinetName:
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;
673     case stMaxDiskSize:
674         return DoMaxDiskSize(NumberValid, Number);
675     default:
676         return CAB_STATUS_FAILURE;
677     }
678 }
679
680
681 ULONG CDFParser::PerformNewCommand()
682 /*
683  * FUNCTION: Performs a new disk|cabinet|folder command
684  * RETURNS:
685  *     Status of operation
686  */
687 {
688     NEWTYPE NewType;
689     ULONG Status;
690
691     if (!IsNextToken(TokenIdentifier, TRUE))
692         return CAB_STATUS_FAILURE;
693
694     if (strcmpi(CurrentString, "Disk") == 0)
695         NewType = ntDisk;
696     else if (strcmpi(CurrentString, "Cabinet") == 0)
697         NewType = ntCabinet;
698     else if (strcmpi(CurrentString, "Folder") == 0)
699         NewType = ntFolder;
700     else
701         return CAB_STATUS_FAILURE;
702
703     switch (NewType) {
704     case ntDisk:
705         if (DiskCreated) {
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;
712             }
713             DiskCreated = FALSE;
714         }
715
716         Status = NewDisk();
717         if (Status != CAB_STATUS_SUCCESS) {
718             DPRINT(MIN_TRACE, ("Cannot create disk (%d).\n", (UINT)Status));
719             return CAB_STATUS_SUCCESS;
720         }
721         DiskCreated = TRUE;
722         SetupNewDisk();
723         return CAB_STATUS_SUCCESS;
724     case ntCabinet:
725         if (DiskCreated) {
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;
732             }
733             DiskCreated = FALSE;
734         }
735
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;
740         }
741         DiskCreated = TRUE;
742         SetupNewDisk();
743         return CAB_STATUS_SUCCESS;
744     case ntFolder:
745         Status = NewFolder();
746                 ASSERT(Status == CAB_STATUS_SUCCESS);
747                 return CAB_STATUS_SUCCESS;
748     default:
749         return CAB_STATUS_FAILURE;
750     }
751 }
752
753
754 ULONG CDFParser::PerformCommand()
755 /*
756  * FUNCTION: Performs a command
757  * RETURNS:
758  *     Status of operation
759  */
760 {
761     if (strcmpi(CurrentString, "Set") == 0)
762         return PerformSetCommand();
763     if (strcmpi(CurrentString, "New") == 0)
764         return PerformNewCommand();
765
766     return CAB_STATUS_FAILURE;
767 }
768
769
770 ULONG CDFParser::PerformFileCopy()
771 /*
772  * FUNCTION: Performs a file copy
773  * RETURNS:
774  *     Status of operation
775  */
776 {
777     ULONG Status;
778     ULONG i, j;
779     TCHAR ch;
780     TCHAR SrcName[MAX_PATH];
781     TCHAR DstName[MAX_PATH];
782
783     lstrcpy(SrcName, "");
784     lstrcpy(DstName, "");
785
786     i = lstrlen(CurrentString);
787     while ((i < LineLength) &&
788         ((ch = Line[i]) != ' ') &&
789          (ch != 0x09) &&
790          (ch != ';')) {
791         CurrentString[i] = ch;
792         i++;
793     }
794     CurrentString[i] = '\0';
795     CurrentToken = TokenString;
796     CurrentChar  = i + 1;
797     lstrcpy(SrcName, CurrentString);
798
799     SkipSpaces();
800
801     if (CurrentToken != TokenEnd) {
802         j = lstrlen(CurrentString); i = 0;
803         while ((CurrentChar + i < LineLength) &&
804             ((ch = Line[CurrentChar + i]) != ' ') &&
805              (ch != 0x09) &&
806              (ch != ';')) {
807             CurrentString[j + i] = ch;
808             i++;
809         }
810         CurrentString[j + i] = '\0';
811         CurrentToken = TokenString;
812         CurrentChar += i + 1;
813         lstrcpy(DstName, CurrentString);
814     }
815
816     if (!CabinetCreated) {
817
818         DPRINT(MID_TRACE, ("Creating cabinet.\n"));
819
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;
825         }
826         CabinetCreated = TRUE;
827
828         DPRINT(MID_TRACE, ("Creating disk.\n"));
829
830         Status = NewDisk();
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;
835         }
836         DiskCreated = TRUE;
837         SetupNewDisk();
838     }
839
840     DPRINT(MID_TRACE, ("Adding file: '%s'   destination: '%s'.\n", SrcName, DstName));
841
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);
848         else
849             printf("Cannot add file: %s (%d).\n", SrcName, Status);
850         return Status;
851     }
852
853     return CAB_STATUS_SUCCESS;
854 }
855
856
857 VOID CDFParser::SkipSpaces()
858 /*
859  * FUNCTION: Skips any spaces in the current line
860  */
861 {
862     NextToken();
863     while (CurrentToken == TokenSpace)
864         NextToken();
865 }
866
867
868 BOOL CDFParser::IsNextToken(TOKEN Token, BOOL NoSpaces)
869 /*
870  * FUNCTION: Checks if next token equals Token
871  * ARGUMENTS:
872  *     Token  = Token to compare with
873  *     SkipSp = TRUE if spaces should be skipped
874  * RETURNS:
875  *     FALSE if next token is diffrent from Token
876  */
877 {
878     if (NoSpaces)
879         SkipSpaces();
880     else
881         NextToken();
882     return (CurrentToken == Token);
883 }
884
885
886 BOOL CDFParser::ReadLine()
887 /*
888  * FUNCTION: Reads the next line into the line buffer
889  * RETURNS:
890  *     TRUE if there is a new line, FALSE if not
891  */
892 {
893     ULONG i, j;
894     TCHAR ch;
895
896     if (CurrentOffset >= FileBufferSize)
897         return FALSE;
898
899     i = 0;
900     while (((j = CurrentOffset + i) < FileBufferSize) && (i < 127) &&
901         ((ch = FileBuffer[j]) != 0x0D)) {
902         Line[i] = ch;
903         i++;
904     }
905
906     Line[i]    = '\0';
907     LineLength = i;
908     
909     if (FileBuffer[CurrentOffset + i + 1] == 0x0A)
910         CurrentOffset++;
911
912     CurrentOffset += i + 1;
913
914     CurrentChar = 0;
915
916     CurrentLine++;
917
918     NextToken();
919
920     return TRUE;
921 }
922
923
924 VOID CDFParser::NextToken()
925 /*
926  * FUNCTION: Reads the next token from the current line
927  */
928 {
929     ULONG i;
930     TCHAR ch = ' ';
931
932     if (CurrentChar >= LineLength) {
933         CurrentToken = TokenEnd;
934         return;
935     }
936
937     switch (Line[CurrentChar]) {
938     case ' ':
939     case 0x09: CurrentToken = TokenSpace;
940         break;
941     case ';': CurrentToken = TokenSemi;
942         break;
943     case '=': CurrentToken = TokenEqual;
944         break;
945     case '.': CurrentToken = TokenPeriod;
946         break;
947     case '\\': CurrentToken = TokenBackslash;
948         break;
949     case '"':
950         i = 0;
951         while ((CurrentChar + i + 1 < LineLength) &&
952             ((ch = Line[CurrentChar + i + 1]) != '"')) {
953             CurrentString[i] = ch;
954             i++;
955         }
956         CurrentString[i] = '\0';
957         CurrentToken = TokenString;
958         CurrentChar += i + 2;
959         return;
960     default:
961         i = 0;
962         while ((CurrentChar + i < LineLength) &&
963             ((ch = Line[CurrentChar + i]) >= '0') && (ch <= '9')) {
964             CurrentString[i] = ch;
965             i++;
966         }
967         if (i > 0) {
968             CurrentString[i] = '\0';
969             CurrentInteger = atoi((PCHAR)CurrentString);
970             CurrentToken = TokenInteger;
971             CurrentChar += i;
972             return;
973         }
974         i = 0;
975         while (((CurrentChar + i < LineLength) &&
976             (((ch = Line[CurrentChar + i]) >= 'a') && (ch <= 'z')) ||
977             ((ch >= 'A') && (ch <= 'Z')) || (ch == '_'))) {
978             CurrentString[i] = ch;
979             i++;
980         }
981         if (i > 0) {
982             CurrentString[i] = '\0';
983             CurrentToken = TokenIdentifier;
984             CurrentChar += i;
985             return;
986         }
987         CurrentToken = TokenUnknown;
988     }
989     CurrentChar++;
990 }
991
992 /* EOF */