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