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
CDFParser()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
~CDFParser()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
WriteInfLine(char * InfLine)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
Load(char * FileName)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
Parse()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
SetFileRelativePath(char * Path)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
OnDiskLabel(ULONG Number,char * Label)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
OnCabinetName(ULONG Number,char * Name)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
SetDiskName(PCABINET_NAME * List,ULONG Number,char * String)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
GetDiskName(PCABINET_NAME * List,ULONG Number,char * String)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
SetDiskNumber(PDISK_NUMBER * List,ULONG Number,ULONG Value)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
GetDiskNumber(PDISK_NUMBER * List,ULONG Number,PULONG Value)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
DoDiskLabel(ULONG Number,char * Label)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
DoDiskLabelTemplate(char * Template)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
DoCabinetName(ULONG Number,char * Name)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
DoCabinetNameTemplate(char * Template)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
DoMaxDiskSize(bool NumberValid,ULONG Number)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
DoInfFileName(char * FileName)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
SetupNewDisk()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
PerformSetCommand()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
PerformNewCommand()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
PerformInfBeginCommand()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
PerformInfEndCommand()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
PerformCommand()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
PerformFileCopy()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*2+1]; // To hold: GetFileName(SrcName) "=" DstName
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 snprintf(InfLine, _countof(InfLine) - 1,
1137 "%s=%s", GetFileName(SrcName).c_str(), DstName);
1138 WriteInfLine(InfLine);
1139 break;
1140
1141 case CAB_STATUS_CANNOT_OPEN:
1142 if (strstr(Options, "optional"))
1143 {
1144 Status = CAB_STATUS_SUCCESS;
1145 printf("Optional file skipped (does not exist): %s.\n", SrcName);
1146 }
1147 else
1148 printf("ERROR: File not found: %s.\n", SrcName);
1149
1150 break;
1151
1152 case CAB_STATUS_NOMEMORY:
1153 printf("ERROR: Insufficient memory to add file: %s.\n", SrcName);
1154 break;
1155
1156 default:
1157 printf("ERROR: Cannot add file: %s (%u).\n", SrcName, (UINT)Status);
1158 break;
1159 }
1160 return Status;
1161 }
1162
1163
SkipSpaces()1164 void CDFParser::SkipSpaces()
1165 /*
1166 * FUNCTION: Skips any spaces in the current line
1167 */
1168 {
1169 NextToken();
1170 while (CurrentToken == TokenSpace)
1171 NextToken();
1172 }
1173
1174
IsNextToken(DFP_TOKEN Token,bool NoSpaces)1175 bool CDFParser::IsNextToken(DFP_TOKEN Token, bool NoSpaces)
1176 /*
1177 * FUNCTION: Checks if next token equals Token
1178 * ARGUMENTS:
1179 * Token = Token to compare with
1180 * SkipSp = true if spaces should be skipped
1181 * RETURNS:
1182 * false if next token is diffrent from Token
1183 */
1184 {
1185 if (NoSpaces)
1186 SkipSpaces();
1187 else
1188 NextToken();
1189 return (CurrentToken == Token);
1190 }
1191
1192
ReadLine()1193 bool CDFParser::ReadLine()
1194 /*
1195 * FUNCTION: Reads the next line into the line buffer
1196 * RETURNS:
1197 * true if there is a new line, false if not
1198 */
1199 {
1200 ULONG i, j;
1201 char ch;
1202
1203 if (CurrentOffset >= FileBufferSize)
1204 return false;
1205
1206 i = 0;
1207 while (((j = CurrentOffset + i) < FileBufferSize) && (i < sizeof(Line) - 1) &&
1208 ((ch = FileBuffer[j]) != 0x0D && (ch = FileBuffer[j]) != 0x0A))
1209 {
1210 Line[i] = ch;
1211 i++;
1212 }
1213
1214 Line[i] = '\0';
1215 LineLength = i;
1216
1217 if ((FileBuffer[CurrentOffset + i] == 0x0D) && (FileBuffer[CurrentOffset + i + 1] == 0x0A))
1218 CurrentOffset++;
1219
1220 CurrentOffset += i + 1;
1221
1222 CurrentChar = 0;
1223
1224 CurrentLine++;
1225
1226 NextToken();
1227
1228 return true;
1229 }
1230
1231
NextToken()1232 void CDFParser::NextToken()
1233 /*
1234 * FUNCTION: Reads the next token from the current line
1235 */
1236 {
1237 ULONG i;
1238 char ch = ' ';
1239
1240 if (CurrentChar >= LineLength)
1241 {
1242 CurrentToken = TokenEnd;
1243 return;
1244 }
1245
1246 switch (Line[CurrentChar])
1247 {
1248 case ' ':
1249 case 0x09:
1250 CurrentToken = TokenSpace;
1251 break;
1252
1253 case ';':
1254 CurrentToken = TokenSemi;
1255 break;
1256
1257 case '=':
1258 CurrentToken = TokenEqual;
1259 break;
1260
1261 case '.':
1262 CurrentToken = TokenPeriod;
1263 break;
1264
1265 case '\\':
1266 CurrentToken = TokenBackslash;
1267 break;
1268
1269 case '"':
1270 i = 0;
1271 while ((CurrentChar + i + 1 < LineLength) &&
1272 ((ch = Line[CurrentChar + i + 1]) != '"'))
1273 {
1274 CurrentString[i] = ch;
1275 i++;
1276 }
1277 CurrentString[i] = '\0';
1278 CurrentToken = TokenString;
1279 CurrentChar += i + 2;
1280 return;
1281
1282 default:
1283 i = 0;
1284 while ((CurrentChar + i < LineLength) &&
1285 ((ch = Line[CurrentChar + i]) >= '0') && (ch <= '9'))
1286 {
1287 CurrentString[i] = ch;
1288 i++;
1289 }
1290 if (i > 0)
1291 {
1292 CurrentString[i] = '\0';
1293 CurrentInteger = atoi(CurrentString);
1294 CurrentToken = TokenInteger;
1295 CurrentChar += i;
1296 return;
1297 }
1298 i = 0;
1299 while (((CurrentChar + i < LineLength) &&
1300 (((ch = Line[CurrentChar + i]) >= 'a') && (ch <= 'z'))) ||
1301 ((ch >= 'A') && (ch <= 'Z')) || (ch == '_'))
1302 {
1303 CurrentString[i] = ch;
1304 i++;
1305 }
1306 if (i > 0)
1307 {
1308 CurrentString[i] = '\0';
1309 CurrentToken = TokenIdentifier;
1310 CurrentChar += i;
1311 return;
1312 }
1313 CurrentToken = TokenEnd;
1314 }
1315 CurrentChar++;
1316 }
1317
1318 /* EOF */
1319