1 /* 2 * PROJECT: FreeLoader 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: INF file parser that caches contents of INF file in memory. 5 * COPYRIGHT: Copyright 2002-2006 Royce Mitchell III 6 * Copyright 2003-2019 Eric Kohl 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <freeldr.h> 12 #include "inffile.h" 13 14 #define CONTROL_Z '\x1a' 15 #define MAX_SECTION_NAME_LEN 255 16 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ 17 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ 18 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) 19 20 #define TAG_INF_KEY 'KfnI' 21 #define TAG_INF_FIELD 'ffnI' 22 #define TAG_INF_LINE 'LfnI' 23 #define TAG_INF_SECTION 'SfnI' 24 #define TAG_INF_CACHE 'CfnI' 25 #define TAG_INF_FILE 'FfnI' 26 27 typedef struct _INFCACHEFIELD 28 { 29 struct _INFCACHEFIELD *Next; 30 struct _INFCACHEFIELD *Prev; 31 32 CHAR Data[1]; 33 } INFCACHEFIELD, *PINFCACHEFIELD; 34 35 typedef struct _INFCACHELINE 36 { 37 struct _INFCACHELINE *Next; 38 struct _INFCACHELINE *Prev; 39 40 ULONG FieldCount; 41 42 PCHAR Key; 43 44 PINFCACHEFIELD FirstField; 45 PINFCACHEFIELD LastField; 46 47 } INFCACHELINE, *PINFCACHELINE; 48 49 typedef struct _INFCACHESECTION 50 { 51 struct _INFCACHESECTION *Next; 52 struct _INFCACHESECTION *Prev; 53 54 PINFCACHELINE FirstLine; 55 PINFCACHELINE LastLine; 56 57 LONG LineCount; 58 59 CHAR Name[1]; 60 } INFCACHESECTION, *PINFCACHESECTION; 61 62 typedef struct _INFCACHE 63 { 64 PINFCACHESECTION FirstSection; 65 PINFCACHESECTION LastSection; 66 67 PINFCACHESECTION StringsSection; 68 } INFCACHE, *PINFCACHE; 69 70 /* parser definitions */ 71 enum parser_state 72 { 73 LINE_START, /* at beginning of a line */ 74 SECTION_NAME, /* parsing a section name */ 75 KEY_NAME, /* parsing a key name */ 76 VALUE_NAME, /* parsing a value name */ 77 EOL_BACKSLASH, /* backslash at end of line */ 78 QUOTES, /* inside quotes */ 79 LEADING_SPACES, /* leading spaces */ 80 TRAILING_SPACES, /* trailing spaces */ 81 COMMENT, /* inside a comment */ 82 NB_PARSER_STATES 83 }; 84 85 struct parser 86 { 87 const CHAR *start; /* start position of item being parsed */ 88 const CHAR *end; /* end of buffer */ 89 PINFCACHE file; /* file being built */ 90 enum parser_state state; /* current parser state */ 91 enum parser_state stack[4]; /* state stack */ 92 int stack_pos; /* current pos in stack */ 93 94 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/ 95 PINFCACHELINE line; /* current line */ 96 unsigned int line_pos; /* current line position in file */ 97 unsigned int error; /* error code */ 98 unsigned int token_len; /* current token len */ 99 CHAR token[MAX_FIELD_LEN + 1]; /* current token */ 100 }; 101 102 typedef const CHAR * (*parser_state_func)(struct parser *parser, const CHAR *pos); 103 104 /* parser state machine functions */ 105 static const CHAR *line_start_state(struct parser *parser, const CHAR *pos); 106 static const CHAR *section_name_state(struct parser *parser, const CHAR *pos); 107 static const CHAR *key_name_state(struct parser *parser, const CHAR *pos); 108 static const CHAR *value_name_state(struct parser *parser, const CHAR *pos); 109 static const CHAR *eol_backslash_state(struct parser *parser, const CHAR *pos); 110 static const CHAR *quotes_state(struct parser *parser, const CHAR *pos); 111 static const CHAR *leading_spaces_state(struct parser *parser, const CHAR *pos); 112 static const CHAR *trailing_spaces_state(struct parser *parser, const CHAR *pos); 113 static const CHAR *comment_state(struct parser *parser, const CHAR *pos); 114 115 static 116 const parser_state_func 117 parser_funcs[NB_PARSER_STATES] = 118 { 119 line_start_state, /* LINE_START */ 120 section_name_state, /* SECTION_NAME */ 121 key_name_state, /* KEY_NAME */ 122 value_name_state, /* VALUE_NAME */ 123 eol_backslash_state, /* EOL_BACKSLASH */ 124 quotes_state, /* QUOTES */ 125 leading_spaces_state, /* LEADING_SPACES */ 126 trailing_spaces_state, /* TRAILING_SPACES */ 127 comment_state /* COMMENT */ 128 }; 129 130 131 /* PRIVATE FUNCTIONS ********************************************************/ 132 133 static 134 PINFCACHELINE 135 InfpCacheFreeLine( 136 PINFCACHELINE Line) 137 { 138 PINFCACHELINE Next; 139 PINFCACHEFIELD Field; 140 141 if (Line == NULL) 142 { 143 return NULL; 144 } 145 146 Next = Line->Next; 147 if (Line->Key != NULL) 148 { 149 FrLdrTempFree(Line->Key, TAG_INF_KEY); 150 Line->Key = NULL; 151 } 152 153 /* Remove data fields */ 154 while (Line->FirstField != NULL) 155 { 156 Field = Line->FirstField->Next; 157 FrLdrTempFree(Line->FirstField, TAG_INF_FIELD); 158 Line->FirstField = Field; 159 } 160 Line->LastField = NULL; 161 162 FrLdrTempFree(Line, TAG_INF_LINE); 163 164 return Next; 165 } 166 167 168 static 169 PINFCACHESECTION 170 InfpCacheFreeSection( 171 PINFCACHESECTION Section) 172 { 173 PINFCACHESECTION Next; 174 175 if (Section == NULL) 176 { 177 return NULL; 178 } 179 180 /* Release all keys */ 181 Next = Section->Next; 182 while (Section->FirstLine != NULL) 183 { 184 Section->FirstLine = InfpCacheFreeLine(Section->FirstLine); 185 } 186 Section->LastLine = NULL; 187 188 FrLdrTempFree(Section, TAG_INF_SECTION); 189 190 return Next; 191 } 192 193 194 static 195 PINFCACHESECTION 196 InfpCacheFindSection( 197 PINFCACHE Cache, 198 PCSTR Name) 199 { 200 PINFCACHESECTION Section = NULL; 201 202 if (Cache == NULL || Name == NULL) 203 { 204 return NULL; 205 } 206 207 /* iterate through list of sections */ 208 Section = Cache->FirstSection; 209 while (Section != NULL) 210 { 211 if (_stricmp(Section->Name, Name) == 0) 212 { 213 return Section; 214 } 215 216 /* get the next section*/ 217 Section = Section->Next; 218 } 219 220 return NULL; 221 } 222 223 224 static 225 PINFCACHESECTION 226 InfpCacheAddSection( 227 PINFCACHE Cache, 228 PCHAR Name) 229 { 230 PINFCACHESECTION Section = NULL; 231 SIZE_T Size; 232 233 if ((Cache == NULL) || (Name == NULL)) 234 { 235 // DPRINT("Invalid parameter\n"); 236 return NULL; 237 } 238 239 /* Allocate and initialize the new section */ 240 Size = sizeof(INFCACHESECTION) + strlen(Name); 241 Section = (PINFCACHESECTION)FrLdrTempAlloc(Size, TAG_INF_SECTION); 242 if (Section == NULL) 243 { 244 // DPRINT("RtlAllocateHeap() failed\n"); 245 return NULL; 246 } 247 memset(Section, 0, Size); 248 249 /* Copy section name */ 250 strcpy(Section->Name, Name); 251 252 /* Append section */ 253 if (Cache->FirstSection == NULL) 254 { 255 Cache->FirstSection = Section; 256 Cache->LastSection = Section; 257 } 258 else 259 { 260 Cache->LastSection->Next = Section; 261 Section->Prev = Cache->LastSection; 262 Cache->LastSection = Section; 263 } 264 265 return Section; 266 } 267 268 269 static 270 PINFCACHELINE 271 InfpCacheAddLine(PINFCACHESECTION Section) 272 { 273 PINFCACHELINE Line; 274 275 if (Section == NULL) 276 { 277 // DPRINT("Invalid parameter\n"); 278 return NULL; 279 } 280 281 Line = (PINFCACHELINE)FrLdrTempAlloc(sizeof(INFCACHELINE), TAG_INF_LINE); 282 if (Line == NULL) 283 { 284 // DPRINT("RtlAllocateHeap() failed\n"); 285 return NULL; 286 } 287 memset(Line, 0, sizeof(INFCACHELINE)); 288 289 /* Append line */ 290 if (Section->FirstLine == NULL) 291 { 292 Section->FirstLine = Line; 293 Section->LastLine = Line; 294 } 295 else 296 { 297 Section->LastLine->Next = Line; 298 Line->Prev = Section->LastLine; 299 Section->LastLine = Line; 300 } 301 Section->LineCount++; 302 303 return Line; 304 } 305 306 307 static 308 PVOID 309 InfpAddKeyToLine( 310 PINFCACHELINE Line, 311 PCHAR Key) 312 { 313 if (Line == NULL) 314 return NULL; 315 316 if (Line->Key != NULL) 317 return NULL; 318 319 Line->Key = FrLdrTempAlloc(strlen(Key) + 1, TAG_INF_KEY); 320 if (Line->Key == NULL) 321 return NULL; 322 323 strcpy(Line->Key, Key); 324 325 return (PVOID)Line->Key; 326 } 327 328 329 static 330 PVOID 331 InfpAddFieldToLine( 332 PINFCACHELINE Line, 333 PCHAR Data) 334 { 335 PINFCACHEFIELD Field; 336 SIZE_T Size; 337 338 Size = sizeof(INFCACHEFIELD) + strlen(Data); 339 Field = (PINFCACHEFIELD)FrLdrTempAlloc(Size, TAG_INF_FIELD); 340 if (Field == NULL) 341 { 342 return NULL; 343 } 344 memset(Field, 0, Size); 345 346 strcpy(Field->Data, Data); 347 348 /* Append key */ 349 if (Line->FirstField == NULL) 350 { 351 Line->FirstField = Field; 352 Line->LastField = Field; 353 } 354 else 355 { 356 Line->LastField->Next = Field; 357 Field->Prev = Line->LastField; 358 Line->LastField = Field; 359 } 360 Line->FieldCount++; 361 362 return (PVOID)Field; 363 } 364 365 366 static 367 PINFCACHELINE 368 InfpCacheFindKeyLine( 369 PINFCACHESECTION Section, 370 PCSTR Key) 371 { 372 PINFCACHELINE Line; 373 374 Line = Section->FirstLine; 375 while (Line != NULL) 376 { 377 if ((Line->Key != NULL) && (_stricmp(Line->Key, Key) == 0)) 378 { 379 return Line; 380 } 381 382 Line = Line->Next; 383 } 384 385 return NULL; 386 } 387 388 389 /* push the current state on the parser stack */ 390 __inline static void push_state(struct parser *parser, enum parser_state state) 391 { 392 // assert(parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0])); 393 parser->stack[parser->stack_pos++] = state; 394 } 395 396 397 /* pop the current state */ 398 __inline static void pop_state(struct parser *parser) 399 { 400 // assert( parser->stack_pos ); 401 parser->state = parser->stack[--parser->stack_pos]; 402 } 403 404 405 /* set the parser state and return the previous one */ 406 __inline static enum parser_state set_state(struct parser *parser, enum parser_state state) 407 { 408 enum parser_state ret = parser->state; 409 parser->state = state; 410 return ret; 411 } 412 413 414 /* check if the pointer points to an end of file */ 415 __inline static int is_eof(struct parser *parser, const CHAR *ptr) 416 { 417 return (ptr >= parser->end || *ptr == CONTROL_Z); 418 } 419 420 421 /* check if the pointer points to an end of line */ 422 __inline static int is_eol(struct parser *parser, const CHAR *ptr) 423 { 424 return ((ptr >= parser->end) || 425 (*ptr == CONTROL_Z) || 426 (*ptr == '\n') || 427 ((*ptr == '\r') && (*(ptr + 1) == '\n'))); 428 } 429 430 431 /* push data from current token start up to pos into the current token */ 432 static 433 int 434 push_token( 435 struct parser *parser, 436 const CHAR *pos) 437 { 438 SIZE_T len = pos - parser->start; 439 const CHAR *src = parser->start; 440 CHAR *dst = parser->token + parser->token_len; 441 442 if (len > MAX_FIELD_LEN - parser->token_len) 443 len = MAX_FIELD_LEN - parser->token_len; 444 445 parser->token_len += (ULONG)len; 446 for ( ; len > 0; len--, dst++, src++) 447 *dst = *src ? (CHAR)*src : L' '; 448 *dst = 0; 449 parser->start = pos; 450 451 return 0; 452 } 453 454 455 /* add a section with the current token as name */ 456 static 457 PVOID 458 add_section_from_token(struct parser *parser) 459 { 460 PINFCACHESECTION Section; 461 462 if (parser->token_len > MAX_SECTION_NAME_LEN) 463 { 464 parser->error = FALSE; 465 return NULL; 466 } 467 468 Section = InfpCacheFindSection(parser->file, parser->token); 469 if (Section == NULL) 470 { 471 /* need to create a new one */ 472 Section = InfpCacheAddSection(parser->file, parser->token); 473 if (Section == NULL) 474 { 475 parser->error = FALSE; 476 return NULL; 477 } 478 } 479 480 parser->token_len = 0; 481 parser->cur_section = Section; 482 483 return (PVOID)Section; 484 } 485 486 487 /* add a field containing the current token to the current line */ 488 static 489 struct field* 490 add_field_from_token( 491 struct parser *parser, 492 int is_key) 493 { 494 PVOID field; 495 496 if (!parser->line) /* need to start a new line */ 497 { 498 if (parser->cur_section == NULL) /* got a line before the first section */ 499 { 500 parser->error = STATUS_WRONG_INF_STYLE; 501 return NULL; 502 } 503 504 parser->line = InfpCacheAddLine(parser->cur_section); 505 if (parser->line == NULL) 506 goto error; 507 } 508 else 509 { 510 // assert(!is_key); 511 } 512 513 if (is_key) 514 { 515 field = InfpAddKeyToLine(parser->line, parser->token); 516 } 517 else 518 { 519 field = InfpAddFieldToLine(parser->line, parser->token); 520 } 521 522 if (field != NULL) 523 { 524 parser->token_len = 0; 525 return field; 526 } 527 528 error: 529 parser->error = FALSE; 530 return NULL; 531 } 532 533 534 /* close the current line and prepare for parsing a new one */ 535 static 536 VOID 537 close_current_line(struct parser *parser) 538 { 539 parser->line = NULL; 540 } 541 542 543 /* handler for parser LINE_START state */ 544 static 545 const CHAR* 546 line_start_state( 547 struct parser *parser, 548 const CHAR *pos) 549 { 550 const CHAR *p; 551 552 for (p = pos; !is_eof(parser, p); p++) 553 { 554 switch(*p) 555 { 556 case '\r': 557 continue; 558 559 case '\n': 560 parser->line_pos++; 561 close_current_line(parser); 562 break; 563 564 case ';': 565 push_state(parser, LINE_START); 566 set_state(parser, COMMENT); 567 return p + 1; 568 569 case '[': 570 parser->start = p + 1; 571 set_state(parser, SECTION_NAME); 572 return p + 1; 573 574 default: 575 if (!isspace((unsigned char)*p)) 576 { 577 parser->start = p; 578 set_state(parser, KEY_NAME); 579 return p; 580 } 581 break; 582 } 583 } 584 close_current_line(parser); 585 return NULL; 586 } 587 588 589 /* handler for parser SECTION_NAME state */ 590 static 591 const CHAR* 592 section_name_state( 593 struct parser *parser, 594 const CHAR *pos) 595 { 596 const CHAR *p; 597 598 for (p = pos; !is_eol(parser, p); p++) 599 { 600 if (*p == ']') 601 { 602 push_token(parser, p); 603 if (add_section_from_token(parser) == NULL) 604 return NULL; 605 push_state(parser, LINE_START); 606 set_state(parser, COMMENT); /* ignore everything else on the line */ 607 return p + 1; 608 } 609 } 610 parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */ 611 return NULL; 612 } 613 614 615 /* handler for parser KEY_NAME state */ 616 static 617 const CHAR* 618 key_name_state( 619 struct parser *parser, 620 const CHAR *pos) 621 { 622 const CHAR *p, *token_end = parser->start; 623 624 for (p = pos; !is_eol(parser, p); p++) 625 { 626 if (*p == ',') break; 627 switch(*p) 628 { 629 630 case '=': 631 push_token(parser, token_end); 632 if (!add_field_from_token(parser, 1)) return NULL; 633 parser->start = p + 1; 634 push_state(parser, VALUE_NAME); 635 set_state(parser, LEADING_SPACES); 636 return p + 1; 637 case ';': 638 push_token(parser, token_end); 639 if (!add_field_from_token(parser, 0)) return NULL; 640 push_state(parser, LINE_START); 641 set_state(parser, COMMENT); 642 return p + 1; 643 case '"': 644 push_token(parser, token_end); 645 parser->start = p + 1; 646 push_state(parser, KEY_NAME); 647 set_state(parser, QUOTES); 648 return p + 1; 649 case '\\': 650 push_token(parser, token_end); 651 parser->start = p; 652 push_state(parser, KEY_NAME); 653 set_state(parser, EOL_BACKSLASH); 654 return p; 655 default: 656 if (!isspace((unsigned char)*p)) token_end = p + 1; 657 else 658 { 659 push_token(parser, p); 660 push_state(parser, KEY_NAME); 661 set_state(parser, TRAILING_SPACES); 662 return p; 663 } 664 break; 665 } 666 } 667 push_token(parser, token_end); 668 set_state(parser, VALUE_NAME); 669 return p; 670 } 671 672 673 /* handler for parser VALUE_NAME state */ 674 static 675 const CHAR* 676 value_name_state( 677 struct parser *parser, 678 const CHAR *pos) 679 { 680 const CHAR *p, *token_end = parser->start; 681 682 for (p = pos; !is_eol(parser, p); p++) 683 { 684 switch(*p) 685 { 686 case ';': 687 push_token(parser, token_end); 688 if (!add_field_from_token(parser, 0)) return NULL; 689 push_state(parser, LINE_START); 690 set_state(parser, COMMENT); 691 return p + 1; 692 case ',': 693 push_token(parser, token_end); 694 if (!add_field_from_token(parser, 0)) return NULL; 695 parser->start = p + 1; 696 push_state(parser, VALUE_NAME); 697 set_state(parser, LEADING_SPACES); 698 return p + 1; 699 case '"': 700 push_token(parser, token_end); 701 parser->start = p + 1; 702 push_state(parser, VALUE_NAME); 703 set_state(parser, QUOTES); 704 return p + 1; 705 case '\\': 706 push_token(parser, token_end); 707 parser->start = p; 708 push_state(parser, VALUE_NAME); 709 set_state(parser, EOL_BACKSLASH); 710 return p; 711 default: 712 if (!isspace((unsigned char)*p)) token_end = p + 1; 713 else 714 { 715 push_token(parser, p); 716 push_state(parser, VALUE_NAME); 717 set_state(parser, TRAILING_SPACES); 718 return p; 719 } 720 break; 721 } 722 } 723 push_token(parser, token_end); 724 if (!add_field_from_token(parser, 0)) return NULL; 725 set_state(parser, LINE_START); 726 return p; 727 } 728 729 730 /* handler for parser EOL_BACKSLASH state */ 731 static 732 const CHAR* 733 eol_backslash_state( 734 struct parser *parser, 735 const CHAR *pos ) 736 { 737 const CHAR *p; 738 739 for (p = pos; !is_eof(parser, p); p++) 740 { 741 switch(*p) 742 { 743 case '\r': 744 continue; 745 746 case '\n': 747 parser->line_pos++; 748 parser->start = p + 1; 749 set_state(parser, LEADING_SPACES); 750 return p + 1; 751 752 case '\\': 753 continue; 754 755 case ';': 756 push_state(parser, EOL_BACKSLASH); 757 set_state(parser, COMMENT); 758 return p + 1; 759 760 default: 761 if (isspace((unsigned char)*p)) 762 continue; 763 push_token(parser, p); 764 pop_state(parser); 765 return p; 766 } 767 } 768 parser->start = p; 769 pop_state(parser); 770 771 return p; 772 } 773 774 775 /* handler for parser QUOTES state */ 776 static 777 const CHAR* 778 quotes_state( 779 struct parser *parser, 780 const CHAR *pos ) 781 { 782 const CHAR *p, *token_end = parser->start; 783 784 for (p = pos; !is_eol(parser, p); p++) 785 { 786 if (*p == '"') 787 { 788 if (p + 1 < parser->end && p[1] == '"') /* double quotes */ 789 { 790 push_token(parser, p + 1); 791 parser->start = token_end = p + 2; 792 p++; 793 } 794 else /* end of quotes */ 795 { 796 push_token(parser, p); 797 parser->start = p + 1; 798 pop_state(parser); 799 return p + 1; 800 } 801 } 802 } 803 push_token(parser, p); 804 pop_state(parser); 805 return p; 806 } 807 808 809 /* handler for parser LEADING_SPACES state */ 810 static 811 const CHAR* 812 leading_spaces_state( 813 struct parser *parser, 814 const CHAR *pos ) 815 { 816 const CHAR *p; 817 818 for (p = pos; !is_eol(parser, p); p++) 819 { 820 if (*p == '\\') 821 { 822 parser->start = p; 823 set_state(parser, EOL_BACKSLASH); 824 return p; 825 } 826 if (!isspace((unsigned char)*p)) 827 break; 828 } 829 parser->start = p; 830 pop_state(parser); 831 return p; 832 } 833 834 835 /* handler for parser TRAILING_SPACES state */ 836 static 837 const CHAR* 838 trailing_spaces_state( 839 struct parser *parser, 840 const CHAR *pos ) 841 { 842 const CHAR *p; 843 844 for (p = pos; !is_eol(parser, p); p++) 845 { 846 if (*p == '\\') 847 { 848 set_state(parser, EOL_BACKSLASH); 849 return p; 850 } 851 if (!isspace((unsigned char)*p)) 852 break; 853 } 854 pop_state(parser); 855 return p; 856 } 857 858 859 /* handler for parser COMMENT state */ 860 static 861 const CHAR* 862 comment_state( 863 struct parser *parser, 864 const CHAR *pos ) 865 { 866 const CHAR *p = pos; 867 868 while (!is_eol(parser, p)) 869 p++; 870 pop_state(parser); 871 return p; 872 } 873 874 875 /* parse a complete buffer */ 876 static 877 BOOLEAN 878 InfpParseBuffer ( 879 PINFCACHE file, 880 PCCHAR buffer, 881 PCCHAR end, 882 PULONG error_line) 883 { 884 struct parser parser; 885 const CHAR* pos = buffer; 886 887 parser.start = buffer; 888 parser.end = end; 889 parser.file = file; 890 parser.line = NULL; 891 parser.state = LINE_START; 892 parser.stack_pos = 0; 893 parser.cur_section = NULL; 894 parser.line_pos = 1; 895 parser.error = TRUE; 896 parser.token_len = 0; 897 898 /* parser main loop */ 899 while (pos) 900 pos = (parser_funcs[parser.state])(&parser, pos); 901 902 if (parser.error) 903 { 904 if (error_line) 905 *error_line = parser.line_pos; 906 return parser.error; 907 } 908 909 /* find the [strings] section */ 910 file->StringsSection = InfpCacheFindSection(file, "Strings"); 911 912 return TRUE; 913 } 914 915 /* PUBLIC FUNCTIONS *********************************************************/ 916 917 BOOLEAN 918 InfOpenFile( 919 PHINF InfHandle, 920 PCSTR FileName, 921 PULONG ErrorLine) 922 { 923 FILEINFORMATION Information; 924 ULONG FileId; 925 PCHAR FileBuffer; 926 ULONG FileSize, Count; 927 PINFCACHE Cache; 928 BOOLEAN Success; 929 ARC_STATUS Status; 930 931 *InfHandle = NULL; 932 *ErrorLine = (ULONG) - 1; 933 934 // 935 // Open the .inf file 936 // 937 Status = ArcOpen((PSTR)FileName, OpenReadOnly, &FileId); 938 if (Status != ESUCCESS) 939 { 940 return FALSE; 941 } 942 943 // 944 // Query file size 945 // 946 Status = ArcGetFileInformation(FileId, &Information); 947 if ((Status != ESUCCESS) || (Information.EndingAddress.HighPart != 0)) 948 { 949 ArcClose(FileId); 950 return FALSE; 951 } 952 FileSize = Information.EndingAddress.LowPart; 953 954 // 955 // Allocate buffer to cache the file 956 // 957 FileBuffer = FrLdrTempAlloc(FileSize + 1, TAG_INF_FILE); 958 if (!FileBuffer) 959 { 960 ArcClose(FileId); 961 return FALSE; 962 } 963 964 // 965 // Read file into memory 966 // 967 Status = ArcRead(FileId, FileBuffer, FileSize, &Count); 968 if ((Status != ESUCCESS) || (Count != FileSize)) 969 { 970 ArcClose(FileId); 971 FrLdrTempFree(FileBuffer, TAG_INF_FILE); 972 return FALSE; 973 } 974 975 // 976 // We don't need the file anymore. Close it 977 // 978 ArcClose(FileId); 979 980 // 981 // Append string terminator 982 // 983 FileBuffer[FileSize] = 0; 984 985 // 986 // Allocate infcache header 987 // 988 Cache = (PINFCACHE)FrLdrTempAlloc(sizeof(INFCACHE), TAG_INF_CACHE); 989 if (!Cache) 990 { 991 FrLdrTempFree(FileBuffer, TAG_INF_FILE); 992 return FALSE; 993 } 994 995 // 996 // Initialize inicache header 997 // 998 RtlZeroMemory(Cache, sizeof(INFCACHE)); 999 1000 // 1001 // Parse the inf buffer 1002 // 1003 Success = InfpParseBuffer(Cache, 1004 FileBuffer, 1005 FileBuffer + FileSize, 1006 ErrorLine); 1007 if (!Success) 1008 { 1009 FrLdrTempFree(Cache, TAG_INF_CACHE); 1010 Cache = NULL; 1011 } 1012 1013 // 1014 // Free file buffer, as it has been parsed 1015 // 1016 FrLdrTempFree(FileBuffer, TAG_INF_FILE); 1017 1018 // 1019 // Return .inf parsed contents 1020 // 1021 *InfHandle = (HINF)Cache; 1022 1023 return Success; 1024 } 1025 1026 1027 VOID 1028 InfCloseFile(HINF InfHandle) 1029 { 1030 PINFCACHE Cache; 1031 1032 Cache = (PINFCACHE)InfHandle; 1033 1034 if (Cache == NULL) 1035 { 1036 return; 1037 } 1038 1039 while (Cache->FirstSection != NULL) 1040 { 1041 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection); 1042 } 1043 Cache->LastSection = NULL; 1044 1045 FrLdrTempFree(Cache, TAG_INF_CACHE); 1046 } 1047 1048 1049 BOOLEAN 1050 InfFindFirstLine ( 1051 HINF InfHandle, 1052 PCSTR Section, 1053 PCSTR Key, 1054 PINFCONTEXT Context) 1055 { 1056 PINFCACHE Cache; 1057 PINFCACHESECTION CacheSection; 1058 PINFCACHELINE CacheLine; 1059 1060 if ((InfHandle == NULL) || (Section == NULL) || (Context == NULL)) 1061 { 1062 // DPRINT("Invalid parameter\n"); 1063 return FALSE; 1064 } 1065 1066 Cache = (PINFCACHE)InfHandle; 1067 1068 /* Iterate through list of sections */ 1069 CacheSection = Cache->FirstSection; 1070 while (CacheSection != NULL) 1071 { 1072 // DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section); 1073 1074 /* Are the section names the same? */ 1075 if (_stricmp(CacheSection->Name, Section) == 0) 1076 { 1077 if (Key != NULL) 1078 { 1079 CacheLine = InfpCacheFindKeyLine(CacheSection, Key); 1080 } 1081 else 1082 { 1083 CacheLine = CacheSection->FirstLine; 1084 } 1085 1086 if (CacheLine == NULL) 1087 return FALSE; 1088 1089 Context->Inf = (PVOID)Cache; 1090 Context->Section = (PVOID)CacheSection; 1091 Context->Line = (PVOID)CacheLine; 1092 1093 return TRUE; 1094 } 1095 1096 /* Get the next section */ 1097 CacheSection = CacheSection->Next; 1098 } 1099 1100 // DPRINT("Section not found\n"); 1101 1102 return FALSE; 1103 } 1104 1105 1106 BOOLEAN 1107 InfFindNextLine ( 1108 PINFCONTEXT ContextIn, 1109 PINFCONTEXT ContextOut) 1110 { 1111 PINFCACHELINE CacheLine; 1112 1113 if ((ContextIn == NULL) || (ContextOut == NULL)) 1114 return FALSE; 1115 1116 if (ContextIn->Line == NULL) 1117 return FALSE; 1118 1119 CacheLine = (PINFCACHELINE)ContextIn->Line; 1120 if (CacheLine->Next == NULL) 1121 return FALSE; 1122 1123 if (ContextIn != ContextOut) 1124 { 1125 ContextOut->Inf = ContextIn->Inf; 1126 ContextOut->Section = ContextIn->Section; 1127 } 1128 ContextOut->Line = (PVOID)(CacheLine->Next); 1129 1130 return TRUE; 1131 } 1132 1133 1134 BOOLEAN 1135 InfFindFirstMatchLine ( 1136 PINFCONTEXT ContextIn, 1137 PCHAR Key, 1138 PINFCONTEXT ContextOut) 1139 { 1140 PINFCACHELINE CacheLine; 1141 1142 if ((ContextIn == NULL) || (ContextOut == NULL) || (Key == NULL) || (*Key == 0)) 1143 return FALSE; 1144 1145 if (ContextIn->Inf == NULL || ContextIn->Section == NULL) 1146 return FALSE; 1147 1148 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine; 1149 while (CacheLine != NULL) 1150 { 1151 if ((CacheLine->Key != NULL) && (_stricmp(CacheLine->Key, Key) == 0)) 1152 { 1153 1154 if (ContextIn != ContextOut) 1155 { 1156 ContextOut->Inf = ContextIn->Inf; 1157 ContextOut->Section = ContextIn->Section; 1158 } 1159 ContextOut->Line = (PVOID)CacheLine; 1160 1161 return TRUE; 1162 } 1163 1164 CacheLine = CacheLine->Next; 1165 } 1166 1167 return FALSE; 1168 } 1169 1170 1171 BOOLEAN 1172 InfFindNextMatchLine ( 1173 PINFCONTEXT ContextIn, 1174 PCHAR Key, 1175 PINFCONTEXT ContextOut) 1176 { 1177 PINFCACHELINE CacheLine; 1178 1179 if ((ContextIn == NULL) || (ContextOut == NULL) || (Key == NULL) || (*Key == 0)) 1180 return FALSE; 1181 1182 if ((ContextIn->Inf == NULL) || (ContextIn->Section == NULL) || (ContextIn->Line == NULL)) 1183 return FALSE; 1184 1185 CacheLine = (PINFCACHELINE)ContextIn->Line; 1186 while (CacheLine != NULL) 1187 { 1188 if ((CacheLine->Key != NULL) && (_stricmp(CacheLine->Key, Key) == 0)) 1189 { 1190 1191 if (ContextIn != ContextOut) 1192 { 1193 ContextOut->Inf = ContextIn->Inf; 1194 ContextOut->Section = ContextIn->Section; 1195 } 1196 ContextOut->Line = (PVOID)CacheLine; 1197 1198 return TRUE; 1199 } 1200 1201 CacheLine = CacheLine->Next; 1202 } 1203 1204 return FALSE; 1205 } 1206 1207 1208 LONG 1209 InfGetLineCount( 1210 HINF InfHandle, 1211 PCHAR Section) 1212 { 1213 PINFCACHE Cache; 1214 PINFCACHESECTION CacheSection; 1215 1216 if ((InfHandle == NULL) || (Section == NULL)) 1217 { 1218 // DPRINT("Invalid parameter\n"); 1219 return -1; 1220 } 1221 1222 Cache = (PINFCACHE)InfHandle; 1223 1224 /* Iterate through list of sections */ 1225 CacheSection = Cache->FirstSection; 1226 while (CacheSection != NULL) 1227 { 1228 // DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section); 1229 1230 /* Are the section names the same? */ 1231 if (_stricmp(CacheSection->Name, Section) == 0) 1232 { 1233 return CacheSection->LineCount; 1234 } 1235 1236 /* Get the next section */ 1237 CacheSection = CacheSection->Next; 1238 } 1239 1240 // DPRINT("Section not found\n"); 1241 1242 return -1; 1243 } 1244 1245 1246 /* InfGetLineText */ 1247 1248 1249 LONG 1250 InfGetFieldCount(PINFCONTEXT Context) 1251 { 1252 if ((Context == NULL) || (Context->Line == NULL)) 1253 return 0; 1254 1255 return ((PINFCACHELINE)Context->Line)->FieldCount; 1256 } 1257 1258 1259 BOOLEAN 1260 InfGetBinaryField ( 1261 PINFCONTEXT Context, 1262 ULONG FieldIndex, 1263 PUCHAR ReturnBuffer, 1264 ULONG ReturnBufferSize, 1265 PULONG RequiredSize) 1266 { 1267 PINFCACHELINE CacheLine; 1268 PINFCACHEFIELD CacheField; 1269 ULONG Index; 1270 ULONG Size; 1271 PUCHAR Ptr; 1272 1273 if ((Context == NULL) || (Context->Line == NULL) || (FieldIndex == 0)) 1274 { 1275 // DPRINT("Invalid parameter\n"); 1276 return FALSE; 1277 } 1278 1279 if (RequiredSize != NULL) 1280 *RequiredSize = 0; 1281 1282 CacheLine = (PINFCACHELINE)Context->Line; 1283 1284 if (FieldIndex > CacheLine->FieldCount) 1285 return FALSE; 1286 1287 CacheField = CacheLine->FirstField; 1288 for (Index = 1; Index < FieldIndex; Index++) 1289 CacheField = CacheField->Next; 1290 1291 Size = CacheLine->FieldCount - FieldIndex + 1; 1292 1293 if (RequiredSize != NULL) 1294 *RequiredSize = Size; 1295 1296 if (ReturnBuffer != NULL) 1297 { 1298 if (ReturnBufferSize < Size) 1299 return FALSE; 1300 1301 /* Copy binary data */ 1302 Ptr = ReturnBuffer; 1303 while (CacheField != NULL) 1304 { 1305 *Ptr = (UCHAR)atoi(CacheField->Data); //strtoul(CacheField->Data, NULL, 16); 1306 1307 Ptr++; 1308 CacheField = CacheField->Next; 1309 } 1310 } 1311 1312 return TRUE; 1313 } 1314 1315 1316 BOOLEAN 1317 InfGetIntField ( 1318 PINFCONTEXT Context, 1319 ULONG FieldIndex, 1320 PLONG IntegerValue) 1321 { 1322 PINFCACHELINE CacheLine; 1323 PINFCACHEFIELD CacheField; 1324 ULONG Index; 1325 PCHAR Ptr; 1326 1327 if ((Context == NULL) || (Context->Line == NULL) || (IntegerValue == NULL)) 1328 { 1329 // DPRINT("Invalid parameter\n"); 1330 return FALSE; 1331 } 1332 1333 CacheLine = (PINFCACHELINE)Context->Line; 1334 1335 if (FieldIndex > CacheLine->FieldCount) 1336 { 1337 // DPRINT("Invalid parameter\n"); 1338 return FALSE; 1339 } 1340 1341 if (FieldIndex == 0) 1342 { 1343 Ptr = CacheLine->Key; 1344 } 1345 else 1346 { 1347 CacheField = CacheLine->FirstField; 1348 for (Index = 1; Index < FieldIndex; Index++) 1349 CacheField = CacheField->Next; 1350 1351 Ptr = CacheField->Data; 1352 } 1353 1354 *IntegerValue = atoi(Ptr); //strtol(Ptr, NULL, 0); 1355 1356 return TRUE; 1357 } 1358 1359 1360 BOOLEAN 1361 InfGetMultiSzField ( 1362 PINFCONTEXT Context, 1363 ULONG FieldIndex, 1364 PCHAR ReturnBuffer, 1365 ULONG ReturnBufferSize, 1366 PULONG RequiredSize) 1367 { 1368 PINFCACHELINE CacheLine; 1369 PINFCACHEFIELD CacheField; 1370 PINFCACHEFIELD FieldPtr; 1371 ULONG Index; 1372 SIZE_T Size; 1373 PCHAR Ptr; 1374 1375 if ((Context == NULL) || (Context->Line == NULL) || (FieldIndex == 0)) 1376 { 1377 // DPRINT("Invalid parameter\n"); 1378 return FALSE; 1379 } 1380 1381 if (RequiredSize != NULL) 1382 *RequiredSize = 0; 1383 1384 CacheLine = (PINFCACHELINE)Context->Line; 1385 1386 if (FieldIndex > CacheLine->FieldCount) 1387 return FALSE; 1388 1389 CacheField = CacheLine->FirstField; 1390 for (Index = 1; Index < FieldIndex; Index++) 1391 CacheField = CacheField->Next; 1392 1393 /* Calculate the required buffer size */ 1394 FieldPtr = CacheField; 1395 Size = 0; 1396 while (FieldPtr != NULL) 1397 { 1398 Size += (strlen(FieldPtr->Data) + 1); 1399 FieldPtr = FieldPtr->Next; 1400 } 1401 Size++; 1402 1403 if (RequiredSize != NULL) 1404 *RequiredSize = (ULONG)Size; 1405 1406 if (ReturnBuffer != NULL) 1407 { 1408 if (ReturnBufferSize < Size) 1409 return FALSE; 1410 1411 /* Copy multi-sz string */ 1412 Ptr = ReturnBuffer; 1413 FieldPtr = CacheField; 1414 while (FieldPtr != NULL) 1415 { 1416 Size = strlen(FieldPtr->Data) + 1; 1417 1418 strcpy(Ptr, FieldPtr->Data); 1419 1420 Ptr = Ptr + Size; 1421 FieldPtr = FieldPtr->Next; 1422 } 1423 *Ptr = 0; 1424 } 1425 1426 return TRUE; 1427 } 1428 1429 1430 BOOLEAN 1431 InfGetStringField ( 1432 PINFCONTEXT Context, 1433 ULONG FieldIndex, 1434 PCHAR ReturnBuffer, 1435 ULONG ReturnBufferSize, 1436 PULONG RequiredSize) 1437 { 1438 PINFCACHELINE CacheLine; 1439 PINFCACHEFIELD CacheField; 1440 ULONG Index; 1441 PCHAR Ptr; 1442 SIZE_T Size; 1443 1444 if ((Context == NULL) || (Context->Line == NULL)) 1445 { 1446 // DPRINT("Invalid parameter\n"); 1447 return FALSE; 1448 } 1449 1450 if (RequiredSize != NULL) 1451 *RequiredSize = 0; 1452 1453 CacheLine = (PINFCACHELINE)Context->Line; 1454 1455 if (FieldIndex > CacheLine->FieldCount) 1456 return FALSE; 1457 1458 if (FieldIndex == 0) 1459 { 1460 Ptr = CacheLine->Key; 1461 } 1462 else 1463 { 1464 CacheField = CacheLine->FirstField; 1465 for (Index = 1; Index < FieldIndex; Index++) 1466 CacheField = CacheField->Next; 1467 1468 Ptr = CacheField->Data; 1469 } 1470 1471 Size = strlen(Ptr) + 1; 1472 1473 if (RequiredSize != NULL) 1474 *RequiredSize = (ULONG)Size; 1475 1476 if (ReturnBuffer != NULL) 1477 { 1478 if (ReturnBufferSize < Size) 1479 return FALSE; 1480 1481 strcpy(ReturnBuffer, Ptr); 1482 } 1483 1484 return TRUE; 1485 } 1486 1487 1488 1489 1490 BOOLEAN 1491 InfGetData ( 1492 PINFCONTEXT Context, 1493 PCHAR *Key, 1494 PCHAR *Data) 1495 { 1496 PINFCACHELINE CacheKey; 1497 1498 if ((Context == NULL) || (Context->Line == NULL) || (Data == NULL)) 1499 { 1500 // DPRINT("Invalid parameter\n"); 1501 return FALSE; 1502 } 1503 1504 CacheKey = (PINFCACHELINE)Context->Line; 1505 if (Key != NULL) 1506 *Key = CacheKey->Key; 1507 1508 if (Data != NULL) 1509 { 1510 if (CacheKey->FirstField == NULL) 1511 { 1512 *Data = NULL; 1513 } 1514 else 1515 { 1516 *Data = CacheKey->FirstField->Data; 1517 } 1518 } 1519 1520 return TRUE; 1521 } 1522 1523 1524 BOOLEAN 1525 InfGetDataField ( 1526 PINFCONTEXT Context, 1527 ULONG FieldIndex, 1528 PCSTR *Data) 1529 { 1530 PINFCACHELINE CacheLine; 1531 PINFCACHEFIELD CacheField; 1532 ULONG Index; 1533 1534 if ((Context == NULL) || (Context->Line == NULL) || (Data == NULL)) 1535 { 1536 // DPRINT("Invalid parameter\n"); 1537 return FALSE; 1538 } 1539 1540 CacheLine = (PINFCACHELINE)Context->Line; 1541 1542 if (FieldIndex > CacheLine->FieldCount) 1543 return FALSE; 1544 1545 if (FieldIndex == 0) 1546 { 1547 *Data = CacheLine->Key; 1548 } 1549 else 1550 { 1551 CacheField = CacheLine->FirstField; 1552 for (Index = 1; Index < FieldIndex; Index++) 1553 CacheField = CacheField->Next; 1554 1555 *Data = CacheField->Data; 1556 } 1557 1558 return TRUE; 1559 } 1560 1561 1562 /* EOF */ 1563