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