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