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