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