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