2c8995a5f84dde2641f836249da7d2aa851b9e50
[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 * 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 "cabinet.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[MAX_PATH];
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("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("Directive file contains errors at line %u.\n", (UINT)CurrentLine);
363 DPRINT(MID_TRACE, ("Error while copying file.\n"));
364 }
365
366 if (Status != CAB_STATUS_SUCCESS)
367 return Status;
368 }
369 break;
370
371 case TokenSpace:
372 break;
373
374 case TokenSemi:
375 CurrentToken = TokenEnd;
376 continue;
377
378 case TokenPeriod:
379 Command = true;
380 break;
381
382 default:
383 printf("Directive file contains errors at line %u.\n", (UINT)CurrentLine);
384 DPRINT(MID_TRACE, ("Token is (%u).\n", (UINT)CurrentToken));
385 return CAB_STATUS_SUCCESS;
386 }
387 NextToken();
388 }
389 }
390 }
391
392 if (!InfFileOnly)
393 {
394 printf("\nWriting cabinet. This may take a while...\n\n");
395
396 if (DiskCreated)
397 {
398 Status = WriteDisk(false);
399 if (Status == CAB_STATUS_SUCCESS)
400 Status = CloseDisk();
401 if (Status != CAB_STATUS_SUCCESS)
402 {
403 DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
404 return Status;
405 }
406 }
407
408 if (CabinetCreated)
409 {
410 Status = CloseCabinet();
411 if (Status != CAB_STATUS_SUCCESS)
412 {
413 DPRINT(MIN_TRACE, ("Cannot close cabinet (%u).\n", (UINT)Status));
414 return Status;
415 }
416 }
417
418 printf("\nDone.\n");
419 }
420
421 return CAB_STATUS_SUCCESS;
422 }
423
424
425 void CDFParser::SetFileRelativePath(char* Path)
426 /*
427 * FUNCTION: Sets path where files in the .dff is assumed relative to
428 * ARGUMENTS:
429 * Path = Pointer to string with path
430 */
431 {
432 strcpy(FileRelativePath, Path);
433 ConvertPath(FileRelativePath, false);
434 if (strlen(FileRelativePath) > 0)
435 NormalizePath(FileRelativePath, MAX_PATH);
436 }
437
438
439 bool CDFParser::OnDiskLabel(ULONG Number, char* Label)
440 /*
441 * FUNCTION: Called when a disk needs a label
442 * ARGUMENTS:
443 * Number = Cabinet number that needs a label
444 * Label = Pointer to buffer to place label of disk
445 * RETURNS:
446 * true if a disk label was returned, false if not
447 */
448 {
449 char Buffer[20];
450 ULONG i;
451 int j;
452 char ch;
453
454 Number += 1;
455
456 DPRINT(MID_TRACE, ("Giving disk (%u) a label...\n", (UINT)Number));
457
458 if (GetDiskName(&DiskLabel, Number, Label))
459 return true;
460
461 if (DiskLabelTemplateSet)
462 {
463 j = 0;
464 strcpy(Label, "");
465 for (i = 0; i < strlen(DiskLabelTemplate); i++)
466 {
467 ch = DiskLabelTemplate[i];
468 if (ch == '*')
469 {
470 sprintf(Buffer, "%u", (UINT)Number);
471 strcat(Label, Buffer);
472 j += (LONG)strlen(Buffer);
473 }
474 else
475 {
476 Label[j] = ch;
477 j++;
478 }
479 Label[j] = '\0';
480 }
481
482 DPRINT(MID_TRACE, ("Giving disk (%s) as a label...\n", Label));
483
484 return true;
485 }
486 else
487 return false;
488 }
489
490
491 bool CDFParser::OnCabinetName(ULONG Number, char* Name)
492 /*
493 * FUNCTION: Called when a cabinet needs a name
494 * ARGUMENTS:
495 * Number = Disk number that needs a name
496 * Name = Pointer to buffer to place name of cabinet
497 * RETURNS:
498 * true if a cabinet name was returned, false if not
499 */
500 {
501 char Buffer[MAX_PATH];
502 ULONG i;
503 int j;
504 char ch;
505
506 Number += 1;
507
508 DPRINT(MID_TRACE, ("Giving cabinet (%u) a name...\n", (UINT)Number));
509
510 if (GetDiskName(&CabinetName, Number, Buffer))
511 {
512 strcpy(Name, GetDestinationPath());
513 strcat(Name, Buffer);
514 return true;
515 }
516
517 if (CabinetNameTemplateSet)
518 {
519 strcpy(Name, GetDestinationPath());
520 j = (LONG)strlen(Name);
521 for (i = 0; i < strlen(CabinetNameTemplate); i++)
522 {
523 ch = CabinetNameTemplate[i];
524 if (ch == '*')
525 {
526 sprintf(Buffer, "%u", (UINT)Number);
527 strcat(Name, Buffer);
528 j += (LONG)strlen(Buffer);
529 }
530 else
531 {
532 Name[j] = ch;
533 j++;
534 }
535 Name[j] = '\0';
536 }
537
538 DPRINT(MID_TRACE, ("Giving cabinet (%s) as a name...\n", Name));
539 return true;
540 }
541 else
542 return false;
543 }
544
545
546 bool CDFParser::SetDiskName(PCABINET_NAME *List, ULONG Number, char* String)
547 /*
548 * FUNCTION: Sets an entry in a list
549 * ARGUMENTS:
550 * List = Address of pointer to list
551 * Number = Disk number
552 * String = Pointer to string
553 * RETURNS:
554 * false if there was not enough free memory available
555 */
556 {
557 PCABINET_NAME CN;
558
559 CN = *List;
560 while (CN != NULL)
561 {
562 if (CN->DiskNumber == Number)
563 {
564 strcpy(CN->Name, String);
565 return true;
566 }
567 CN = CN->Next;
568 }
569
570 CN = (PCABINET_NAME)AllocateMemory(sizeof(CABINET_NAME));
571 if (!CN)
572 return false;
573
574 CN->DiskNumber = Number;
575 strcpy(CN->Name, String);
576
577 CN->Next = *List;
578 *List = CN;
579
580 return true;
581 }
582
583
584 bool CDFParser::GetDiskName(PCABINET_NAME *List, ULONG Number, char* String)
585 /*
586 * FUNCTION: Returns an entry in a list
587 * ARGUMENTS:
588 * List = Address of pointer to list
589 * Number = Disk number
590 * String = Address of buffer to copy string to
591 * RETURNS:
592 * false if there was not enough free memory available
593 */
594 {
595 PCABINET_NAME CN;
596
597 CN = *List;
598 while (CN != NULL)
599 {
600 if (CN->DiskNumber == Number)
601 {
602 strcpy(String, CN->Name);
603 return true;
604 }
605 CN = CN->Next;
606 }
607
608 return false;
609 }
610
611
612 bool CDFParser::SetDiskNumber(PDISK_NUMBER *List, ULONG Number, ULONG Value)
613 /*
614 * FUNCTION: Sets an entry in a list
615 * ARGUMENTS:
616 * List = Address of pointer to list
617 * Number = Disk number
618 * Value = Value to set
619 * RETURNS:
620 * false if there was not enough free memory available
621 */
622 {
623 PDISK_NUMBER DN;
624
625 DN = *List;
626 while (DN != NULL)
627 {
628 if (DN->DiskNumber == Number)
629 {
630 DN->Number = Value;
631 return true;
632 }
633 DN = DN->Next;
634 }
635
636 DN = (PDISK_NUMBER)AllocateMemory(sizeof(DISK_NUMBER));
637 if (!DN)
638 return false;
639
640 DN->DiskNumber = Number;
641 DN->Number = Value;
642
643 DN->Next = *List;
644 *List = DN;
645
646 return true;
647 }
648
649
650 bool CDFParser::GetDiskNumber(PDISK_NUMBER *List, ULONG Number, PULONG Value)
651 /*
652 * FUNCTION: Returns an entry in a list
653 * ARGUMENTS:
654 * List = Address of pointer to list
655 * Number = Disk number
656 * Value = Address of buffer to place value
657 * RETURNS:
658 * true if the entry was found
659 */
660 {
661 PDISK_NUMBER DN;
662
663 DN = *List;
664 while (DN != NULL)
665 {
666 if (DN->DiskNumber == Number)
667 {
668 *Value = DN->Number;
669 return true;
670 }
671 DN = DN->Next;
672 }
673
674 return false;
675 }
676
677
678 bool CDFParser::DoDiskLabel(ULONG Number, char* Label)
679 /*
680 * FUNCTION: Sets the label of a disk
681 * ARGUMENTS:
682 * Number = Disk number
683 * Label = Pointer to label of disk
684 * RETURNS:
685 * false if there was not enough free memory available
686 */
687 {
688 DPRINT(MID_TRACE, ("Setting label of disk (%u) to '%s'\n", (UINT)Number, Label));
689
690 return SetDiskName(&DiskLabel, Number, Label);
691 }
692
693
694 void CDFParser::DoDiskLabelTemplate(char* Template)
695 /*
696 * FUNCTION: Sets a disk label template to use
697 * ARGUMENTS:
698 * Template = Pointer to disk label template
699 */
700 {
701 DPRINT(MID_TRACE, ("Setting disk label template to '%s'\n", Template));
702
703 strcpy(DiskLabelTemplate, Template);
704 DiskLabelTemplateSet = true;
705 }
706
707
708 bool CDFParser::DoCabinetName(ULONG Number, char* Name)
709 /*
710 * FUNCTION: Sets the name of a cabinet
711 * ARGUMENTS:
712 * Number = Disk number
713 * Name = Pointer to name of cabinet
714 * RETURNS:
715 * false if there was not enough free memory available
716 */
717 {
718 DPRINT(MID_TRACE, ("Setting name of cabinet (%u) to '%s'\n", (UINT)Number, Name));
719
720 return SetDiskName(&CabinetName, Number, Name);
721 }
722
723
724 void CDFParser::DoCabinetNameTemplate(char* Template)
725 /*
726 * FUNCTION: Sets a cabinet name template to use
727 * ARGUMENTS:
728 * Template = Pointer to cabinet name template
729 */
730 {
731 DPRINT(MID_TRACE, ("Setting cabinet name template to '%s'\n", Template));
732
733 strcpy(CabinetNameTemplate, Template);
734 CabinetNameTemplateSet = true;
735 }
736
737
738 ULONG CDFParser::DoMaxDiskSize(bool NumberValid, ULONG Number)
739 /*
740 * FUNCTION: Sets the maximum disk size
741 * ARGUMENTS:
742 * NumberValid = true if disk number is valid
743 * Number = Disk number
744 * RETURNS:
745 * Status of operation
746 * NOTES:
747 * Standard sizes are 2.88M, 1.44M, 1.25M, 1.2M, 720K, 360K, and CDROM
748 */
749 {
750 ULONG A, B, Value;
751
752 if (IsNextToken(TokenInteger, true))
753 {
754 A = CurrentInteger;
755
756 if (IsNextToken(TokenPeriod, false))
757 {
758 if (!IsNextToken(TokenInteger, false))
759 return CAB_STATUS_FAILURE;
760
761 B = CurrentInteger;
762
763 }
764 else
765 B = 0;
766
767 if (CurrentToken == TokenIdentifier)
768 {
769 switch (CurrentString[0])
770 {
771 case 'K':
772 if (B != 0)
773 return CAB_STATUS_FAILURE;
774
775 if (A == 720)
776 /* 720K disk */
777 Value = 730112;
778 else if (A == 360)
779 /* 360K disk */
780 Value = 362496;
781 else
782 return CAB_STATUS_FAILURE;
783 break;
784
785 case 'M':
786 if (A == 1)
787 {
788 if (B == 44)
789 /* 1.44M disk */
790 Value = 1457664;
791 else if (B == 25)
792 /* 1.25M disk */
793 Value = 1300000; // FIXME: Value?
794 else if (B == 2)
795 /* 1.2M disk */
796 Value = 1213952;
797 else
798 return CAB_STATUS_FAILURE;
799 }
800 else if (A == 2)
801 {
802 if (B == 88)
803 /* 2.88M disk */
804 Value = 2915328;
805 else
806 return CAB_STATUS_FAILURE;
807 }
808 else
809 return CAB_STATUS_FAILURE;
810 break;
811
812 default:
813 DPRINT(MID_TRACE, ("Bad suffix (%c)\n", CurrentString[0]));
814 return CAB_STATUS_FAILURE;
815 }
816 }
817 else
818 Value = A;
819 }
820 else
821 {
822 if ((CurrentToken != TokenString) &&
823 (strcasecmp(CurrentString, "CDROM") != 0))
824 return CAB_STATUS_FAILURE;
825 /* CDROM */
826 Value = 640*1024*1024; // FIXME: Correct size for CDROM?
827 }
828
829 if (NumberValid)
830 return (SetDiskNumber(&MaxDiskSize, Number, Value)?
831 CAB_STATUS_SUCCESS : CAB_STATUS_FAILURE);
832
833 MaxDiskSizeAll = Value;
834 MaxDiskSizeAllSet = true;
835
836 SetMaxDiskSize(Value);
837
838 return CAB_STATUS_SUCCESS;
839 }
840
841
842 void CDFParser::DoInfFileName(char* FileName)
843 /*
844 * FUNCTION: Sets filename of the generated .inf file
845 * ARGUMENTS:
846 * FileName = Pointer to .inf filename
847 */
848 {
849 DPRINT(MID_TRACE, ("Setting .inf filename to '%s'\n", FileName));
850
851 strcpy(InfFileName, FileName);
852 InfFileNameSet = true;
853 }
854
855 ULONG CDFParser::SetupNewDisk()
856 /*
857 * FUNCTION: Sets up parameters for a new disk
858 * RETURNS:
859 * Status of operation
860 */
861 {
862 ULONG Value;
863
864 if (!GetDiskNumber(&MaxDiskSize, GetCurrentDiskNumber(), &Value))
865 {
866 if (MaxDiskSizeAllSet)
867 Value = MaxDiskSizeAll;
868 else
869 Value = 0;
870 }
871 SetMaxDiskSize(Value);
872
873 return CAB_STATUS_SUCCESS;
874 }
875
876
877 ULONG CDFParser::PerformSetCommand()
878 /*
879 * FUNCTION: Performs a set variable command
880 * RETURNS:
881 * Status of operation
882 */
883 {
884 SETTYPE SetType;
885 bool NumberValid = false;
886 ULONG Number = 0;
887
888 if (!IsNextToken(TokenIdentifier, true))
889 return CAB_STATUS_FAILURE;
890
891 if (strcasecmp(CurrentString, "DiskLabel") == 0)
892 SetType = stDiskLabel;
893 else if (strcasecmp(CurrentString, "DiskLabelTemplate") == 0)
894 SetType = stDiskLabelTemplate;
895 else if (strcasecmp(CurrentString, "CabinetName") == 0)
896 SetType = stCabinetName;
897 else if (strcasecmp(CurrentString, "CabinetNameTemplate") == 0)
898 SetType = stCabinetNameTemplate;
899 else if (strcasecmp(CurrentString, "MaxDiskSize") == 0)
900 SetType = stMaxDiskSize;
901 else if (strcasecmp(CurrentString, "InfFileName") == 0)
902 SetType = stInfFileName;
903 else
904 return CAB_STATUS_FAILURE;
905
906 if ((SetType == stDiskLabel) || (SetType == stCabinetName))
907 {
908 if (!IsNextToken(TokenInteger, false))
909 return CAB_STATUS_FAILURE;
910 Number = CurrentInteger;
911
912 if (!IsNextToken(TokenEqual, true))
913 return CAB_STATUS_FAILURE;
914 }
915 else if (SetType == stMaxDiskSize)
916 {
917 if (IsNextToken(TokenInteger, false))
918 {
919 NumberValid = true;
920 Number = CurrentInteger;
921 }
922 else
923 {
924 NumberValid = false;
925 while (CurrentToken == TokenSpace)
926 NextToken();
927 if (CurrentToken != TokenEqual)
928 return CAB_STATUS_FAILURE;
929 }
930 }
931 else if (!IsNextToken(TokenEqual, true))
932 return CAB_STATUS_FAILURE;
933
934 if (SetType != stMaxDiskSize)
935 {
936 if (!IsNextToken(TokenString, true))
937 return CAB_STATUS_FAILURE;
938 }
939
940 switch (SetType)
941 {
942 case stDiskLabel:
943 if (!DoDiskLabel(Number, CurrentString))
944 DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
945 return CAB_STATUS_SUCCESS;
946
947 case stCabinetName:
948 if (!DoCabinetName(Number, CurrentString))
949 DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
950 return CAB_STATUS_SUCCESS;
951
952 case stDiskLabelTemplate:
953 DoDiskLabelTemplate(CurrentString);
954 return CAB_STATUS_SUCCESS;
955
956 case stCabinetNameTemplate:
957 DoCabinetNameTemplate(CurrentString);
958 return CAB_STATUS_SUCCESS;
959
960 case stMaxDiskSize:
961 return DoMaxDiskSize(NumberValid, Number);
962
963 case stInfFileName:
964 DoInfFileName(CurrentString);
965 return CAB_STATUS_SUCCESS;
966
967 default:
968 return CAB_STATUS_FAILURE;
969 }
970 }
971
972
973 ULONG CDFParser::PerformNewCommand()
974 /*
975 * FUNCTION: Performs a new disk|cabinet|folder command
976 * RETURNS:
977 * Status of operation
978 */
979 {
980 NEWTYPE NewType;
981 ULONG Status;
982
983 if (!IsNextToken(TokenIdentifier, true))
984 return CAB_STATUS_FAILURE;
985
986 if (strcasecmp(CurrentString, "Disk") == 0)
987 NewType = ntDisk;
988 else if (strcasecmp(CurrentString, "Cabinet") == 0)
989 NewType = ntCabinet;
990 else if (strcasecmp(CurrentString, "Folder") == 0)
991 NewType = ntFolder;
992 else
993 return CAB_STATUS_FAILURE;
994
995 switch (NewType)
996 {
997 case ntDisk:
998 if (DiskCreated)
999 {
1000 Status = WriteDisk(true);
1001 if (Status == CAB_STATUS_SUCCESS)
1002 Status = CloseDisk();
1003 if (Status != CAB_STATUS_SUCCESS)
1004 {
1005 DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
1006 return CAB_STATUS_SUCCESS;
1007 }
1008 DiskCreated = false;
1009 }
1010
1011 Status = NewDisk();
1012 if (Status != CAB_STATUS_SUCCESS)
1013 {
1014 DPRINT(MIN_TRACE, ("Cannot create disk (%u).\n", (UINT)Status));
1015 return CAB_STATUS_SUCCESS;
1016 }
1017 DiskCreated = true;
1018 SetupNewDisk();
1019 return CAB_STATUS_SUCCESS;
1020
1021 case ntCabinet:
1022 if (DiskCreated)
1023 {
1024 Status = WriteDisk(true);
1025 if (Status == CAB_STATUS_SUCCESS)
1026 Status = CloseDisk();
1027 if (Status != CAB_STATUS_SUCCESS)
1028 {
1029 DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
1030 return CAB_STATUS_SUCCESS;
1031 }
1032 DiskCreated = false;
1033 }
1034
1035 Status = NewCabinet();
1036 if (Status != CAB_STATUS_SUCCESS)
1037 {
1038 DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
1039 return CAB_STATUS_SUCCESS;
1040 }
1041 DiskCreated = true;
1042 SetupNewDisk();
1043 return CAB_STATUS_SUCCESS;
1044
1045 case ntFolder:
1046 Status = NewFolder();
1047 ASSERT(Status == CAB_STATUS_SUCCESS);
1048 return CAB_STATUS_SUCCESS;
1049
1050 default:
1051 return CAB_STATUS_FAILURE;
1052 }
1053 }
1054
1055
1056 ULONG CDFParser::PerformInfBeginCommand()
1057 /*
1058 * FUNCTION: Begins inf mode
1059 * RETURNS:
1060 * Status of operation
1061 */
1062 {
1063 InfModeEnabled = true;
1064 return CAB_STATUS_SUCCESS;
1065 }
1066
1067
1068 ULONG CDFParser::PerformInfEndCommand()
1069 /*
1070 * FUNCTION: Begins inf mode
1071 * RETURNS:
1072 * Status of operation
1073 */
1074 {
1075 InfModeEnabled = false;
1076 return CAB_STATUS_SUCCESS;
1077 }
1078
1079
1080 ULONG CDFParser::PerformCommand()
1081 /*
1082 * FUNCTION: Performs a command
1083 * RETURNS:
1084 * Status of operation
1085 */
1086 {
1087 if (strcasecmp(CurrentString, "Set") == 0)
1088 return PerformSetCommand();
1089 if (strcasecmp(CurrentString, "New") == 0)
1090 return PerformNewCommand();
1091 if (strcasecmp(CurrentString, "InfBegin") == 0)
1092 return PerformInfBeginCommand();
1093 if (strcasecmp(CurrentString, "InfEnd") == 0)
1094 return PerformInfEndCommand();
1095
1096 return CAB_STATUS_FAILURE;
1097 }
1098
1099
1100 ULONG CDFParser::PerformFileCopy()
1101 /*
1102 * FUNCTION: Performs a file copy
1103 * RETURNS:
1104 * Status of operation
1105 */
1106 {
1107 ULONG Status;
1108 ULONG i, j;
1109 char ch;
1110 char SrcName[MAX_PATH];
1111 char DstName[MAX_PATH];
1112 char InfLine[MAX_PATH];
1113 char Options[128];
1114 char BaseFilename[MAX_PATH];
1115
1116 *SrcName = '\0';
1117 *DstName = '\0';
1118 *Options = '\0';
1119
1120 // source file
1121 i = CurrentChar;
1122 while ((i < LineLength) &&
1123 ((ch = Line[i]) != ' ') &&
1124 (ch != 0x09) &&
1125 (ch != ';'))
1126 {
1127 CurrentString[i] = ch;
1128 i++;
1129 }
1130 CurrentString[i] = '\0';
1131 CurrentToken = TokenString;
1132 CurrentChar = i + 1;
1133 strcpy(BaseFilename, CurrentString);
1134 strcat(SrcName, BaseFilename);
1135
1136 // destination
1137 SkipSpaces();
1138
1139 if (CurrentToken != TokenEnd)
1140 {
1141 j = (ULONG)strlen(CurrentString); i = 0;
1142 while ((CurrentChar + i < LineLength) &&
1143 ((ch = Line[CurrentChar + i]) != ' ') &&
1144 (ch != 0x09) &&
1145 (ch != ';'))
1146 {
1147 CurrentString[j + i] = ch;
1148 i++;
1149 }
1150 CurrentString[j + i] = '\0';
1151 CurrentToken = TokenString;
1152 CurrentChar += i + 1;
1153 strcpy(DstName, CurrentString);
1154 }
1155
1156 // options (it may be empty)
1157 SkipSpaces ();
1158
1159 if (CurrentToken != TokenEnd)
1160 {
1161 j = (ULONG)strlen(CurrentString); i = 0;
1162 while ((CurrentChar + i < LineLength) &&
1163 ((ch = Line[CurrentChar + i]) != ' ') &&
1164 (ch != 0x09) &&
1165 (ch != ';'))
1166 {
1167 CurrentString[j + i] = ch;
1168 i++;
1169 }
1170 CurrentString[j + i] = '\0';
1171 CurrentToken = TokenString;
1172 CurrentChar += i + 1;
1173 strcpy(Options, CurrentString);
1174 }
1175
1176 if (!CabinetCreated)
1177 {
1178 DPRINT(MID_TRACE, ("Creating cabinet.\n"));
1179
1180 Status = NewCabinet();
1181 if (Status != CAB_STATUS_SUCCESS)
1182 {
1183 DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
1184 printf("Cannot create cabinet.\n");
1185 return CAB_STATUS_FAILURE;
1186 }
1187 CabinetCreated = true;
1188
1189 DPRINT(MID_TRACE, ("Creating disk.\n"));
1190
1191 Status = NewDisk();
1192 if (Status != CAB_STATUS_SUCCESS)
1193 {
1194 DPRINT(MIN_TRACE, ("Cannot create disk (%u).\n", (UINT)Status));
1195 printf("Cannot create disk.\n");
1196 return CAB_STATUS_FAILURE;
1197 }
1198 DiskCreated = true;
1199 SetupNewDisk();
1200 }
1201
1202 DPRINT(MID_TRACE, ("Adding file: '%s' destination: '%s'.\n", SrcName, DstName));
1203
1204 Status = AddFile(SrcName);
1205 if (Status == CAB_STATUS_CANNOT_OPEN)
1206 {
1207 strcpy(SrcName, FileRelativePath);
1208 strcat(SrcName, BaseFilename);
1209 Status = AddFile(SrcName);
1210 }
1211 switch (Status)
1212 {
1213 case CAB_STATUS_SUCCESS:
1214 sprintf(InfLine, "%s=%s", GetFileName(SrcName), DstName);
1215 WriteInfLine(InfLine);
1216 break;
1217
1218 case CAB_STATUS_CANNOT_OPEN:
1219 if (strstr(Options,"optional"))
1220 {
1221 Status = CAB_STATUS_SUCCESS;
1222 printf("Optional file does not exist: %s.\n", SrcName);
1223 }
1224 else
1225 printf("File does not exist: %s.\n", SrcName);
1226
1227 break;
1228
1229 case CAB_STATUS_NOMEMORY:
1230 printf("Insufficient memory to add file: %s.\n", SrcName);
1231 break;
1232
1233 default:
1234 printf("Cannot add file: %s (%u).\n", SrcName, (UINT)Status);
1235 break;
1236 }
1237 return Status;
1238 }
1239
1240
1241 void CDFParser::SkipSpaces()
1242 /*
1243 * FUNCTION: Skips any spaces in the current line
1244 */
1245 {
1246 NextToken();
1247 while (CurrentToken == TokenSpace)
1248 NextToken();
1249 }
1250
1251
1252 bool CDFParser::IsNextToken(DFP_TOKEN Token, bool NoSpaces)
1253 /*
1254 * FUNCTION: Checks if next token equals Token
1255 * ARGUMENTS:
1256 * Token = Token to compare with
1257 * SkipSp = true if spaces should be skipped
1258 * RETURNS:
1259 * false if next token is diffrent from Token
1260 */
1261 {
1262 if (NoSpaces)
1263 SkipSpaces();
1264 else
1265 NextToken();
1266 return (CurrentToken == Token);
1267 }
1268
1269
1270 bool CDFParser::ReadLine()
1271 /*
1272 * FUNCTION: Reads the next line into the line buffer
1273 * RETURNS:
1274 * true if there is a new line, false if not
1275 */
1276 {
1277 ULONG i, j;
1278 char ch;
1279
1280 if (CurrentOffset >= FileBufferSize)
1281 return false;
1282
1283 i = 0;
1284 while (((j = CurrentOffset + i) < FileBufferSize) && (i < 127) &&
1285 ((ch = FileBuffer[j]) != 0x0D && (ch = FileBuffer[j]) != 0x0A))
1286 {
1287 Line[i] = ch;
1288 i++;
1289 }
1290
1291 Line[i] = '\0';
1292 LineLength = i;
1293
1294 if ((FileBuffer[CurrentOffset + i] == 0x0D) && (FileBuffer[CurrentOffset + i + 1] == 0x0A))
1295 CurrentOffset++;
1296
1297 CurrentOffset += i + 1;
1298
1299 CurrentChar = 0;
1300
1301 CurrentLine++;
1302
1303 NextToken();
1304
1305 return true;
1306 }
1307
1308
1309 void CDFParser::NextToken()
1310 /*
1311 * FUNCTION: Reads the next token from the current line
1312 */
1313 {
1314 ULONG i;
1315 char ch = ' ';
1316
1317 if (CurrentChar >= LineLength)
1318 {
1319 CurrentToken = TokenEnd;
1320 return;
1321 }
1322
1323 switch (Line[CurrentChar])
1324 {
1325 case ' ':
1326 case 0x09:
1327 CurrentToken = TokenSpace;
1328 break;
1329
1330 case ';':
1331 CurrentToken = TokenSemi;
1332 break;
1333
1334 case '=':
1335 CurrentToken = TokenEqual;
1336 break;
1337
1338 case '.':
1339 CurrentToken = TokenPeriod;
1340 break;
1341
1342 case '\\':
1343 CurrentToken = TokenBackslash;
1344 break;
1345
1346 case '"':
1347 i = 0;
1348 while ((CurrentChar + i + 1 < LineLength) &&
1349 ((ch = Line[CurrentChar + i + 1]) != '"'))
1350 {
1351 CurrentString[i] = ch;
1352 i++;
1353 }
1354 CurrentString[i] = '\0';
1355 CurrentToken = TokenString;
1356 CurrentChar += i + 2;
1357 return;
1358
1359 default:
1360 i = 0;
1361 while ((CurrentChar + i < LineLength) &&
1362 ((ch = Line[CurrentChar + i]) >= '0') && (ch <= '9'))
1363 {
1364 CurrentString[i] = ch;
1365 i++;
1366 }
1367 if (i > 0)
1368 {
1369 CurrentString[i] = '\0';
1370 CurrentInteger = atoi(CurrentString);
1371 CurrentToken = TokenInteger;
1372 CurrentChar += i;
1373 return;
1374 }
1375 i = 0;
1376 while ((CurrentChar + i < LineLength) &&
1377 (((ch = Line[CurrentChar + i]) >= 'a') && (ch <= 'z')) ||
1378 ((ch >= 'A') && (ch <= 'Z')) || (ch == '_'))
1379 {
1380 CurrentString[i] = ch;
1381 i++;
1382 }
1383 if (i > 0)
1384 {
1385 CurrentString[i] = '\0';
1386 CurrentToken = TokenIdentifier;
1387 CurrentChar += i;
1388 return;
1389 }
1390 CurrentToken = TokenEnd;
1391 }
1392 CurrentChar++;
1393 }
1394
1395 /* EOF */