1 /*++ 2 3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 ParseInf.c 15 16 Abstract: 17 18 This contains some useful functions for parsing INF files. 19 20 --*/ 21 22 #include "ParseInf.h" 23 #include <assert.h> 24 #include <string.h> 25 #include <ctype.h> 26 27 CHAR8 * 28 ReadLine ( 29 IN MEMORY_FILE *InputFile, 30 IN OUT CHAR8 *InputBuffer, 31 IN UINTN MaxLength 32 ) 33 /*++ 34 35 Routine Description: 36 37 This function reads a line, stripping any comments. 38 The function reads a string from the input stream argument and stores it in 39 the input string. ReadLine reads characters from the current file position 40 to and including the first newline character, to the end of the stream, or 41 until the number of characters read is equal to MaxLength - 1, whichever 42 comes first. The newline character, if read, is replaced with a \0. 43 44 Arguments: 45 46 InputFile Memory file image. 47 InputBuffer Buffer to read into, must be _MAX_PATH size. 48 MaxLength The maximum size of the input buffer. 49 50 Returns: 51 52 NULL if error or EOF 53 InputBuffer otherwise 54 55 --*/ 56 { 57 CHAR8 *CharPtr; 58 CHAR8 *EndOfLine; 59 UINTN CharsToCopy; 60 61 // 62 // Verify input parameters are not null 63 // 64 assert (InputBuffer); 65 assert (InputFile->FileImage); 66 assert (InputFile->Eof); 67 assert (InputFile->CurrentFilePointer); 68 69 // 70 // Check for end of file condition 71 // 72 if (InputFile->CurrentFilePointer >= InputFile->Eof) { 73 return NULL; 74 } 75 // 76 // Find the next newline char 77 // 78 EndOfLine = strchr (InputFile->CurrentFilePointer, '\n'); 79 80 // 81 // Determine the number of characters to copy. 82 // 83 if (EndOfLine == 0) { 84 // 85 // If no newline found, copy to the end of the file. 86 // 87 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; 88 } else if (EndOfLine >= InputFile->Eof) { 89 // 90 // If the newline found was beyond the end of file, copy to the eof. 91 // 92 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; 93 } else { 94 // 95 // Newline found in the file. 96 // 97 CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; 98 } 99 // 100 // If the end of line is too big for the current buffer, set it to the max 101 // size of the buffer (leaving room for the \0. 102 // 103 if (CharsToCopy > MaxLength - 1) { 104 CharsToCopy = MaxLength - 1; 105 } 106 // 107 // Copy the line. 108 // 109 memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy); 110 111 // 112 // Add the null termination over the 0x0D 113 // 114 InputBuffer[CharsToCopy - 1] = '\0'; 115 116 // 117 // Increment the current file pointer (include the 0x0A) 118 // 119 InputFile->CurrentFilePointer += CharsToCopy + 1; 120 121 // 122 // Strip any comments 123 // 124 CharPtr = strstr (InputBuffer, "//"); 125 if (CharPtr != 0) { 126 CharPtr[0] = 0; 127 } 128 // 129 // Return the string 130 // 131 return InputBuffer; 132 } 133 134 BOOLEAN 135 FindSection ( 136 IN MEMORY_FILE *InputFile, 137 IN CHAR8 *Section 138 ) 139 /*++ 140 141 Routine Description: 142 143 This function parses a file from the beginning to find a section. 144 The section string may be anywhere within a line. 145 146 Arguments: 147 148 InputFile Memory file image. 149 Section Section to search for 150 151 Returns: 152 153 FALSE if error or EOF 154 TRUE if section found 155 156 --*/ 157 { 158 CHAR8 InputBuffer[_MAX_PATH]; 159 CHAR8 *CurrentToken; 160 161 // 162 // Verify input is not NULL 163 // 164 assert (InputFile->FileImage); 165 assert (InputFile->Eof); 166 assert (InputFile->CurrentFilePointer); 167 assert (Section); 168 169 // 170 // Rewind to beginning of file 171 // 172 InputFile->CurrentFilePointer = InputFile->FileImage; 173 174 // 175 // Read lines until the section is found 176 // 177 while (InputFile->CurrentFilePointer < InputFile->Eof) { 178 // 179 // Read a line 180 // 181 ReadLine (InputFile, InputBuffer, _MAX_PATH); 182 183 // 184 // Check if the section is found 185 // 186 CurrentToken = strstr (InputBuffer, Section); 187 if (CurrentToken != NULL) { 188 return TRUE; 189 } 190 } 191 192 return FALSE; 193 } 194 195 EFI_STATUS 196 FindToken ( 197 IN MEMORY_FILE *InputFile, 198 IN CHAR8 *Section, 199 IN CHAR8 *Token, 200 IN UINTN Instance, 201 OUT CHAR8 *Value 202 ) 203 /*++ 204 205 Routine Description: 206 207 Finds a token value given the section and token to search for. 208 209 Arguments: 210 211 InputFile Memory file image. 212 Section The section to search for, a string within []. 213 Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. 214 Instance The instance of the token to search for. Zero is the first instance. 215 Value The string that holds the value following the =. Must be _MAX_PATH in size. 216 217 Returns: 218 219 EFI_SUCCESS Value found. 220 EFI_ABORTED Format error detected in INF file. 221 EFI_INVALID_PARAMETER Input argument was null. 222 EFI_LOAD_ERROR Error reading from the file. 223 EFI_NOT_FOUND Section/Token/Value not found. 224 225 --*/ 226 { 227 CHAR8 InputBuffer[_MAX_PATH]; 228 CHAR8 *CurrentToken; 229 BOOLEAN ParseError; 230 BOOLEAN ReadError; 231 UINTN Occurrance; 232 233 // 234 // Check input parameters 235 // 236 if (InputFile->FileImage == NULL || 237 InputFile->Eof == NULL || 238 InputFile->CurrentFilePointer == NULL || 239 Section == NULL || 240 strlen (Section) == 0 || 241 Token == NULL || 242 strlen (Token) == 0 || 243 Value == NULL 244 ) { 245 return EFI_INVALID_PARAMETER; 246 } 247 // 248 // Initialize error codes 249 // 250 ParseError = FALSE; 251 ReadError = FALSE; 252 253 // 254 // Initialize our instance counter for the search token 255 // 256 Occurrance = 0; 257 258 if (FindSection (InputFile, Section)) { 259 // 260 // Found the desired section, find and read the desired token 261 // 262 do { 263 // 264 // Read a line from the file 265 // 266 if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) { 267 // 268 // Error reading from input file 269 // 270 ReadError = TRUE; 271 break; 272 } 273 // 274 // Get the first non-whitespace string 275 // 276 CurrentToken = strtok (InputBuffer, " \t\n"); 277 if (CurrentToken == NULL) { 278 // 279 // Whitespace line found (or comment) so continue 280 // 281 CurrentToken = InputBuffer; 282 continue; 283 } 284 // 285 // Make sure we have not reached the end of the current section 286 // 287 if (CurrentToken[0] == '[') { 288 break; 289 } 290 // 291 // Compare the current token with the desired token 292 // 293 if (strcmp (CurrentToken, Token) == 0) { 294 // 295 // Found it 296 // 297 // 298 // Check if it is the correct instance 299 // 300 if (Instance == Occurrance) { 301 // 302 // Copy the contents following the = 303 // 304 CurrentToken = strtok (NULL, "= \t\n"); 305 if (CurrentToken == NULL) { 306 // 307 // Nothing found, parsing error 308 // 309 ParseError = TRUE; 310 } else { 311 // 312 // Copy the current token to the output value 313 // 314 strcpy (Value, CurrentToken); 315 return EFI_SUCCESS; 316 } 317 } else { 318 // 319 // Increment the occurrance found 320 // 321 Occurrance++; 322 } 323 } 324 } while ( 325 !ParseError && 326 !ReadError && 327 InputFile->CurrentFilePointer < InputFile->Eof && 328 CurrentToken[0] != '[' && 329 Occurrance <= Instance 330 ); 331 } 332 // 333 // Distinguish between read errors and INF file format errors. 334 // 335 if (ReadError) { 336 return EFI_LOAD_ERROR; 337 } 338 339 if (ParseError) { 340 return EFI_ABORTED; 341 } 342 343 return EFI_NOT_FOUND; 344 } 345 346 EFI_STATUS 347 FindTokenInstanceInSection ( 348 IN MEMORY_FILE *InputFile, 349 IN CHAR8 *Section, 350 IN UINTN Instance, 351 OUT CHAR8 *Token, 352 OUT CHAR8 *Value 353 ) 354 /*++ 355 356 Routine Description: 357 358 Finds the Instance-th token in a section. 359 360 Arguments: 361 362 InputFile Memory file image. 363 Section The section to search for, a string within []. 364 Instance Specify the Instance-th token to search for, starting from zero 365 Token The token name to return. Caller should allocate the buffer. 366 Must be _MAX_PATH in size. 367 Value The token value to return. Caller should allocate the buffer. 368 Must be _MAX_PATH in size. 369 370 Returns: 371 372 EFI_SUCCESS Token and Value found. 373 EFI_ABORTED Format error detected in INF file. 374 EFI_INVALID_PARAMETER Input argument was null. 375 EFI_LOAD_ERROR Error reading from the file. 376 EFI_NOT_FOUND Section/Token/Value not found. 377 378 --*/ 379 { 380 CHAR8 InputBuffer[_MAX_PATH]; 381 CHAR8 *CurrentToken; 382 CHAR8 *CurrentValue; 383 BOOLEAN ParseError; 384 BOOLEAN ReadError; 385 UINTN InstanceIndex; 386 387 // 388 // Check input parameters 389 // 390 if (InputFile->FileImage == NULL || 391 InputFile->Eof == NULL || 392 InputFile->CurrentFilePointer == NULL || 393 Section == NULL || 394 strlen (Section) == 0 || 395 Value == NULL 396 ) { 397 return EFI_INVALID_PARAMETER; 398 } 399 // 400 // Initialize error codes 401 // 402 ParseError = FALSE; 403 ReadError = FALSE; 404 405 // 406 // Initialize our instance counter for the search token 407 // 408 InstanceIndex = 0; 409 410 if (FindSection (InputFile, Section)) { 411 // 412 // Found the desired section, find and read the desired token 413 // 414 do { 415 // 416 // Read a line from the file 417 // 418 if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) { 419 // 420 // Error reading from input file 421 // 422 ReadError = TRUE; 423 break; 424 } 425 // 426 // Get the first non-whitespace string 427 // 428 CurrentToken = strtok (InputBuffer, " \t\n"); 429 if (CurrentToken == NULL) { 430 // 431 // Whitespace line found (or comment) so continue 432 // 433 CurrentToken = InputBuffer; 434 continue; 435 } 436 // 437 // Make sure we have not reached the end of the current section 438 // 439 if (CurrentToken[0] == '[') { 440 break; 441 } 442 // 443 // Check if it is the correct instance 444 // 445 if (Instance == InstanceIndex) { 446 // 447 // Copy the contents following the = 448 // 449 CurrentValue = strtok (NULL, "= \t\n"); 450 if (CurrentValue == NULL) { 451 // 452 // Nothing found, parsing error 453 // 454 ParseError = TRUE; 455 } else { 456 // 457 // Copy the current token to the output value 458 // 459 strcpy (Token, CurrentToken); 460 strcpy (Value, CurrentValue); 461 return EFI_SUCCESS; 462 } 463 } else { 464 // 465 // Increment the occurrance found 466 // 467 InstanceIndex++; 468 } 469 } while ( 470 !ParseError && 471 !ReadError && 472 InputFile->CurrentFilePointer < InputFile->Eof && 473 CurrentToken[0] != '[' && 474 InstanceIndex <= Instance 475 ); 476 } 477 // 478 // Distinguish between read errors and INF file format errors. 479 // 480 if (ReadError) { 481 return EFI_LOAD_ERROR; 482 } 483 484 if (ParseError) { 485 return EFI_ABORTED; 486 } 487 488 return EFI_NOT_FOUND; 489 } 490 491 492 EFI_STATUS 493 StringToGuid ( 494 IN CHAR8 *AsciiGuidBuffer, 495 OUT EFI_GUID *GuidBuffer 496 ) 497 /*++ 498 499 Routine Description: 500 501 Converts a string to an EFI_GUID. The string must be in the 502 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. 503 504 Arguments: 505 506 AsciiGuidBuffer - pointer to ascii string 507 GuidBuffer - pointer to destination Guid 508 509 Returns: 510 511 EFI_ABORTED Could not convert the string 512 EFI_SUCCESS The string was successfully converted 513 EFI_INVALID_PARAMETER Input parameter is invalid. 514 515 --*/ 516 { 517 INT32 Index; 518 UINTN Data1; 519 UINTN Data2; 520 UINTN Data3; 521 UINTN Data4[8]; 522 523 if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) { 524 return EFI_INVALID_PARAMETER; 525 } 526 // 527 // Scan the guid string into the buffer 528 // 529 Index = sscanf ( 530 AsciiGuidBuffer, 531 "%08x-%04x-%04x-%02x%02x-%02hx%02hx%02hx%02hx%02hx%02hx", 532 &Data1, 533 &Data2, 534 &Data3, 535 &Data4[0], 536 &Data4[1], 537 &Data4[2], 538 &Data4[3], 539 &Data4[4], 540 &Data4[5], 541 &Data4[6], 542 &Data4[7] 543 ); 544 545 // 546 // Verify the correct number of items were scanned. 547 // 548 if (Index != 11) { 549 printf ("ERROR: Malformed GUID \"%s\".\n\n", AsciiGuidBuffer); 550 return EFI_ABORTED; 551 } 552 // 553 // Copy the data into our GUID. 554 // 555 GuidBuffer->Data1 = (UINT32) Data1; 556 GuidBuffer->Data2 = (UINT16) Data2; 557 GuidBuffer->Data3 = (UINT16) Data3; 558 GuidBuffer->Data4[0] = (UINT8) Data4[0]; 559 GuidBuffer->Data4[1] = (UINT8) Data4[1]; 560 GuidBuffer->Data4[2] = (UINT8) Data4[2]; 561 GuidBuffer->Data4[3] = (UINT8) Data4[3]; 562 GuidBuffer->Data4[4] = (UINT8) Data4[4]; 563 GuidBuffer->Data4[5] = (UINT8) Data4[5]; 564 GuidBuffer->Data4[6] = (UINT8) Data4[6]; 565 GuidBuffer->Data4[7] = (UINT8) Data4[7]; 566 567 return EFI_SUCCESS; 568 } 569 570 EFI_STATUS 571 AsciiStringToUint64 ( 572 IN CONST CHAR8 *AsciiString, 573 IN BOOLEAN IsHex, 574 OUT UINT64 *ReturnValue 575 ) 576 /*++ 577 578 Routine Description: 579 580 Converts a null terminated ascii string that represents a number into a 581 UINT64 value. A hex number may be preceeded by a 0x, but may not be 582 succeeded by an h. A number without 0x or 0X is considered to be base 10 583 unless the IsHex input is true. 584 585 Arguments: 586 587 AsciiString The string to convert. 588 IsHex Force the string to be treated as a hex number. 589 ReturnValue The return value. 590 591 Returns: 592 593 EFI_SUCCESS Number successfully converted. 594 EFI_ABORTED Invalid character encountered. 595 596 --*/ 597 { 598 UINT8 Index; 599 UINT64 HexNumber; 600 CHAR8 CurrentChar; 601 602 // 603 // Initialize the result 604 // 605 HexNumber = 0; 606 607 // 608 // Add each character to the result 609 // 610 if (IsHex || (AsciiString[0] == '0' && (AsciiString[1] == 'x' || AsciiString[1] == 'X'))) { 611 // 612 // Verify string is a hex number 613 // 614 for (Index = 2; Index < strlen (AsciiString); Index++) { 615 if (isxdigit (AsciiString[Index]) == 0) { 616 return EFI_ABORTED; 617 } 618 } 619 // 620 // Convert the hex string. 621 // 622 for (Index = 2; AsciiString[Index] != '\0'; Index++) { 623 CurrentChar = AsciiString[Index]; 624 HexNumber *= 16; 625 if (CurrentChar >= '0' && CurrentChar <= '9') { 626 HexNumber += CurrentChar - '0'; 627 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') { 628 HexNumber += CurrentChar - 'a' + 10; 629 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') { 630 HexNumber += CurrentChar - 'A' + 10; 631 } else { 632 // 633 // Unrecognized character 634 // 635 return EFI_ABORTED; 636 } 637 } 638 639 *ReturnValue = HexNumber; 640 } else { 641 // 642 // Verify string is a number 643 // 644 for (Index = 0; Index < strlen (AsciiString); Index++) { 645 if (isdigit (AsciiString[Index]) == 0) { 646 return EFI_ABORTED; 647 } 648 } 649 650 *ReturnValue = atol (AsciiString); 651 } 652 653 return EFI_SUCCESS; 654 }; 655 656 CHAR8 * 657 ReadLineInStream ( 658 IN FILE *InputFile, 659 IN OUT CHAR8 *InputBuffer 660 ) 661 /*++ 662 663 Routine Description: 664 665 This function reads a line, stripping any comments. 666 // BUGBUG: This is obsolete once genmake goes away... 667 668 Arguments: 669 670 InputFile Stream pointer. 671 InputBuffer Buffer to read into, must be _MAX_PATH size. 672 673 Returns: 674 675 NULL if error or EOF 676 InputBuffer otherwise 677 678 --*/ 679 { 680 CHAR8 *CharPtr; 681 682 // 683 // Verify input parameters are not null 684 // 685 assert (InputFile); 686 assert (InputBuffer); 687 688 // 689 // Read a line 690 // 691 if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) { 692 return NULL; 693 } 694 // 695 // Strip any comments 696 // 697 CharPtr = strstr (InputBuffer, "//"); 698 if (CharPtr != 0) { 699 CharPtr[0] = 0; 700 } 701 702 CharPtr = strstr (InputBuffer, "#"); 703 if (CharPtr != 0) { 704 CharPtr[0] = 0; 705 } 706 // 707 // Return the string 708 // 709 return InputBuffer; 710 } 711 712 BOOLEAN 713 FindSectionInStream ( 714 IN FILE *InputFile, 715 IN CHAR8 *Section 716 ) 717 /*++ 718 719 Routine Description: 720 721 This function parses a stream file from the beginning to find a section. 722 The section string may be anywhere within a line. 723 // BUGBUG: This is obsolete once genmake goes away... 724 725 Arguments: 726 727 InputFile Stream pointer. 728 Section Section to search for 729 730 Returns: 731 732 FALSE if error or EOF 733 TRUE if section found 734 735 --*/ 736 { 737 CHAR8 InputBuffer[_MAX_PATH]; 738 CHAR8 *CurrentToken; 739 740 // 741 // Verify input is not NULL 742 // 743 assert (InputFile); 744 assert (Section); 745 746 // 747 // Rewind to beginning of file 748 // 749 if (fseek (InputFile, 0, SEEK_SET) != 0) { 750 return FALSE; 751 } 752 // 753 // Read lines until the section is found 754 // 755 while (feof (InputFile) == 0) { 756 // 757 // Read a line 758 // 759 ReadLineInStream (InputFile, InputBuffer); 760 761 // 762 // Check if the section is found 763 // 764 CurrentToken = strstr (InputBuffer, Section); 765 if (CurrentToken != NULL) { 766 return TRUE; 767 } 768 } 769 770 return FALSE; 771 } 772