Reactos
at master 2419 lines 76 kB view raw
1/* 2 * INF file parsing 3 * 4 * Copyright 2002 Alexandre Julliard for CodeWeavers 5 * 2005-2006 Herv� Poussineau (hpoussin@reactos.org) 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22/* Partially synced with Wine Staging 2.2 */ 23 24#include "setupapi_private.h" 25 26#include <ndk/obfuncs.h> 27 28/* Unicode constants */ 29static const WCHAR BackSlash[] = {'\\',0}; 30static const WCHAR Class[] = {'C','l','a','s','s',0}; 31static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; 32static const WCHAR InfDirectory[] = {'i','n','f','\\',0}; 33static const WCHAR InfFileSpecification[] = {'*','.','i','n','f',0}; 34 35#define CONTROL_Z '\x1a' 36#define MAX_SECTION_NAME_LEN 255 37#define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ 38/* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ 39#define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) 40 41/* inf file structure definitions */ 42 43struct field 44{ 45 const WCHAR *text; /* field text */ 46}; 47 48struct line 49{ 50 int first_field; /* index of first field in field array */ 51 int nb_fields; /* number of fields in line */ 52 int key_field; /* index of field for key or -1 if no key */ 53}; 54 55struct section 56{ 57 const WCHAR *name; /* section name */ 58 unsigned int nb_lines; /* number of used lines */ 59 unsigned int alloc_lines; /* total number of allocated lines in array below */ 60 struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */ 61}; 62 63struct inf_file 64{ 65 struct inf_file *next; /* next appended file */ 66 WCHAR *strings; /* buffer for string data (section names and field values) */ 67 WCHAR *string_pos; /* position of next available string in buffer */ 68 unsigned int nb_sections; /* number of used sections */ 69 unsigned int alloc_sections; /* total number of allocated section pointers */ 70 struct section **sections; /* section pointers array */ 71 unsigned int nb_fields; 72 unsigned int alloc_fields; 73 struct field *fields; 74 int strings_section; /* index of [Strings] section or -1 if none */ 75 WCHAR *filename; /* filename of the INF */ 76}; 77 78/* parser definitions */ 79 80enum parser_state 81{ 82 LINE_START, /* at beginning of a line */ 83 SECTION_NAME, /* parsing a section name */ 84 KEY_NAME, /* parsing a key name */ 85 VALUE_NAME, /* parsing a value name */ 86 EOL_BACKSLASH, /* backslash at end of line */ 87 QUOTES, /* inside quotes */ 88 LEADING_SPACES, /* leading spaces */ 89 TRAILING_SPACES, /* trailing spaces */ 90 COMMENT, /* inside a comment */ 91 NB_PARSER_STATES 92}; 93 94struct parser 95{ 96 const WCHAR *start; /* start position of item being parsed */ 97 const WCHAR *end; /* end of buffer */ 98 struct inf_file *file; /* file being built */ 99 enum parser_state state; /* current parser state */ 100 enum parser_state stack[4]; /* state stack */ 101 int stack_pos; /* current pos in stack */ 102 103 int cur_section; /* index of section being parsed*/ 104 struct line *line; /* current line */ 105 unsigned int line_pos; /* current line position in file */ 106 unsigned int broken_line; /* first line containing invalid data (if any) */ 107 unsigned int error; /* error code */ 108 unsigned int token_len; /* current token len */ 109 WCHAR token[MAX_FIELD_LEN+1]; /* current token */ 110}; 111 112typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos ); 113 114/* parser state machine functions */ 115static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ); 116static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ); 117static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ); 118static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ); 119static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ); 120static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ); 121static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ); 122static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ); 123static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ); 124 125static const parser_state_func parser_funcs[NB_PARSER_STATES] = 126{ 127 line_start_state, /* LINE_START */ 128 section_name_state, /* SECTION_NAME */ 129 key_name_state, /* KEY_NAME */ 130 value_name_state, /* VALUE_NAME */ 131 eol_backslash_state, /* EOL_BACKSLASH */ 132 quotes_state, /* QUOTES */ 133 leading_spaces_state, /* LEADING_SPACES */ 134 trailing_spaces_state, /* TRAILING_SPACES */ 135 comment_state /* COMMENT */ 136}; 137 138 139/* Unicode string constants */ 140static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; 141static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0}; 142static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0}; 143static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0}; 144static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0}; 145static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0}; 146 147/* extend an array, allocating more memory if necessary */ 148static void *grow_array( void *array, unsigned int *count, size_t elem ) 149{ 150 void *new_array; 151 unsigned int new_count = *count + *count / 2; 152 if (new_count < 32) new_count = 32; 153 154 if (array) 155 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, array, new_count * elem ); 156 else 157 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * elem ); 158 159 if (new_array) 160 *count = new_count; 161 else 162 HeapFree( GetProcessHeap(), 0, array ); 163 return new_array; 164} 165 166 167/* get the directory of the inf file (as counted string, not null-terminated) */ 168static const WCHAR *get_inf_dir( const struct inf_file *file, unsigned int *len ) 169{ 170 const WCHAR *p = strrchrW( file->filename, '\\' ); 171 *len = p ? (p + 1 - file->filename) : 0; 172 return file->filename; 173} 174 175 176/* find a section by name */ 177static int find_section( const struct inf_file *file, const WCHAR *name ) 178{ 179 unsigned int i; 180 181 for (i = 0; i < file->nb_sections; i++) 182 if (!strcmpiW( name, file->sections[i]->name )) return i; 183 return -1; 184} 185 186 187/* find a line by name */ 188static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name ) 189{ 190 struct section *section; 191 struct line *line; 192 unsigned int i; 193 194 if (section_index < 0 || section_index >= file->nb_sections) return NULL; 195 section = file->sections[section_index]; 196 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) 197 { 198 if (line->key_field == -1) continue; 199 if (!strcmpiW( name, file->fields[line->key_field].text )) return line; 200 } 201 return NULL; 202} 203 204 205/* add a section to the file and return the section index */ 206static int add_section( struct inf_file *file, const WCHAR *name ) 207{ 208 struct section *section; 209 210 if (file->nb_sections >= file->alloc_sections) 211 { 212 if (!(file->sections = grow_array( file->sections, &file->alloc_sections, 213 sizeof(file->sections[0]) ))) return -1; 214 } 215 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ))) return -1; 216 section->name = name; 217 section->nb_lines = 0; 218 section->alloc_lines = sizeof(section->lines)/sizeof(section->lines[0]); 219 file->sections[file->nb_sections] = section; 220 return file->nb_sections++; 221} 222 223 224/* add a line to a given section */ 225static struct line *add_line( struct inf_file *file, int section_index ) 226{ 227 struct section *section; 228 struct line *line; 229 230 ASSERT( section_index >= 0 && section_index < file->nb_sections ); 231 232 section = file->sections[section_index]; 233 if (section->nb_lines == section->alloc_lines) /* need to grow the section */ 234 { 235 int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line); 236 if (!(section = HeapReAlloc( GetProcessHeap(), 0, section, size ))) return NULL; 237 section->alloc_lines *= 2; 238 file->sections[section_index] = section; 239 } 240 line = &section->lines[section->nb_lines++]; 241 line->first_field = file->nb_fields; 242 line->nb_fields = 0; 243 line->key_field = -1; 244 return line; 245} 246 247 248/* retrieve a given line from section/line index */ 249static inline struct line *get_line( struct inf_file *file, unsigned int section_index, 250 unsigned int line_index ) 251{ 252 struct section *section; 253 254 if (section_index >= file->nb_sections) return NULL; 255 section = file->sections[section_index]; 256 if (line_index >= section->nb_lines) return NULL; 257 return &section->lines[line_index]; 258} 259 260 261/* retrieve a given field from section/line/field index */ 262static struct field *get_field( struct inf_file *file, int section_index, int line_index, 263 int field_index ) 264{ 265 struct line *line = get_line( file, section_index, line_index ); 266 267 if (!line) return NULL; 268 if (!field_index) /* get the key */ 269 { 270 if (line->key_field == -1) return NULL; 271 return &file->fields[line->key_field]; 272 } 273 field_index--; 274 if (field_index >= line->nb_fields) return NULL; 275 return &file->fields[line->first_field + field_index]; 276} 277 278 279/* allocate a new field, growing the array if necessary */ 280static struct field *add_field( struct inf_file *file, const WCHAR *text ) 281{ 282 struct field *field; 283 284 if (file->nb_fields >= file->alloc_fields) 285 { 286 if (!(file->fields = grow_array( file->fields, &file->alloc_fields, 287 sizeof(file->fields[0]) ))) return NULL; 288 } 289 field = &file->fields[file->nb_fields++]; 290 field->text = text; 291 return field; 292} 293 294 295/* retrieve the string substitution for a directory id */ 296static const WCHAR *get_dirid_subst( const struct inf_file *file, int dirid, unsigned int *len ) 297{ 298 const WCHAR *ret; 299 300 if (dirid == DIRID_SRCPATH) return get_inf_dir( file, len ); 301 ret = DIRID_get_string( dirid ); 302 if (ret) *len = strlenW(ret); 303 return ret; 304} 305 306 307/* retrieve the string substitution for a given string, or NULL if not found */ 308/* if found, len is set to the substitution length */ 309static const WCHAR *get_string_subst( const struct inf_file *file, const WCHAR *str, unsigned int *len, 310 BOOL no_trailing_slash ) 311{ 312 static const WCHAR percent = '%'; 313 314 struct section *strings_section; 315 struct line *line; 316 struct field *field; 317 unsigned int i, j; 318 int dirid; 319 WCHAR *dirid_str, *end; 320 const WCHAR *ret = NULL; 321 WCHAR StringLangId[13] = {'S','t','r','i','n','g','s','.',0}; 322 TCHAR Lang[5]; 323 324 if (!*len) /* empty string (%%) is replaced by single percent */ 325 { 326 *len = 1; 327 return &percent; 328 } 329 if (file->strings_section == -1) goto not_found; 330 strings_section = file->sections[file->strings_section]; 331 for (j = 0, line = strings_section->lines; j < strings_section->nb_lines; j++, line++) 332 { 333 if (line->key_field == -1) continue; 334 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; 335 if (!file->fields[line->key_field].text[*len]) break; 336 } 337 if (j == strings_section->nb_lines || !line->nb_fields) goto not_found; 338 field = &file->fields[line->first_field]; 339 GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, Lang, sizeof(Lang)/sizeof(TCHAR)); // get the current system locale for translated strings 340 341 strcpyW(StringLangId + 8, Lang + 2); 342 // now you have e.g. Strings.07 for german neutral translations 343 for (i = 0; i < file->nb_sections; i++) // search in all sections 344 { 345 if (!strcmpiW(file->sections[i]->name,StringLangId)) // if the section is a Strings.* section 346 { 347 strings_section = file->sections[i]; // select this section for further use 348 for (j = 0, line = strings_section->lines; j < strings_section->nb_lines; j++, line++) // process all lines in this section 349 { 350 if (line->key_field == -1) continue; // if no key then skip 351 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; // if wrong key name, then skip 352 if (!file->fields[line->key_field].text[*len]) // if value exist 353 { 354 field = &file->fields[line->first_field]; // then extract value and 355 break; // no more search necessary 356 } 357 } 358 } 359 } 360 361 strcpyW(StringLangId + 8, Lang); // append the Language identifier from GetLocaleInfo 362 // now you have e.g. Strings.0407 for german translations 363 for (i = 0; i < file->nb_sections; i++) // search in all sections 364 { 365 if (!strcmpiW(file->sections[i]->name,StringLangId)) // if the section is a Strings.* section 366 { 367 strings_section = file->sections[i]; // select this section for further use 368 for (j = 0, line = strings_section->lines; j < strings_section->nb_lines; j++, line++) // process all lines in this section 369 { 370 if (line->key_field == -1) continue; // if no key then skip 371 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; // if wrong key name, then skip 372 if (!file->fields[line->key_field].text[*len]) // if value exist 373 { 374 field = &file->fields[line->first_field]; // then extract value and 375 break; // no more search necessary 376 } 377 } 378 } 379 } 380 *len = strlenW( field->text ); // set length 381 ret = field->text; // return the english or translated string 382 return ret; 383 384 385 not_found: /* check for integer id */ 386 if ((dirid_str = HeapAlloc( GetProcessHeap(), 0, (*len+1) * sizeof(WCHAR) ))) 387 { 388 memcpy( dirid_str, str, *len * sizeof(WCHAR) ); 389 dirid_str[*len] = 0; 390 dirid = strtolW( dirid_str, &end, 10 ); 391 if (!*end) ret = get_dirid_subst( file, dirid, len ); 392 if (no_trailing_slash && ret && *len && ret[*len - 1] == '\\') *len -= 1; 393 HeapFree( GetProcessHeap(), 0, dirid_str ); 394 return ret; 395 } 396 return NULL; 397} 398 399 400/* do string substitutions on the specified text */ 401/* the buffer is assumed to be large enough */ 402/* returns necessary length not including terminating null */ 403static unsigned int PARSER_string_substW( const struct inf_file *file, const WCHAR *text, 404 WCHAR *buffer, unsigned int size ) 405{ 406 const WCHAR *start, *subst, *p; 407 unsigned int len, total = 0; 408 BOOL inside = FALSE; 409 410 if (!buffer) size = MAX_STRING_LEN + 1; 411 for (p = start = text; *p; p++) 412 { 413 if (*p != '%') continue; 414 inside = !inside; 415 if (inside) /* start of a %xx% string */ 416 { 417 len = p - start; 418 if (len > size - 1) len = size - 1; 419 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 420 total += len; 421 size -= len; 422 start = p; 423 } 424 else /* end of the %xx% string, find substitution */ 425 { 426 len = p - start - 1; 427 subst = get_string_subst( file, start + 1, &len, p[1] == '\\' ); 428 if (!subst) 429 { 430 subst = start; 431 len = p - start + 1; 432 } 433 if (len > size - 1) len = size - 1; 434 if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) ); 435 total += len; 436 size -= len; 437 start = p + 1; 438 } 439 } 440 441 if (start != p) /* unfinished string, copy it */ 442 { 443 len = p - start; 444 if (len > size - 1) len = size - 1; 445 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 446 total += len; 447 } 448 if (buffer && size) buffer[total] = 0; 449 return total; 450} 451 452 453/* do string substitutions on the specified text */ 454/* the buffer is assumed to be large enough */ 455/* returns necessary length not including terminating null */ 456static unsigned int PARSER_string_substA( const struct inf_file *file, const WCHAR *text, 457 char *buffer, unsigned int size ) 458{ 459 WCHAR buffW[MAX_STRING_LEN+1]; 460 DWORD ret; 461 462 unsigned int len = PARSER_string_substW( file, text, buffW, sizeof(buffW)/sizeof(WCHAR) ); 463 if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) ); 464 else 465 { 466 RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) ); 467 buffer[ret] = 0; 468 } 469 return ret; 470} 471 472 473/* push some string data into the strings buffer */ 474static WCHAR *push_string( struct inf_file *file, const WCHAR *string ) 475{ 476 WCHAR *ret = file->string_pos; 477 strcpyW( ret, string ); 478 file->string_pos += strlenW( ret ) + 1; 479 return ret; 480} 481 482 483/* push the current state on the parser stack */ 484static inline void push_state( struct parser *parser, enum parser_state state ) 485{ 486 ASSERT( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) ); 487 parser->stack[parser->stack_pos++] = state; 488} 489 490 491/* pop the current state */ 492static inline void pop_state( struct parser *parser ) 493{ 494 ASSERT( parser->stack_pos ); 495 parser->state = parser->stack[--parser->stack_pos]; 496} 497 498 499/* set the parser state and return the previous one */ 500static inline enum parser_state set_state( struct parser *parser, enum parser_state state ) 501{ 502 enum parser_state ret = parser->state; 503 parser->state = state; 504 return ret; 505} 506 507 508/* check if the pointer points to an end of file */ 509static inline BOOL is_eof( const struct parser *parser, const WCHAR *ptr ) 510{ 511 return (ptr >= parser->end || *ptr == CONTROL_Z); 512} 513 514 515/* check if the pointer points to an end of line */ 516static inline BOOL is_eol( const struct parser *parser, const WCHAR *ptr ) 517{ 518 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n'); 519} 520 521 522/* push data from current token start up to pos into the current token */ 523static int push_token( struct parser *parser, const WCHAR *pos ) 524{ 525 int len = pos - parser->start; 526 const WCHAR *src = parser->start; 527 WCHAR *dst = parser->token + parser->token_len; 528 529 if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len; 530 531 parser->token_len += len; 532 for ( ; len > 0; len--, dst++, src++) *dst = *src ? *src : ' '; 533 *dst = 0; 534 parser->start = pos; 535 return 0; 536} 537 538 539/* add a section with the current token as name */ 540static int add_section_from_token( struct parser *parser ) 541{ 542 int section_index; 543 544 if (parser->token_len > MAX_SECTION_NAME_LEN) 545 { 546 parser->error = ERROR_SECTION_NAME_TOO_LONG; 547 return -1; 548 } 549 if ((section_index = find_section( parser->file, parser->token )) == -1) 550 { 551 /* need to create a new one */ 552 const WCHAR *name = push_string( parser->file, parser->token ); 553 if ((section_index = add_section( parser->file, name )) == -1) 554 { 555 parser->error = ERROR_NOT_ENOUGH_MEMORY; 556 return -1; 557 } 558 } 559 parser->token_len = 0; 560 parser->cur_section = section_index; 561 return section_index; 562} 563 564 565/* add a field containing the current token to the current line */ 566static struct field *add_field_from_token( struct parser *parser, BOOL is_key ) 567{ 568 struct field *field; 569 WCHAR *text; 570 571 if (!parser->line) /* need to start a new line */ 572 { 573 if (parser->cur_section == -1) /* got a line before the first section */ 574 { 575 parser->error = ERROR_EXPECTED_SECTION_NAME; 576 return NULL; 577 } 578 if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error; 579 } 580 else ASSERT(!is_key); 581 582 text = push_string( parser->file, parser->token ); 583 if ((field = add_field( parser->file, text ))) 584 { 585 if (!is_key) parser->line->nb_fields++; 586 else 587 { 588 /* replace first field by key field */ 589 parser->line->key_field = parser->line->first_field; 590 parser->line->first_field++; 591 } 592 parser->token_len = 0; 593 return field; 594 } 595 error: 596 parser->error = ERROR_NOT_ENOUGH_MEMORY; 597 return NULL; 598} 599 600 601/* close the current line and prepare for parsing a new one */ 602static void close_current_line( struct parser *parser ) 603{ 604 struct line *cur_line = parser->line; 605 606 if (cur_line) 607 { 608 /* if line has a single field and no key, the field is the key too */ 609 if (cur_line->nb_fields == 1 && cur_line->key_field == -1) 610 cur_line->key_field = cur_line->first_field; 611 } 612 parser->line = NULL; 613} 614 615 616/* handler for parser LINE_START state */ 617static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ) 618{ 619 const WCHAR *p; 620 621 for (p = pos; !is_eof( parser, p ); p++) 622 { 623 switch(*p) 624 { 625 case '\n': 626 parser->line_pos++; 627 close_current_line( parser ); 628 break; 629 case ';': 630 push_state( parser, LINE_START ); 631 set_state( parser, COMMENT ); 632 return p + 1; 633 case '[': 634 parser->start = p + 1; 635 set_state( parser, SECTION_NAME ); 636 return p + 1; 637 default: 638 if (isspaceW(*p)) break; 639 if (parser->cur_section != -1) 640 { 641 parser->start = p; 642 set_state( parser, KEY_NAME ); 643 return p; 644 } 645 if (!parser->broken_line) 646 parser->broken_line = parser->line_pos; 647 break; 648 } 649 } 650 close_current_line( parser ); 651 return NULL; 652} 653 654 655/* handler for parser SECTION_NAME state */ 656static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ) 657{ 658 const WCHAR *p; 659 660 for (p = pos; !is_eol( parser, p ); p++) 661 { 662 if (*p == ']') 663 { 664 push_token( parser, p ); 665 if (add_section_from_token( parser ) == -1) return NULL; 666 push_state( parser, LINE_START ); 667 set_state( parser, COMMENT ); /* ignore everything else on the line */ 668 return p + 1; 669 } 670 } 671 parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */ 672 return NULL; 673} 674 675 676/* handler for parser KEY_NAME state */ 677static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ) 678{ 679 const WCHAR *p, *token_end = parser->start; 680 681 for (p = pos; !is_eol( parser, p ); p++) 682 { 683 if (*p == ',') break; 684 switch(*p) 685 { 686 687 case '=': 688 push_token( parser, token_end ); 689 if (!add_field_from_token( parser, TRUE )) return NULL; 690 parser->start = p + 1; 691 push_state( parser, VALUE_NAME ); 692 set_state( parser, LEADING_SPACES ); 693 return p + 1; 694 case ';': 695 push_token( parser, token_end ); 696 if (!add_field_from_token( parser, FALSE )) return NULL; 697 push_state( parser, LINE_START ); 698 set_state( parser, COMMENT ); 699 return p + 1; 700 case '"': 701 push_token( parser, p ); 702 parser->start = p + 1; 703 push_state( parser, KEY_NAME ); 704 set_state( parser, QUOTES ); 705 return p + 1; 706 case '\\': 707 push_token( parser, token_end ); 708 parser->start = p; 709 push_state( parser, KEY_NAME ); 710 set_state( parser, EOL_BACKSLASH ); 711 return p; 712 default: 713 if (!isspaceW(*p)) token_end = p + 1; 714 else 715 { 716 push_token( parser, p ); 717 push_state( parser, KEY_NAME ); 718 set_state( parser, TRAILING_SPACES ); 719 return p; 720 } 721 break; 722 } 723 } 724 push_token( parser, token_end ); 725 set_state( parser, VALUE_NAME ); 726 return p; 727} 728 729 730/* handler for parser VALUE_NAME state */ 731static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ) 732{ 733 const WCHAR *p, *token_end = parser->start; 734 735 for (p = pos; !is_eol( parser, p ); p++) 736 { 737 switch(*p) 738 { 739 case ';': 740 push_token( parser, token_end ); 741 if (!add_field_from_token( parser, FALSE )) return NULL; 742 push_state( parser, LINE_START ); 743 set_state( parser, COMMENT ); 744 return p + 1; 745 case ',': 746 push_token( parser, token_end ); 747 if (!add_field_from_token( parser, FALSE )) return NULL; 748 parser->start = p + 1; 749 push_state( parser, VALUE_NAME ); 750 set_state( parser, LEADING_SPACES ); 751 return p + 1; 752 case '"': 753 push_token( parser, p ); 754 parser->start = p + 1; 755 push_state( parser, VALUE_NAME ); 756 set_state( parser, QUOTES ); 757 return p + 1; 758 case '\\': 759 push_token( parser, token_end ); 760 parser->start = p; 761 push_state( parser, VALUE_NAME ); 762 set_state( parser, EOL_BACKSLASH ); 763 return p; 764 default: 765 if (!isspaceW(*p)) token_end = p + 1; 766 else 767 { 768 push_token( parser, p ); 769 push_state( parser, VALUE_NAME ); 770 set_state( parser, TRAILING_SPACES ); 771 return p; 772 } 773 break; 774 } 775 } 776 push_token( parser, token_end ); 777 if (!add_field_from_token( parser, FALSE )) return NULL; 778 set_state( parser, LINE_START ); 779 return p; 780} 781 782 783/* handler for parser EOL_BACKSLASH state */ 784static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ) 785{ 786 const WCHAR *p; 787 788 for (p = pos; !is_eof( parser, p ); p++) 789 { 790 switch(*p) 791 { 792 case '\n': 793 parser->line_pos++; 794 parser->start = p + 1; 795 set_state( parser, LEADING_SPACES ); 796 return p + 1; 797 case '\\': 798 continue; 799 case ';': 800 push_state( parser, EOL_BACKSLASH ); 801 set_state( parser, COMMENT ); 802 return p + 1; 803 default: 804 if (isspaceW(*p)) continue; 805 push_token( parser, p ); 806 pop_state( parser ); 807 return p; 808 } 809 } 810 parser->start = p; 811 pop_state( parser ); 812 return p; 813} 814 815 816/* handler for parser QUOTES state */ 817static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ) 818{ 819 const WCHAR *p; 820 821 for (p = pos; !is_eol( parser, p ); p++) 822 { 823 if (*p == '"') 824 { 825 if (p+1 < parser->end && p[1] == '"') /* double quotes */ 826 { 827 push_token( parser, p + 1 ); 828 parser->start = p + 2; 829 p++; 830 } 831 else /* end of quotes */ 832 { 833 push_token( parser, p ); 834 parser->start = p + 1; 835 pop_state( parser ); 836 return p + 1; 837 } 838 } 839 } 840 push_token( parser, p ); 841 pop_state( parser ); 842 return p; 843} 844 845 846/* handler for parser LEADING_SPACES state */ 847static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ) 848{ 849 const WCHAR *p; 850 851 for (p = pos; !is_eol( parser, p ); p++) 852 { 853 if (*p == '\\') 854 { 855 parser->start = p; 856 set_state( parser, EOL_BACKSLASH ); 857 return p; 858 } 859 if (!isspaceW(*p)) break; 860 } 861 parser->start = p; 862 pop_state( parser ); 863 return p; 864} 865 866 867/* handler for parser TRAILING_SPACES state */ 868static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ) 869{ 870 const WCHAR *p; 871 872 for (p = pos; !is_eol( parser, p ); p++) 873 { 874 if (*p == '\\') 875 { 876 set_state( parser, EOL_BACKSLASH ); 877 return p; 878 } 879 if (!isspaceW(*p)) break; 880 } 881 pop_state( parser ); 882 return p; 883} 884 885 886/* handler for parser COMMENT state */ 887static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ) 888{ 889 const WCHAR *p = pos; 890 891 while (!is_eol( parser, p )) p++; 892 pop_state( parser ); 893 return p; 894} 895 896 897static void free_inf_file( struct inf_file *file ) 898{ 899 unsigned int i; 900 901 for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] ); 902 HeapFree( GetProcessHeap(), 0, file->filename ); 903 HeapFree( GetProcessHeap(), 0, file->sections ); 904 HeapFree( GetProcessHeap(), 0, file->fields ); 905 HeapFree( GetProcessHeap(), 0, file->strings ); 906 HeapFree( GetProcessHeap(), 0, file ); 907} 908 909 910/* parse a complete buffer */ 911static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end, 912 UINT *error_line ) 913{ 914 static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0}; 915 916 struct parser parser; 917 const WCHAR *pos = buffer; 918 919 parser.start = buffer; 920 parser.end = end; 921 parser.file = file; 922 parser.line = NULL; 923 parser.state = LINE_START; 924 parser.stack_pos = 0; 925 parser.cur_section = -1; 926 parser.line_pos = 1; 927 parser.broken_line = 0; 928 parser.error = 0; 929 parser.token_len = 0; 930 931 /* parser main loop */ 932 while (pos) pos = (parser_funcs[parser.state])( &parser, pos ); 933 934 /* trim excess buffer space */ 935 if (file->alloc_sections > file->nb_sections) 936 { 937 file->sections = HeapReAlloc( GetProcessHeap(), 0, file->sections, 938 file->nb_sections * sizeof(file->sections[0]) ); 939 file->alloc_sections = file->nb_sections; 940 } 941 if (file->alloc_fields > file->nb_fields) 942 { 943 file->fields = HeapReAlloc( GetProcessHeap(), 0, file->fields, 944 file->nb_fields * sizeof(file->fields[0]) ); 945 file->alloc_fields = file->nb_fields; 946 } 947 file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings, 948 (file->string_pos - file->strings) * sizeof(WCHAR) ); 949 950 if (parser.error) 951 { 952 if (error_line) *error_line = parser.line_pos; 953 return parser.error; 954 } 955 956 /* find the [strings] section */ 957 file->strings_section = find_section( file, Strings ); 958 959 if (file->strings_section == -1 && parser.broken_line) 960 { 961 if (error_line) *error_line = parser.broken_line; 962 return ERROR_EXPECTED_SECTION_NAME; 963 } 964 965 return 0; 966} 967 968 969/* append a child INF file to its parent list, in a thread-safe manner */ 970static void append_inf_file( struct inf_file *parent, struct inf_file *child ) 971{ 972 struct inf_file **ppnext = &parent->next; 973 child->next = NULL; 974 975 for (;;) 976 { 977 struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL ); 978 if (!next) return; 979 ppnext = &next->next; 980 } 981} 982 983 984/*********************************************************************** 985 * parse_file 986 * 987 * parse an INF file. 988 */ 989static struct inf_file *parse_file( HANDLE handle, UINT *error_line, DWORD style ) 990{ 991 void *buffer; 992 DWORD err = 0; 993 struct inf_file *file; 994 995 DWORD size = GetFileSize( handle, NULL ); 996 HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL ); 997 if (!mapping) return NULL; 998 buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size ); 999 NtClose( mapping ); 1000 if (!buffer) return NULL; 1001 1002 if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) ))) 1003 { 1004 err = ERROR_NOT_ENOUGH_MEMORY; 1005 goto done; 1006 } 1007 1008 /* we won't need more strings space than the size of the file, 1009 * so we can preallocate it here 1010 */ 1011 if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) 1012 { 1013 err = ERROR_NOT_ENOUGH_MEMORY; 1014 goto done; 1015 } 1016 file->string_pos = file->strings; 1017 file->strings_section = -1; 1018 1019 if (!RtlIsTextUnicode( buffer, size, NULL )) 1020 { 1021 static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; 1022 WCHAR *new_buff; 1023 UINT codepage = CP_ACP; 1024 UINT offset = 0; 1025 1026 if (size > sizeof(utf8_bom) && !memcmp( buffer, utf8_bom, sizeof(utf8_bom) )) 1027 { 1028 codepage = CP_UTF8; 1029 offset = sizeof(utf8_bom); 1030 } 1031 1032 if ((new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) 1033 { 1034 DWORD len = MultiByteToWideChar( codepage, 0, (char *)buffer + offset, 1035 size - offset, new_buff, size ); 1036 err = parse_buffer( file, new_buff, new_buff + len, error_line ); 1037 HeapFree( GetProcessHeap(), 0, new_buff ); 1038 } 1039 } 1040 else 1041 { 1042 WCHAR *new_buff = buffer; 1043 /* UCS-16 files should start with the Unicode BOM; we should skip it */ 1044 if (*new_buff == 0xfeff) 1045 new_buff++; 1046 err = parse_buffer( file, new_buff, (WCHAR *)((char *)buffer + size), error_line ); 1047 } 1048 1049 if (!err) /* now check signature */ 1050 { 1051 int version_index = find_section( file, Version ); 1052 if (version_index != -1) 1053 { 1054 struct line *line = find_line( file, version_index, Signature ); 1055 if (line && line->nb_fields > 0) 1056 { 1057 struct field *field = file->fields + line->first_field; 1058 if (!strcmpiW( field->text, Chicago )) goto done; 1059 if (!strcmpiW( field->text, WindowsNT )) goto done; 1060 if (!strcmpiW( field->text, Windows95 )) goto done; 1061 } 1062 } 1063 if (error_line) *error_line = 0; 1064 if (style & INF_STYLE_WIN4) err = ERROR_WRONG_INF_STYLE; 1065 } 1066 1067 done: 1068 UnmapViewOfFile( buffer ); 1069 if (err) 1070 { 1071 if (file) free_inf_file( file ); 1072 SetLastError( err ); 1073 file = NULL; 1074 } 1075 return file; 1076} 1077 1078 1079/*********************************************************************** 1080 * PARSER_get_inf_filename 1081 * 1082 * Retrieve the filename of an inf file. 1083 */ 1084const WCHAR *PARSER_get_inf_filename( HINF hinf ) 1085{ 1086 struct inf_file *file = hinf; 1087 return file->filename; 1088} 1089 1090 1091/*********************************************************************** 1092 * PARSER_get_src_root 1093 * 1094 * Retrieve the source directory of an inf file. 1095 */ 1096WCHAR *PARSER_get_src_root( HINF hinf ) 1097{ 1098 unsigned int len; 1099 const WCHAR *dir = get_inf_dir( hinf, &len ); 1100 WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ); 1101 if (ret) 1102 { 1103 memcpy( ret, dir, len * sizeof(WCHAR) ); 1104 ret[len] = 0; 1105 } 1106 return ret; 1107} 1108 1109 1110/*********************************************************************** 1111 * PARSER_get_dest_dir 1112 * 1113 * retrieve a destination dir of the form "dirid,relative_path" in the given entry. 1114 * returned buffer must be freed by caller. 1115 */ 1116WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) 1117{ 1118 const WCHAR *dir; 1119 WCHAR *ptr, *ret; 1120 INT dirid; 1121 unsigned int len1; 1122 DWORD len2; 1123 1124 if (!SetupGetIntField( context, 1, &dirid )) return NULL; 1125 if (!(dir = get_dirid_subst( context->Inf, dirid, &len1 ))) return NULL; 1126 if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0; 1127 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2+1) * sizeof(WCHAR) ))) return NULL; 1128 memcpy( ret, dir, len1 * sizeof(WCHAR) ); 1129 ptr = ret + len1; 1130 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\'; 1131 if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0; 1132 return ret; 1133} 1134 1135 1136/*********************************************************************** 1137 * SetupOpenInfFileA (SETUPAPI.@) 1138 */ 1139HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error ) 1140{ 1141 UNICODE_STRING nameW, classW; 1142 HINF ret = INVALID_HANDLE_VALUE; 1143 1144 classW.Buffer = NULL; 1145 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class )) 1146 { 1147 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1148 return ret; 1149 } 1150 if (RtlCreateUnicodeStringFromAsciiz( &nameW, name )) 1151 { 1152 ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error ); 1153 RtlFreeUnicodeString( &nameW ); 1154 } 1155 RtlFreeUnicodeString( &classW ); 1156 return ret; 1157} 1158 1159 1160static BOOL 1161PARSER_GetInfClassW( 1162 IN HINF hInf, 1163 OUT LPGUID ClassGuid, 1164 OUT PWSTR ClassName, 1165 IN DWORD ClassNameSize, 1166 OUT PDWORD RequiredSize OPTIONAL) 1167{ 1168 DWORD requiredSize; 1169 WCHAR guidW[MAX_GUID_STRING_LEN + 1]; 1170 BOOL ret = FALSE; 1171 1172 /* Read class Guid */ 1173 if (!SetupGetLineTextW(NULL, hInf, Version, ClassGUID, guidW, sizeof(guidW), NULL)) 1174 goto cleanup; 1175 guidW[37] = '\0'; /* Replace the } by a NULL character */ 1176 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK) 1177 goto cleanup; 1178 1179 /* Read class name */ 1180 ret = SetupGetLineTextW(NULL, hInf, Version, Class, ClassName, ClassNameSize, &requiredSize); 1181 if (ret && ClassName == NULL && ClassNameSize == 0) 1182 { 1183 if (RequiredSize) 1184 *RequiredSize = requiredSize; 1185 SetLastError(ERROR_INSUFFICIENT_BUFFER); 1186 ret = FALSE; 1187 goto cleanup; 1188 } 1189 if (!ret) 1190 { 1191 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 1192 { 1193 if (RequiredSize) 1194 *RequiredSize = requiredSize; 1195 goto cleanup; 1196 } 1197 else if (!SetupDiClassNameFromGuidW(ClassGuid, ClassName, ClassNameSize, &requiredSize)) 1198 { 1199 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 1200 { 1201 if (RequiredSize) 1202 *RequiredSize = requiredSize; 1203 goto cleanup; 1204 } 1205 /* Return a NULL class name */ 1206 if (RequiredSize) 1207 *RequiredSize = 1; 1208 if (ClassNameSize < 1) 1209 { 1210 SetLastError(ERROR_INSUFFICIENT_BUFFER); 1211 goto cleanup; 1212 } 1213 memcpy(ClassGuid, &GUID_NULL, sizeof(GUID)); 1214 *ClassName = UNICODE_NULL; 1215 } 1216 } 1217 1218 ret = TRUE; 1219 1220cleanup: 1221 TRACE("Returning %d\n", ret); 1222 return ret; 1223} 1224 1225 1226/*********************************************************************** 1227 * SetupOpenInfFileW (SETUPAPI.@) 1228 */ 1229HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error ) 1230{ 1231 struct inf_file *file = NULL; 1232 HANDLE handle; 1233 WCHAR *path, *p; 1234 UINT len; 1235 1236 TRACE("%s %s %lx %p\n", debugstr_w(name), debugstr_w(class), style, error); 1237 1238#ifdef __REACTOS__ 1239 if (style & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)) 1240 { 1241 SetLastError(ERROR_INVALID_PARAMETER); 1242 return (HINF)INVALID_HANDLE_VALUE; 1243 } 1244 if (!name) 1245 { 1246 SetLastError(ERROR_INVALID_PARAMETER); 1247 return (HINF)INVALID_HANDLE_VALUE; 1248 } 1249#endif // __REACTOS__ 1250 1251 if (strchrW( name, '\\' ) || strchrW( name, '/' )) 1252 { 1253 if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return INVALID_HANDLE_VALUE; 1254 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 1255 { 1256 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1257 return INVALID_HANDLE_VALUE; 1258 } 1259 GetFullPathNameW( name, len, path, NULL ); 1260 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 1261 } 1262 else /* try Windows directory */ 1263 { 1264 static const WCHAR Inf[] = {'\\','i','n','f','\\',0}; 1265 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0}; 1266 1267 len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12; 1268 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 1269 { 1270 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1271 return INVALID_HANDLE_VALUE; 1272 } 1273 GetWindowsDirectoryW( path, len ); 1274 p = path + strlenW(path); 1275 strcpyW( p, Inf ); 1276 strcatW( p, name ); 1277 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 1278 if (handle == INVALID_HANDLE_VALUE) 1279 { 1280 strcpyW( p, System32 ); 1281 strcatW( p, name ); 1282 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 1283 } 1284 } 1285 1286 if (handle != INVALID_HANDLE_VALUE) 1287 { 1288 file = parse_file( handle, error, style); 1289 CloseHandle( handle ); 1290 } 1291 if (!file) 1292 { 1293 HeapFree( GetProcessHeap(), 0, path ); 1294 return INVALID_HANDLE_VALUE; 1295 } 1296 TRACE( "%s -> %p\n", debugstr_w(path), file ); 1297 file->filename = path; 1298 1299 if (class) 1300 { 1301 GUID ClassGuid; 1302 LPWSTR ClassName = HeapAlloc(GetProcessHeap(), 0, (strlenW(class) + 1) * sizeof(WCHAR)); 1303 if (!ClassName) 1304 { 1305 /* Not enough memory */ 1306 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1307 SetupCloseInfFile((HINF)file); 1308 return INVALID_HANDLE_VALUE; 1309 } 1310 else if (!PARSER_GetInfClassW((HINF)file, &ClassGuid, ClassName, strlenW(class) + 1, NULL)) 1311 { 1312 /* Unable to get class name in .inf file */ 1313 HeapFree(GetProcessHeap(), 0, ClassName); 1314 SetLastError(ERROR_CLASS_MISMATCH); 1315 SetupCloseInfFile((HINF)file); 1316 return INVALID_HANDLE_VALUE; 1317 } 1318 else if (strcmpW(class, ClassName) != 0) 1319 { 1320 /* Provided name name is not the expected one */ 1321 HeapFree(GetProcessHeap(), 0, ClassName); 1322 SetLastError(ERROR_CLASS_MISMATCH); 1323 SetupCloseInfFile((HINF)file); 1324 return INVALID_HANDLE_VALUE; 1325 } 1326 HeapFree(GetProcessHeap(), 0, ClassName); 1327 } 1328 1329 SetLastError( 0 ); 1330 return file; 1331} 1332 1333 1334/*********************************************************************** 1335 * SetupOpenAppendInfFileA (SETUPAPI.@) 1336 */ 1337BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error ) 1338{ 1339 HINF child_hinf; 1340 1341 if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error ); 1342 child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error ); 1343 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 1344 append_inf_file( parent_hinf, child_hinf ); 1345 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf ); 1346 return TRUE; 1347} 1348 1349 1350/*********************************************************************** 1351 * SetupOpenAppendInfFileW (SETUPAPI.@) 1352 */ 1353BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error ) 1354{ 1355 HINF child_hinf; 1356 1357 if (!name) 1358 { 1359 INFCONTEXT context; 1360 WCHAR filename[MAX_PATH]; 1361 int idx = 1; 1362 1363 if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE; 1364 while (SetupGetStringFieldW( &context, idx++, filename, 1365 sizeof(filename)/sizeof(WCHAR), NULL )) 1366 { 1367 child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error ); 1368 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 1369 append_inf_file( parent_hinf, child_hinf ); 1370 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf ); 1371 } 1372 return TRUE; 1373 } 1374 child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error ); 1375 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 1376 append_inf_file( parent_hinf, child_hinf ); 1377 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf ); 1378 return TRUE; 1379} 1380 1381 1382/*********************************************************************** 1383 * SetupOpenMasterInf (SETUPAPI.@) 1384 */ 1385HINF WINAPI SetupOpenMasterInf( VOID ) 1386{ 1387 static const WCHAR Layout[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0}; 1388 WCHAR Buffer[MAX_PATH]; 1389 1390 GetWindowsDirectoryW( Buffer, MAX_PATH ); 1391 strcatW( Buffer, Layout ); 1392 return SetupOpenInfFileW( Buffer, NULL, INF_STYLE_WIN4, NULL); 1393} 1394 1395 1396 1397/*********************************************************************** 1398 * SetupCloseInfFile (SETUPAPI.@) 1399 */ 1400void WINAPI SetupCloseInfFile( HINF hinf ) 1401{ 1402 struct inf_file *file = hinf; 1403 1404 if (!hinf || (hinf == INVALID_HANDLE_VALUE)) return; 1405 1406 free_inf_file( file ); 1407} 1408 1409 1410/*********************************************************************** 1411 * SetupEnumInfSectionsA (SETUPAPI.@) 1412 */ 1413BOOL WINAPI SetupEnumInfSectionsA( HINF hinf, UINT index, PSTR buffer, DWORD size, DWORD *need ) 1414{ 1415 struct inf_file *file = hinf; 1416 1417 for (file = hinf; file; file = file->next) 1418 { 1419 if (index < file->nb_sections) 1420 { 1421 DWORD len = WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1, 1422 NULL, 0, NULL, NULL ); 1423 if (need) *need = len; 1424 if (!buffer) 1425 { 1426 if (!size) return TRUE; 1427 SetLastError( ERROR_INVALID_USER_BUFFER ); 1428 return FALSE; 1429 } 1430 if (len > size) 1431 { 1432 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1433 return FALSE; 1434 } 1435 WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1, buffer, size, NULL, NULL ); 1436 return TRUE; 1437 } 1438 index -= file->nb_sections; 1439 } 1440 SetLastError( ERROR_NO_MORE_ITEMS ); 1441 return FALSE; 1442} 1443 1444 1445/*********************************************************************** 1446 * SetupEnumInfSectionsW (SETUPAPI.@) 1447 */ 1448BOOL WINAPI SetupEnumInfSectionsW( HINF hinf, UINT index, PWSTR buffer, DWORD size, DWORD *need ) 1449{ 1450 struct inf_file *file = hinf; 1451 1452 for (file = hinf; file; file = file->next) 1453 { 1454 if (index < file->nb_sections) 1455 { 1456 DWORD len = strlenW( file->sections[index]->name ) + 1; 1457 if (need) *need = len; 1458 if (!buffer) 1459 { 1460 if (!size) return TRUE; 1461 SetLastError( ERROR_INVALID_USER_BUFFER ); 1462 return FALSE; 1463 } 1464 if (len > size) 1465 { 1466 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1467 return FALSE; 1468 } 1469 memcpy( buffer, file->sections[index]->name, len * sizeof(WCHAR) ); 1470 return TRUE; 1471 } 1472 index -= file->nb_sections; 1473 } 1474 SetLastError( ERROR_NO_MORE_ITEMS ); 1475 return FALSE; 1476} 1477 1478 1479/*********************************************************************** 1480 * SetupGetLineCountA (SETUPAPI.@) 1481 */ 1482LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name ) 1483{ 1484 UNICODE_STRING sectionW; 1485 LONG ret = -1; 1486 1487 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, name )) 1488 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1489 else 1490 { 1491 ret = SetupGetLineCountW( hinf, sectionW.Buffer ); 1492 RtlFreeUnicodeString( &sectionW ); 1493 } 1494 return ret; 1495} 1496 1497 1498/*********************************************************************** 1499 * SetupGetLineCountW (SETUPAPI.@) 1500 */ 1501LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section ) 1502{ 1503 struct inf_file *file = hinf; 1504 int section_index; 1505 LONG ret = -1; 1506 1507 for (file = hinf; file; file = file->next) 1508 { 1509 if ((section_index = find_section( file, section )) == -1) continue; 1510 if (ret == -1) ret = 0; 1511 ret += file->sections[section_index]->nb_lines; 1512 } 1513 TRACE( "(%p,%s) returning %d\n", hinf, debugstr_w(section), ret ); 1514 SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 ); 1515 return ret; 1516} 1517 1518 1519/*********************************************************************** 1520 * SetupGetLineByIndexA (SETUPAPI.@) 1521 */ 1522BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context ) 1523{ 1524 UNICODE_STRING sectionW; 1525 BOOL ret = FALSE; 1526 1527 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section )) 1528 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1529 else 1530 { 1531 ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context ); 1532 RtlFreeUnicodeString( &sectionW ); 1533 } 1534 return ret; 1535} 1536 1537 1538/*********************************************************************** 1539 * SetupGetLineByIndexW (SETUPAPI.@) 1540 */ 1541BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context ) 1542{ 1543 struct inf_file *file = hinf; 1544 int section_index; 1545 1546 for (file = hinf; file; file = file->next) 1547 { 1548 if ((section_index = find_section( file, section )) == -1) continue; 1549 if (index < file->sections[section_index]->nb_lines) 1550 { 1551 context->Inf = hinf; 1552 context->CurrentInf = file; 1553 context->Section = section_index; 1554 context->Line = index; 1555 SetLastError( 0 ); 1556 TRACE( "(%p,%s): returning %d/%d\n", 1557 hinf, debugstr_w(section), section_index, index ); 1558 return TRUE; 1559 } 1560 index -= file->sections[section_index]->nb_lines; 1561 } 1562 TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) ); 1563 SetLastError( ERROR_LINE_NOT_FOUND ); 1564 return FALSE; 1565} 1566 1567 1568/*********************************************************************** 1569 * SetupFindFirstLineA (SETUPAPI.@) 1570 */ 1571BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context ) 1572{ 1573 UNICODE_STRING sectionW, keyW; 1574 BOOL ret = FALSE; 1575 1576 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section )) 1577 { 1578 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1579 return FALSE; 1580 } 1581 1582 if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context ); 1583 else 1584 { 1585 if (RtlCreateUnicodeStringFromAsciiz( &keyW, key )) 1586 { 1587 ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context ); 1588 RtlFreeUnicodeString( &keyW ); 1589 } 1590 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1591 } 1592 RtlFreeUnicodeString( &sectionW ); 1593 return ret; 1594} 1595 1596 1597/*********************************************************************** 1598 * SetupFindFirstLineW (SETUPAPI.@) 1599 */ 1600BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context ) 1601{ 1602 struct inf_file *file; 1603 int section_index; 1604 1605 for (file = hinf; file; file = file->next) 1606 { 1607 if ((section_index = find_section( file, section )) == -1) continue; 1608 if (key) 1609 { 1610 INFCONTEXT ctx; 1611 ctx.Inf = hinf; 1612 ctx.CurrentInf = file; 1613 ctx.Section = section_index; 1614 ctx.Line = -1; 1615 return SetupFindNextMatchLineW( &ctx, key, context ); 1616 } 1617 if (file->sections[section_index]->nb_lines) 1618 { 1619 context->Inf = hinf; 1620 context->CurrentInf = file; 1621 context->Section = section_index; 1622 context->Line = 0; 1623 SetLastError( 0 ); 1624 TRACE( "(%p,%s,%s): returning %d/0\n", 1625 hinf, debugstr_w(section), debugstr_w(key), section_index ); 1626 return TRUE; 1627 } 1628 } 1629 TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) ); 1630 SetLastError( ERROR_LINE_NOT_FOUND ); 1631 return FALSE; 1632} 1633 1634 1635/*********************************************************************** 1636 * SetupFindNextLine (SETUPAPI.@) 1637 */ 1638BOOL WINAPI SetupFindNextLine( PINFCONTEXT context_in, PINFCONTEXT context_out ) 1639{ 1640 struct inf_file *file = context_in->CurrentInf; 1641 struct section *section; 1642 1643 if (context_in->Section >= file->nb_sections) goto error; 1644 1645 section = file->sections[context_in->Section]; 1646 if (context_in->Line+1 < section->nb_lines) 1647 { 1648 if (context_out != context_in) *context_out = *context_in; 1649 context_out->Line++; 1650 SetLastError( 0 ); 1651 return TRUE; 1652 } 1653 1654 /* now search the appended files */ 1655 1656 for (file = file->next; file; file = file->next) 1657 { 1658 int section_index = find_section( file, section->name ); 1659 if (section_index == -1) continue; 1660 if (file->sections[section_index]->nb_lines) 1661 { 1662 context_out->Inf = context_in->Inf; 1663 context_out->CurrentInf = file; 1664 context_out->Section = section_index; 1665 context_out->Line = 0; 1666 SetLastError( 0 ); 1667 return TRUE; 1668 } 1669 } 1670 error: 1671 SetLastError( ERROR_LINE_NOT_FOUND ); 1672 return FALSE; 1673} 1674 1675 1676/*********************************************************************** 1677 * SetupFindNextMatchLineA (SETUPAPI.@) 1678 */ 1679BOOL WINAPI SetupFindNextMatchLineA( PINFCONTEXT context_in, PCSTR key, 1680 PINFCONTEXT context_out ) 1681{ 1682 UNICODE_STRING keyW; 1683 BOOL ret = FALSE; 1684 1685 if (!key) return SetupFindNextLine( context_in, context_out ); 1686 1687 if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key )) 1688 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1689 else 1690 { 1691 ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out ); 1692 RtlFreeUnicodeString( &keyW ); 1693 } 1694 return ret; 1695} 1696 1697 1698/*********************************************************************** 1699 * SetupFindNextMatchLineW (SETUPAPI.@) 1700 */ 1701BOOL WINAPI SetupFindNextMatchLineW( PINFCONTEXT context_in, PCWSTR key, 1702 PINFCONTEXT context_out ) 1703{ 1704 struct inf_file *file = context_in->CurrentInf; 1705 struct section *section; 1706 struct line *line; 1707 unsigned int i; 1708 1709 if (!key) return SetupFindNextLine( context_in, context_out ); 1710 1711 if (context_in->Section >= file->nb_sections) goto error; 1712 1713 section = file->sections[context_in->Section]; 1714 1715 for (i = context_in->Line+1, line = &section->lines[i]; i < section->nb_lines; i++, line++) 1716 { 1717 if (line->key_field == -1) continue; 1718 if (!strcmpiW( key, file->fields[line->key_field].text )) 1719 { 1720 if (context_out != context_in) *context_out = *context_in; 1721 context_out->Line = i; 1722 SetLastError( 0 ); 1723 TRACE( "(%p,%s,%s): returning %d\n", 1724 file, debugstr_w(section->name), debugstr_w(key), i ); 1725 return TRUE; 1726 } 1727 } 1728 1729 /* now search the appended files */ 1730 1731 for (file = file->next; file; file = file->next) 1732 { 1733 int section_index = find_section( file, section->name ); 1734 if (section_index == -1) continue; 1735 section = file->sections[section_index]; 1736 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) 1737 { 1738 if (line->key_field == -1) continue; 1739 if (!strcmpiW( key, file->fields[line->key_field].text )) 1740 { 1741 context_out->Inf = context_in->Inf; 1742 context_out->CurrentInf = file; 1743 context_out->Section = section_index; 1744 context_out->Line = i; 1745 SetLastError( 0 ); 1746 TRACE( "(%p,%s,%s): returning %d/%d\n", 1747 file, debugstr_w(section->name), debugstr_w(key), section_index, i ); 1748 return TRUE; 1749 } 1750 } 1751 } 1752 TRACE( "(%p,%s,%s): not found\n", 1753 context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) ); 1754 error: 1755 SetLastError( ERROR_LINE_NOT_FOUND ); 1756 return FALSE; 1757} 1758 1759 1760/*********************************************************************** 1761 * SetupGetLineTextW (SETUPAPI.@) 1762 */ 1763BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_name, 1764 PCWSTR key_name, PWSTR buffer, DWORD size, PDWORD required ) 1765{ 1766 struct inf_file *file; 1767 struct line *line; 1768 struct field *field; 1769 int i; 1770 DWORD total = 0; 1771 1772 if (!context) 1773 { 1774 INFCONTEXT new_context; 1775 if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE; 1776 file = new_context.CurrentInf; 1777 line = get_line( file, new_context.Section, new_context.Line ); 1778 } 1779 else 1780 { 1781 file = context->CurrentInf; 1782 if (!(line = get_line( file, context->Section, context->Line ))) 1783 { 1784 SetLastError( ERROR_LINE_NOT_FOUND ); 1785 return FALSE; 1786 } 1787 } 1788 1789 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 1790 total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1; 1791 1792 if (required) *required = total; 1793 if (buffer) 1794 { 1795 if (total > size) 1796 { 1797 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1798 return FALSE; 1799 } 1800 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 1801 { 1802 unsigned int len = PARSER_string_substW( file, field->text, buffer, size ); 1803 if (i+1 < line->nb_fields) buffer[len] = ','; 1804 buffer += len + 1; 1805 } 1806 } 1807 return TRUE; 1808} 1809 1810 1811/*********************************************************************** 1812 * SetupGetLineTextA (SETUPAPI.@) 1813 */ 1814BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_name, 1815 PCSTR key_name, PSTR buffer, DWORD size, PDWORD required ) 1816{ 1817 struct inf_file *file; 1818 struct line *line; 1819 struct field *field; 1820 int i; 1821 DWORD total = 0; 1822 1823 if (!context) 1824 { 1825 INFCONTEXT new_context; 1826 if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE; 1827 file = new_context.CurrentInf; 1828 line = get_line( file, new_context.Section, new_context.Line ); 1829 } 1830 else 1831 { 1832 file = context->CurrentInf; 1833 if (!(line = get_line( file, context->Section, context->Line ))) 1834 { 1835 SetLastError( ERROR_LINE_NOT_FOUND ); 1836 return FALSE; 1837 } 1838 } 1839 1840 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 1841 total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1; 1842 1843 if (required) *required = total; 1844 if (buffer) 1845 { 1846 if (total > size) 1847 { 1848 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1849 return FALSE; 1850 } 1851 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 1852 { 1853 unsigned int len = PARSER_string_substA( file, field->text, buffer, size ); 1854 if (i+1 < line->nb_fields) buffer[len] = ','; 1855 buffer += len + 1; 1856 } 1857 } 1858 return TRUE; 1859} 1860 1861 1862/*********************************************************************** 1863 * SetupGetFieldCount (SETUPAPI.@) 1864 */ 1865DWORD WINAPI SetupGetFieldCount( PINFCONTEXT context ) 1866{ 1867 struct inf_file *file = context->CurrentInf; 1868 struct line *line = get_line( file, context->Section, context->Line ); 1869 1870 if (!line) return 0; 1871 return line->nb_fields; 1872} 1873 1874 1875/*********************************************************************** 1876 * SetupGetStringFieldA (SETUPAPI.@) 1877 */ 1878BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, 1879 DWORD size, PDWORD required ) 1880{ 1881 struct inf_file *file = context->CurrentInf; 1882 struct field *field = get_field( file, context->Section, context->Line, index ); 1883 unsigned int len; 1884 1885 SetLastError(0); 1886 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } 1887 len = PARSER_string_substA( file, field->text, NULL, 0 ); 1888 if (required) *required = len + 1; 1889 if (buffer) 1890 { 1891 if (size <= len) 1892 { 1893 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1894 return FALSE; 1895 } 1896 PARSER_string_substA( file, field->text, buffer, size ); 1897 1898 TRACE( "context %p/%p/%d/%d index %d returning %s\n", 1899 context->Inf, context->CurrentInf, context->Section, context->Line, 1900 index, debugstr_a(buffer) ); 1901 } 1902 return TRUE; 1903} 1904 1905 1906/*********************************************************************** 1907 * SetupGetStringFieldW (SETUPAPI.@) 1908 */ 1909BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, 1910 DWORD size, PDWORD required ) 1911{ 1912 struct inf_file *file = context->CurrentInf; 1913 struct field *field = get_field( file, context->Section, context->Line, index ); 1914 unsigned int len; 1915 1916 SetLastError(0); 1917 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } 1918 len = PARSER_string_substW( file, field->text, NULL, 0 ); 1919 if (required) *required = len + 1; 1920 if (buffer) 1921 { 1922 if (size <= len) 1923 { 1924 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1925 return FALSE; 1926 } 1927 PARSER_string_substW( file, field->text, buffer, size ); 1928 1929 TRACE( "context %p/%p/%d/%d index %d returning %s\n", 1930 context->Inf, context->CurrentInf, context->Section, context->Line, 1931 index, debugstr_w(buffer) ); 1932 } 1933 return TRUE; 1934} 1935 1936 1937/*********************************************************************** 1938 * SetupGetIntField (SETUPAPI.@) 1939 */ 1940BOOL WINAPI SetupGetIntField( PINFCONTEXT context, DWORD index, PINT result ) 1941{ 1942 char localbuff[20]; 1943 char *end, *buffer = localbuff; 1944 DWORD required; 1945 INT res; 1946 BOOL ret; 1947 1948 if (!(ret = SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required ))) 1949 { 1950 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE; 1951 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE; 1952 if (!(ret = SetupGetStringFieldA( context, index, buffer, required, NULL ))) goto done; 1953 } 1954 /* The call to SetupGetStringFieldA succeeded. If buffer is empty we have an optional field */ 1955 if (!*buffer) *result = 0; 1956 else 1957 { 1958 res = strtol( buffer, &end, 0 ); 1959 if (end != buffer && !*end) *result = res; 1960 else 1961 { 1962 SetLastError( ERROR_INVALID_DATA ); 1963 ret = FALSE; 1964 } 1965 } 1966 1967 done: 1968 if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer ); 1969 return ret; 1970} 1971 1972 1973/*********************************************************************** 1974 * SetupGetBinaryField (SETUPAPI.@) 1975 */ 1976BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer, 1977 DWORD size, LPDWORD required ) 1978{ 1979 struct inf_file *file = context->CurrentInf; 1980 struct line *line = get_line( file, context->Section, context->Line ); 1981 struct field *field; 1982 int i; 1983 1984 if (!line) 1985 { 1986 SetLastError( ERROR_LINE_NOT_FOUND ); 1987 return FALSE; 1988 } 1989 if (!index || index > line->nb_fields) 1990 { 1991 SetLastError( ERROR_INVALID_PARAMETER ); 1992 return FALSE; 1993 } 1994 index--; /* fields start at 0 */ 1995 if (required) *required = line->nb_fields - index; 1996 if (!buffer) return TRUE; 1997 if (size < line->nb_fields - index) 1998 { 1999 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 2000 return FALSE; 2001 } 2002 field = &file->fields[line->first_field + index]; 2003 for (i = index; i < line->nb_fields; i++, field++) 2004 { 2005 const WCHAR *p; 2006 DWORD value = 0; 2007 for (p = field->text; *p && isxdigitW(*p); p++) 2008 { 2009 if ((value <<= 4) > 255) 2010 { 2011 SetLastError( ERROR_INVALID_DATA ); 2012 return FALSE; 2013 } 2014 if (*p <= '9') value |= (*p - '0'); 2015 else value |= (tolowerW(*p) - 'a' + 10); 2016 } 2017 buffer[i - index] = value; 2018 } 2019 if (TRACE_ON(setupapi)) 2020 { 2021 TRACE( "%p/%p/%d/%d index %d returning:\n", 2022 context->Inf, context->CurrentInf, context->Section, context->Line, index ); 2023 for (i = index; i < line->nb_fields; i++) TRACE( " %02x\n", buffer[i - index] ); 2024 } 2025 return TRUE; 2026} 2027 2028 2029/*********************************************************************** 2030 * SetupGetMultiSzFieldA (SETUPAPI.@) 2031 */ 2032BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, 2033 DWORD size, LPDWORD required ) 2034{ 2035 struct inf_file *file = context->CurrentInf; 2036 struct line *line = get_line( file, context->Section, context->Line ); 2037 struct field *field; 2038 unsigned int len; 2039 int i; 2040 DWORD total = 1; 2041 2042 if (!line) 2043 { 2044 SetLastError( ERROR_LINE_NOT_FOUND ); 2045 return FALSE; 2046 } 2047 if (!index || index > line->nb_fields) 2048 { 2049 SetLastError( ERROR_INVALID_PARAMETER ); 2050 return FALSE; 2051 } 2052 index--; /* fields start at 0 */ 2053 field = &file->fields[line->first_field + index]; 2054 for (i = index; i < line->nb_fields; i++, field++) 2055 { 2056 if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break; 2057 total += len + 1; 2058 } 2059 2060 if (required) *required = total; 2061 if (!buffer) return TRUE; 2062 if (total > size) 2063 { 2064 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 2065 return FALSE; 2066 } 2067 field = &file->fields[line->first_field + index]; 2068 for (i = index; i < line->nb_fields; i++, field++) 2069 { 2070 if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break; 2071 buffer += len + 1; 2072 } 2073 *buffer = 0; /* add final null */ 2074 return TRUE; 2075} 2076 2077 2078/*********************************************************************** 2079 * SetupGetMultiSzFieldW (SETUPAPI.@) 2080 */ 2081BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, 2082 DWORD size, LPDWORD required ) 2083{ 2084 struct inf_file *file = context->CurrentInf; 2085 struct line *line = get_line( file, context->Section, context->Line ); 2086 struct field *field; 2087 unsigned int len; 2088 int i; 2089 DWORD total = 1; 2090 2091 if (!line) 2092 { 2093 SetLastError( ERROR_LINE_NOT_FOUND ); 2094 return FALSE; 2095 } 2096 if (!index || index > line->nb_fields) 2097 { 2098 SetLastError( ERROR_INVALID_PARAMETER ); 2099 return FALSE; 2100 } 2101 index--; /* fields start at 0 */ 2102 field = &file->fields[line->first_field + index]; 2103 for (i = index; i < line->nb_fields; i++, field++) 2104 { 2105 if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break; 2106 total += len + 1; 2107 } 2108 2109 if (required) *required = total; 2110 if (!buffer) return TRUE; 2111 if (total > size) 2112 { 2113 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 2114 return FALSE; 2115 } 2116 field = &file->fields[line->first_field + index]; 2117 for (i = index; i < line->nb_fields; i++, field++) 2118 { 2119 if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break; 2120 buffer += len + 1; 2121 } 2122 *buffer = 0; /* add final null */ 2123 return TRUE; 2124} 2125 2126/*********************************************************************** 2127 * pSetupGetField (SETUPAPI.@) 2128 */ 2129LPCWSTR WINAPI pSetupGetField( PINFCONTEXT context, DWORD index ) 2130{ 2131 struct inf_file *file = context->CurrentInf; 2132 struct field *field = get_field( file, context->Section, context->Line, index ); 2133 2134 if (!field) 2135 { 2136 SetLastError( ERROR_INVALID_PARAMETER ); 2137 return NULL; 2138 } 2139 return field->text; 2140} 2141 2142/*********************************************************************** 2143 * SetupGetInfFileListW (SETUPAPI.@) 2144 */ 2145BOOL WINAPI 2146SetupGetInfFileListW( 2147 IN PCWSTR DirectoryPath OPTIONAL, 2148 IN DWORD InfStyle, 2149 IN OUT PWSTR ReturnBuffer OPTIONAL, 2150 IN DWORD ReturnBufferSize OPTIONAL, 2151 OUT PDWORD RequiredSize OPTIONAL) 2152{ 2153 HANDLE hSearch; 2154 LPWSTR pFullFileName = NULL; 2155 LPWSTR pFileName; /* Pointer into pFullFileName buffer */ 2156 LPWSTR pBuffer = ReturnBuffer; 2157 WIN32_FIND_DATAW wfdFileInfo; 2158 size_t len; 2159 DWORD requiredSize = 0; 2160 BOOL ret = FALSE; 2161 2162 TRACE("%s %lx %p %ld %p\n", debugstr_w(DirectoryPath), InfStyle, 2163 ReturnBuffer, ReturnBufferSize, RequiredSize); 2164 2165 if (InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)) 2166 { 2167 TRACE("Unknown flags: 0x%08lx\n", InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)); 2168 SetLastError(ERROR_INVALID_PARAMETER); 2169 goto cleanup; 2170 } 2171 else if (ReturnBufferSize == 0 && ReturnBuffer != NULL) 2172 { 2173 SetLastError(ERROR_INVALID_PARAMETER); 2174 goto cleanup; 2175 } 2176 else if (ReturnBufferSize > 0 && ReturnBuffer == NULL) 2177 { 2178 SetLastError(ERROR_INVALID_PARAMETER); 2179 goto cleanup; 2180 } 2181 2182 /* Allocate memory for file filter */ 2183 if (DirectoryPath != NULL) 2184 /* "DirectoryPath\" form */ 2185 len = strlenW(DirectoryPath) + 1 + 1; 2186 else 2187 /* "%SYSTEMROOT%\Inf\" form */ 2188 len = MAX_PATH + 1 + strlenW(InfDirectory) + 1; 2189 len += MAX_PATH; /* To contain file name or "*.inf" string */ 2190 pFullFileName = MyMalloc(len * sizeof(WCHAR)); 2191 if (pFullFileName == NULL) 2192 { 2193 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2194 goto cleanup; 2195 } 2196 2197 /* Fill file filter buffer */ 2198 if (DirectoryPath) 2199 { 2200 strcpyW(pFullFileName, DirectoryPath); 2201 if (*pFullFileName && pFullFileName[strlenW(pFullFileName) - 1] != '\\') 2202 strcatW(pFullFileName, BackSlash); 2203 } 2204 else 2205 { 2206 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH); 2207 if (len == 0 || len > MAX_PATH) 2208 goto cleanup; 2209 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\') 2210 strcatW(pFullFileName, BackSlash); 2211 strcatW(pFullFileName, InfDirectory); 2212 } 2213 pFileName = &pFullFileName[strlenW(pFullFileName)]; 2214 2215 /* Search for the first file */ 2216 strcpyW(pFileName, InfFileSpecification); 2217 hSearch = FindFirstFileW(pFullFileName, &wfdFileInfo); 2218 if (hSearch == INVALID_HANDLE_VALUE) 2219 { 2220 TRACE("No file returned by %s\n", debugstr_w(pFullFileName)); 2221 goto cleanup; 2222 } 2223 2224 do 2225 { 2226 HINF hInf; 2227 2228 strcpyW(pFileName, wfdFileInfo.cFileName); 2229 hInf = SetupOpenInfFileW( 2230 pFullFileName, 2231 NULL, /* Inf class */ 2232 InfStyle, 2233 NULL /* Error line */); 2234 if (hInf == INVALID_HANDLE_VALUE) 2235 { 2236 if (GetLastError() == ERROR_CLASS_MISMATCH) 2237 { 2238 /* InfStyle was not correct. Skip this file */ 2239 continue; 2240 } 2241 TRACE("Invalid .inf file %s\n", debugstr_w(pFullFileName)); 2242 continue; 2243 } 2244 2245 len = strlenW(wfdFileInfo.cFileName) + 1; 2246 requiredSize += (DWORD)len; 2247 if (requiredSize <= ReturnBufferSize) 2248 { 2249 strcpyW(pBuffer, wfdFileInfo.cFileName); 2250 pBuffer = &pBuffer[len]; 2251 } 2252 SetupCloseInfFile(hInf); 2253 } while (FindNextFileW(hSearch, &wfdFileInfo)); 2254 FindClose(hSearch); 2255 2256 requiredSize += 1; /* Final NULL char */ 2257 if (requiredSize <= ReturnBufferSize) 2258 { 2259 *pBuffer = '\0'; 2260 ret = TRUE; 2261 } 2262 else 2263 { 2264 SetLastError(ERROR_INSUFFICIENT_BUFFER); 2265 ret = FALSE; 2266 } 2267 if (RequiredSize) 2268 *RequiredSize = requiredSize; 2269 2270cleanup: 2271 MyFree(pFullFileName); 2272 return ret; 2273} 2274 2275/*********************************************************************** 2276 * SetupGetInfFileListA (SETUPAPI.@) 2277 */ 2278BOOL WINAPI 2279SetupGetInfFileListA( 2280 IN PCSTR DirectoryPath OPTIONAL, 2281 IN DWORD InfStyle, 2282 IN OUT PSTR ReturnBuffer OPTIONAL, 2283 IN DWORD ReturnBufferSize OPTIONAL, 2284 OUT PDWORD RequiredSize OPTIONAL) 2285{ 2286 PWSTR DirectoryPathW = NULL; 2287 PWSTR ReturnBufferW = NULL; 2288 BOOL ret = FALSE; 2289 2290 TRACE("%s %lx %p %ld %p\n", debugstr_a(DirectoryPath), InfStyle, 2291 ReturnBuffer, ReturnBufferSize, RequiredSize); 2292 2293 if (DirectoryPath != NULL) 2294 { 2295 DirectoryPathW = pSetupMultiByteToUnicode(DirectoryPath, CP_ACP); 2296 if (DirectoryPathW == NULL) goto Cleanup; 2297 } 2298 2299 if (ReturnBuffer != NULL && ReturnBufferSize != 0) 2300 { 2301 ReturnBufferW = MyMalloc(ReturnBufferSize * sizeof(WCHAR)); 2302 if (ReturnBufferW == NULL) goto Cleanup; 2303 } 2304 2305 ret = SetupGetInfFileListW(DirectoryPathW, InfStyle, ReturnBufferW, ReturnBufferSize, RequiredSize); 2306 2307 if (ret && ReturnBufferW != NULL) 2308 { 2309 ret = WideCharToMultiByte(CP_ACP, 0, ReturnBufferW, -1, ReturnBuffer, ReturnBufferSize, NULL, NULL) != 0; 2310 } 2311 2312Cleanup: 2313 MyFree(DirectoryPathW); 2314 MyFree(ReturnBufferW); 2315 2316 return ret; 2317} 2318 2319/*********************************************************************** 2320 * SetupDiGetINFClassW (SETUPAPI.@) 2321 */ 2322BOOL WINAPI 2323SetupDiGetINFClassW( 2324 IN PCWSTR InfName, 2325 OUT LPGUID ClassGuid, 2326 OUT PWSTR ClassName, 2327 IN DWORD ClassNameSize, 2328 OUT PDWORD RequiredSize OPTIONAL) 2329{ 2330 HINF hInf = INVALID_HANDLE_VALUE; 2331 BOOL ret = FALSE; 2332 2333 TRACE("%s %p %p %ld %p\n", debugstr_w(InfName), ClassGuid, 2334 ClassName, ClassNameSize, RequiredSize); 2335 2336 if (!InfName || !ClassGuid || !ClassName || ClassNameSize == 0) 2337 { 2338 SetLastError(ERROR_INVALID_PARAMETER); 2339 return FALSE; 2340 } 2341 2342 /* Open .inf file */ 2343 hInf = SetupOpenInfFileW(InfName, NULL, INF_STYLE_WIN4, NULL); 2344 if (hInf == INVALID_HANDLE_VALUE) 2345 goto cleanup; 2346 2347 ret = PARSER_GetInfClassW(hInf, ClassGuid, ClassName, ClassNameSize, RequiredSize); 2348 2349cleanup: 2350 if (hInf != INVALID_HANDLE_VALUE) 2351 SetupCloseInfFile(hInf); 2352 2353 TRACE("Returning %d\n", ret); 2354 return ret; 2355} 2356 2357/*********************************************************************** 2358 * SetupDiGetINFClassA (SETUPAPI.@) 2359 */ 2360BOOL WINAPI SetupDiGetINFClassA( 2361 IN PCSTR InfName, 2362 OUT LPGUID ClassGuid, 2363 OUT PSTR ClassName, 2364 IN DWORD ClassNameSize, 2365 OUT PDWORD RequiredSize OPTIONAL) 2366{ 2367 PWSTR InfNameW = NULL; 2368 PWSTR ClassNameW = NULL; 2369 BOOL ret = FALSE; 2370 2371 TRACE("%s %p %p %ld %p\n", debugstr_a(InfName), ClassGuid, 2372 ClassName, ClassNameSize, RequiredSize); 2373 2374 if (InfName != NULL) 2375 { 2376 InfNameW = pSetupMultiByteToUnicode(InfName, CP_ACP); 2377 if (InfNameW == NULL) goto Cleanup; 2378 } 2379 2380 if (ClassName != NULL && ClassNameSize != 0) 2381 { 2382 ClassNameW = MyMalloc(ClassNameSize * sizeof(WCHAR)); 2383 if (ClassNameW == NULL) goto Cleanup; 2384 } 2385 2386 ret = SetupDiGetINFClassW(InfNameW, ClassGuid, ClassNameW, ClassNameSize, RequiredSize); 2387 2388 if (ret && ClassNameW != NULL) 2389 { 2390 ret = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName, ClassNameSize, NULL, NULL) != 0; 2391 } 2392 2393Cleanup: 2394 MyFree(InfNameW); 2395 MyFree(ClassNameW); 2396 2397 return ret; 2398} 2399 2400BOOL EnumerateSectionsStartingWith( 2401 IN HINF hInf, 2402 IN LPCWSTR pStr, 2403 IN FIND_CALLBACK Callback, 2404 IN PVOID Context) 2405{ 2406 struct inf_file *file = (struct inf_file *)hInf; 2407 size_t len = strlenW(pStr); 2408 unsigned int i; 2409 2410 for (i = 0; i < file->nb_sections; i++) 2411 { 2412 if (strncmpiW(pStr, file->sections[i]->name, len) == 0) 2413 { 2414 if (!Callback(file->sections[i]->name, Context)) 2415 return FALSE; 2416 } 2417 } 2418 return TRUE; 2419}