Some more error checking...
[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 if (file != NULL)
1306 {
1307 for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] );
1308 HeapFree( GetProcessHeap(), 0, file->filename );
1309 HeapFree( GetProcessHeap(), 0, file->sections );
1310 HeapFree( GetProcessHeap(), 0, file->fields );
1311 HeapFree( GetProcessHeap(), 0, file->strings );
1312 HeapFree( GetProcessHeap(), 0, file );
1313 }
1314 }
1315
1316
1317 /***********************************************************************
1318 * SetupGetLineCountA (SETUPAPI.@)
1319 */
1320 LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name )
1321 {
1322 UNICODE_STRING sectionW;
1323 LONG ret = -1;
1324
1325 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, name ))
1326 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1327 else
1328 {
1329 ret = SetupGetLineCountW( hinf, sectionW.Buffer );
1330 RtlFreeUnicodeString( &sectionW );
1331 }
1332 return ret;
1333 }
1334
1335
1336 /***********************************************************************
1337 * SetupGetLineCountW (SETUPAPI.@)
1338 */
1339 LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section )
1340 {
1341 struct inf_file *file = hinf;
1342 int section_index;
1343 LONG ret = -1;
1344
1345 if (hinf == NULL || hinf == INVALID_HANDLE_VALUE)
1346 return ERROR_INVALID_PARAMETER;
1347
1348 for (file = hinf; file; file = file->next)
1349 {
1350 if ((section_index = find_section( file, section )) == -1) continue;
1351 if (ret == -1) ret = 0;
1352 ret += file->sections[section_index]->nb_lines;
1353 }
1354 TRACE( "(%p,%s) returning %ld\n", hinf, debugstr_w(section), ret );
1355 SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 );
1356 return ret;
1357 }
1358
1359
1360 /***********************************************************************
1361 * SetupGetLineByIndexA (SETUPAPI.@)
1362 */
1363 BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context )
1364 {
1365 UNICODE_STRING sectionW;
1366 BOOL ret = FALSE;
1367
1368 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1369 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1370 else
1371 {
1372 ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context );
1373 RtlFreeUnicodeString( &sectionW );
1374 }
1375 return ret;
1376 }
1377
1378
1379 /***********************************************************************
1380 * SetupGetLineByIndexW (SETUPAPI.@)
1381 */
1382 BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context )
1383 {
1384 struct inf_file *file = hinf;
1385 int section_index;
1386
1387 if (hinf == NULL || hinf == INVALID_HANDLE_VALUE)
1388 {
1389 SetLastError(ERROR_INVALID_PARAMETER);
1390 return FALSE;
1391 }
1392
1393 SetLastError( ERROR_SECTION_NOT_FOUND );
1394 for (file = hinf; file; file = file->next)
1395 {
1396 if ((section_index = find_section( file, section )) == -1) continue;
1397 SetLastError( ERROR_LINE_NOT_FOUND );
1398 if (index < file->sections[section_index]->nb_lines)
1399 {
1400 context->Inf = hinf;
1401 context->CurrentInf = file;
1402 context->Section = section_index;
1403 context->Line = index;
1404 SetLastError( 0 );
1405 TRACE( "(%p,%s): returning %d/%ld\n",
1406 hinf, debugstr_w(section), section_index, index );
1407 return TRUE;
1408 }
1409 index -= file->sections[section_index]->nb_lines;
1410 }
1411 TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) );
1412 return FALSE;
1413 }
1414
1415
1416 /***********************************************************************
1417 * SetupFindFirstLineA (SETUPAPI.@)
1418 */
1419 BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context )
1420 {
1421 UNICODE_STRING sectionW, keyW;
1422 BOOL ret = FALSE;
1423
1424 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1425 {
1426 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1427 return FALSE;
1428 }
1429
1430 if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context );
1431 else
1432 {
1433 if (RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1434 {
1435 ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context );
1436 RtlFreeUnicodeString( &keyW );
1437 }
1438 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1439 }
1440 RtlFreeUnicodeString( &sectionW );
1441 return ret;
1442 }
1443
1444
1445 /***********************************************************************
1446 * SetupFindFirstLineW (SETUPAPI.@)
1447 */
1448 BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context )
1449 {
1450 struct inf_file *file;
1451 int section_index;
1452
1453 if (hinf == NULL || hinf == INVALID_HANDLE_VALUE)
1454 {
1455 SetLastError(ERROR_INVALID_PARAMETER);
1456 return FALSE;
1457 }
1458
1459 SetLastError( ERROR_SECTION_NOT_FOUND );
1460 for (file = hinf; file; file = file->next)
1461 {
1462 if ((section_index = find_section( file, section )) == -1) continue;
1463 if (key)
1464 {
1465 INFCONTEXT ctx;
1466 ctx.Inf = hinf;
1467 ctx.CurrentInf = file;
1468 ctx.Section = section_index;
1469 ctx.Line = -1;
1470 return SetupFindNextMatchLineW( &ctx, key, context );
1471 }
1472 SetLastError( ERROR_LINE_NOT_FOUND ); /* found at least one section */
1473 if (file->sections[section_index]->nb_lines)
1474 {
1475 context->Inf = hinf;
1476 context->CurrentInf = file;
1477 context->Section = section_index;
1478 context->Line = 0;
1479 SetLastError( 0 );
1480 TRACE( "(%p,%s,%s): returning %d/0\n",
1481 hinf, debugstr_w(section), debugstr_w(key), section_index );
1482 return TRUE;
1483 }
1484 }
1485 TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) );
1486 return FALSE;
1487 }
1488
1489
1490 /***********************************************************************
1491 * SetupFindNextLine (SETUPAPI.@)
1492 */
1493 BOOL WINAPI SetupFindNextLine( PINFCONTEXT context_in, PINFCONTEXT context_out )
1494 {
1495 struct inf_file *file = context_in->CurrentInf;
1496 struct section *section;
1497
1498 if (context_in->Section >= file->nb_sections) goto error;
1499
1500 section = file->sections[context_in->Section];
1501 if (context_in->Line+1 < section->nb_lines)
1502 {
1503 if (context_out != context_in) *context_out = *context_in;
1504 context_out->Line++;
1505 SetLastError( 0 );
1506 return TRUE;
1507 }
1508
1509 /* now search the appended files */
1510
1511 for (file = file->next; file; file = file->next)
1512 {
1513 int section_index = find_section( file, section->name );
1514 if (section_index == -1) continue;
1515 if (file->sections[section_index]->nb_lines)
1516 {
1517 context_out->Inf = context_in->Inf;
1518 context_out->CurrentInf = file;
1519 context_out->Section = section_index;
1520 context_out->Line = 0;
1521 SetLastError( 0 );
1522 return TRUE;
1523 }
1524 }
1525 error:
1526 SetLastError( ERROR_LINE_NOT_FOUND );
1527 return FALSE;
1528 }
1529
1530
1531 /***********************************************************************
1532 * SetupFindNextMatchLineA (SETUPAPI.@)
1533 */
1534 BOOL WINAPI SetupFindNextMatchLineA( PINFCONTEXT context_in, PCSTR key,
1535 PINFCONTEXT context_out )
1536 {
1537 UNICODE_STRING keyW;
1538 BOOL ret = FALSE;
1539
1540 if (!key) return SetupFindNextLine( context_in, context_out );
1541
1542 if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1543 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1544 else
1545 {
1546 ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out );
1547 RtlFreeUnicodeString( &keyW );
1548 }
1549 return ret;
1550 }
1551
1552
1553 /***********************************************************************
1554 * SetupFindNextMatchLineW (SETUPAPI.@)
1555 */
1556 BOOL WINAPI SetupFindNextMatchLineW( PINFCONTEXT context_in, PCWSTR key,
1557 PINFCONTEXT context_out )
1558 {
1559 struct inf_file *file = context_in->CurrentInf;
1560 struct section *section;
1561 struct line *line;
1562 unsigned int i;
1563
1564 if (!key) return SetupFindNextLine( context_in, context_out );
1565
1566 if (context_in->Section >= file->nb_sections) goto error;
1567
1568 section = file->sections[context_in->Section];
1569
1570 for (i = context_in->Line+1, line = &section->lines[i]; i < section->nb_lines; i++, line++)
1571 {
1572 if (line->key_field == -1) continue;
1573 if (!strcmpiW( key, file->fields[line->key_field].text ))
1574 {
1575 if (context_out != context_in) *context_out = *context_in;
1576 context_out->Line = i;
1577 SetLastError( 0 );
1578 TRACE( "(%p,%s,%s): returning %d\n",
1579 file, debugstr_w(section->name), debugstr_w(key), i );
1580 return TRUE;
1581 }
1582 }
1583
1584 /* now search the appended files */
1585
1586 for (file = file->next; file; file = file->next)
1587 {
1588 int section_index = find_section( file, section->name );
1589 if (section_index == -1) continue;
1590 section = file->sections[section_index];
1591 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
1592 {
1593 if (line->key_field == -1) continue;
1594 if (!strcmpiW( key, file->fields[line->key_field].text ))
1595 {
1596 context_out->Inf = context_in->Inf;
1597 context_out->CurrentInf = file;
1598 context_out->Section = section_index;
1599 context_out->Line = i;
1600 SetLastError( 0 );
1601 TRACE( "(%p,%s,%s): returning %d/%d\n",
1602 file, debugstr_w(section->name), debugstr_w(key), section_index, i );
1603 return TRUE;
1604 }
1605 }
1606 }
1607 TRACE( "(%p,%s,%s): not found\n",
1608 context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) );
1609 error:
1610 SetLastError( ERROR_LINE_NOT_FOUND );
1611 return FALSE;
1612 }
1613
1614
1615 /***********************************************************************
1616 * SetupGetLineTextW (SETUPAPI.@)
1617 */
1618 BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_name,
1619 PCWSTR key_name, PWSTR buffer, DWORD size, PDWORD required )
1620 {
1621 struct inf_file *file;
1622 struct line *line;
1623 struct field *field;
1624 int i;
1625 DWORD total = 0;
1626
1627 if (!context)
1628 {
1629 INFCONTEXT new_context;
1630 if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE;
1631 file = new_context.CurrentInf;
1632 line = get_line( file, new_context.Section, new_context.Line );
1633 }
1634 else
1635 {
1636 file = context->CurrentInf;
1637 if (!(line = get_line( file, context->Section, context->Line )))
1638 {
1639 SetLastError( ERROR_LINE_NOT_FOUND );
1640 return FALSE;
1641 }
1642 }
1643
1644 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1645 total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1;
1646
1647 if (required) *required = total;
1648 if (buffer)
1649 {
1650 if (total > size)
1651 {
1652 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1653 return FALSE;
1654 }
1655 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1656 {
1657 unsigned int len = PARSER_string_substW( file, field->text, buffer, size );
1658 if (i+1 < line->nb_fields) buffer[len] = ',';
1659 buffer += len + 1;
1660 }
1661 }
1662 return TRUE;
1663 }
1664
1665
1666 /***********************************************************************
1667 * SetupGetLineTextA (SETUPAPI.@)
1668 */
1669 BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_name,
1670 PCSTR key_name, PSTR buffer, DWORD size, PDWORD required )
1671 {
1672 struct inf_file *file;
1673 struct line *line;
1674 struct field *field;
1675 int i;
1676 DWORD total = 0;
1677
1678 if (!context)
1679 {
1680 INFCONTEXT new_context;
1681 if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE;
1682 file = new_context.CurrentInf;
1683 line = get_line( file, new_context.Section, new_context.Line );
1684 }
1685 else
1686 {
1687 file = context->CurrentInf;
1688 if (!(line = get_line( file, context->Section, context->Line )))
1689 {
1690 SetLastError( ERROR_LINE_NOT_FOUND );
1691 return FALSE;
1692 }
1693 }
1694
1695 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1696 total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1;
1697
1698 if (required) *required = total;
1699 if (buffer)
1700 {
1701 if (total > size)
1702 {
1703 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1704 return FALSE;
1705 }
1706 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1707 {
1708 unsigned int len = PARSER_string_substA( file, field->text, buffer, size );
1709 if (i+1 < line->nb_fields) buffer[len] = ',';
1710 buffer += len + 1;
1711 }
1712 }
1713 return TRUE;
1714 }
1715
1716
1717 /***********************************************************************
1718 * SetupGetFieldCount (SETUPAPI.@)
1719 */
1720 DWORD WINAPI SetupGetFieldCount( PINFCONTEXT context )
1721 {
1722 struct inf_file *file = context->CurrentInf;
1723 struct line *line = get_line( file, context->Section, context->Line );
1724
1725 if (!line) return 0;
1726 return line->nb_fields;
1727 }
1728
1729
1730 /***********************************************************************
1731 * SetupGetStringFieldA (SETUPAPI.@)
1732 */
1733 BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer,
1734 DWORD size, PDWORD required )
1735 {
1736 struct inf_file *file = context->CurrentInf;
1737 struct field *field = get_field( file, context->Section, context->Line, index );
1738 unsigned int len;
1739
1740 SetLastError(0);
1741 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
1742 len = PARSER_string_substA( file, field->text, NULL, 0 );
1743 if (required) *required = len + 1;
1744 if (buffer)
1745 {
1746 if (size <= len)
1747 {
1748 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1749 return FALSE;
1750 }
1751 PARSER_string_substA( file, field->text, buffer, size );
1752
1753 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1754 context->Inf, context->CurrentInf, context->Section, context->Line,
1755 index, debugstr_a(buffer) );
1756 }
1757 return TRUE;
1758 }
1759
1760
1761 /***********************************************************************
1762 * SetupGetStringFieldW (SETUPAPI.@)
1763 */
1764 BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer,
1765 DWORD size, PDWORD required )
1766 {
1767 struct inf_file *file = context->CurrentInf;
1768 struct field *field = get_field( file, context->Section, context->Line, index );
1769 unsigned int len;
1770
1771 SetLastError(0);
1772 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
1773 len = PARSER_string_substW( file, field->text, NULL, 0 );
1774 if (required) *required = len + 1;
1775 if (buffer)
1776 {
1777 if (size <= len)
1778 {
1779 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1780 return FALSE;
1781 }
1782 PARSER_string_substW( file, field->text, buffer, size );
1783
1784 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1785 context->Inf, context->CurrentInf, context->Section, context->Line,
1786 index, debugstr_w(buffer) );
1787 }
1788 return TRUE;
1789 }
1790
1791
1792 /***********************************************************************
1793 * SetupGetIntField (SETUPAPI.@)
1794 */
1795 BOOL WINAPI SetupGetIntField( PINFCONTEXT context, DWORD index, PINT result )
1796 {
1797 char localbuff[20];
1798 char *end, *buffer = localbuff;
1799 DWORD required;
1800 INT res;
1801 BOOL ret = FALSE;
1802
1803 if (!SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required ))
1804 {
1805 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
1806 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE;
1807 if (!SetupGetStringFieldA( context, index, buffer, required, NULL )) goto done;
1808 }
1809 res = strtol( buffer, &end, 0 );
1810 if (end != buffer && !*end)
1811 {
1812 *result = res;
1813 ret = TRUE;
1814 }
1815 else SetLastError( ERROR_INVALID_DATA );
1816
1817 done:
1818 if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer );
1819 return ret;
1820 }
1821
1822
1823 /***********************************************************************
1824 * SetupGetBinaryField (SETUPAPI.@)
1825 */
1826 BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer,
1827 DWORD size, LPDWORD required )
1828 {
1829 struct inf_file *file = context->CurrentInf;
1830 struct line *line = get_line( file, context->Section, context->Line );
1831 struct field *field;
1832 int i;
1833
1834 if (!line)
1835 {
1836 SetLastError( ERROR_LINE_NOT_FOUND );
1837 return FALSE;
1838 }
1839 if (!index || index > line->nb_fields)
1840 {
1841 SetLastError( ERROR_INVALID_PARAMETER );
1842 return FALSE;
1843 }
1844 index--; /* fields start at 0 */
1845 if (required) *required = line->nb_fields - index;
1846 if (!buffer) return TRUE;
1847 if (size < line->nb_fields - index)
1848 {
1849 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1850 return FALSE;
1851 }
1852 field = &file->fields[line->first_field + index];
1853 for (i = index; i < line->nb_fields; i++, field++)
1854 {
1855 const WCHAR *p;
1856 DWORD value = 0;
1857 for (p = field->text; *p && isxdigitW(*p); p++)
1858 {
1859 if ((value <<= 4) > 255)
1860 {
1861 SetLastError( ERROR_INVALID_DATA );
1862 return FALSE;
1863 }
1864 if (*p <= '9') value |= (*p - '0');
1865 else value |= (tolowerW(*p) - 'a' + 10);
1866 }
1867 buffer[i - index] = value;
1868 }
1869 if (TRACE_ON(setupapi))
1870 {
1871 TRACE( "%p/%p/%d/%d index %ld returning",
1872 context->Inf, context->CurrentInf, context->Section, context->Line, index );
1873 for (i = index; i < line->nb_fields; i++) TRACE( " %02x", buffer[i - index] );
1874 TRACE( "\n" );
1875 }
1876 return TRUE;
1877 }
1878
1879
1880 /***********************************************************************
1881 * SetupGetMultiSzFieldA (SETUPAPI.@)
1882 */
1883 BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer,
1884 DWORD size, LPDWORD required )
1885 {
1886 struct inf_file *file = context->CurrentInf;
1887 struct line *line = get_line( file, context->Section, context->Line );
1888 struct field *field;
1889 unsigned int len;
1890 int i;
1891 DWORD total = 1;
1892
1893 if (!line)
1894 {
1895 SetLastError( ERROR_LINE_NOT_FOUND );
1896 return FALSE;
1897 }
1898 if (!index || index > line->nb_fields)
1899 {
1900 SetLastError( ERROR_INVALID_PARAMETER );
1901 return FALSE;
1902 }
1903 index--; /* fields start at 0 */
1904 field = &file->fields[line->first_field + index];
1905 for (i = index; i < line->nb_fields; i++, field++)
1906 {
1907 if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break;
1908 total += len + 1;
1909 }
1910
1911 if (required) *required = total;
1912 if (!buffer) return TRUE;
1913 if (total > size)
1914 {
1915 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1916 return FALSE;
1917 }
1918 field = &file->fields[line->first_field + index];
1919 for (i = index; i < line->nb_fields; i++, field++)
1920 {
1921 if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break;
1922 buffer += len + 1;
1923 }
1924 *buffer = 0; /* add final null */
1925 return TRUE;
1926 }
1927
1928
1929 /***********************************************************************
1930 * SetupGetMultiSzFieldW (SETUPAPI.@)
1931 */
1932 BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer,
1933 DWORD size, LPDWORD required )
1934 {
1935 struct inf_file *file = context->CurrentInf;
1936 struct line *line = get_line( file, context->Section, context->Line );
1937 struct field *field;
1938 unsigned int len;
1939 int i;
1940 DWORD total = 1;
1941
1942 if (!line)
1943 {
1944 SetLastError( ERROR_LINE_NOT_FOUND );
1945 return FALSE;
1946 }
1947 if (!index || index > line->nb_fields)
1948 {
1949 SetLastError( ERROR_INVALID_PARAMETER );
1950 return FALSE;
1951 }
1952 index--; /* fields start at 0 */
1953 field = &file->fields[line->first_field + index];
1954 for (i = index; i < line->nb_fields; i++, field++)
1955 {
1956 if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break;
1957 total += len + 1;
1958 }
1959
1960 if (required) *required = total;
1961 if (!buffer) return TRUE;
1962 if (total > size)
1963 {
1964 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1965 return FALSE;
1966 }
1967 field = &file->fields[line->first_field + index];
1968 for (i = index; i < line->nb_fields; i++, field++)
1969 {
1970 if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break;
1971 buffer += len + 1;
1972 }
1973 *buffer = 0; /* add final null */
1974 return TRUE;
1975 }
1976
1977 /***********************************************************************
1978 * SetupGetInfFileListW (SETUPAPI.@)
1979 */
1980 BOOL WINAPI
1981 SetupGetInfFileListW(
1982 IN PCWSTR DirectoryPath OPTIONAL,
1983 IN DWORD InfStyle,
1984 IN OUT PWSTR ReturnBuffer OPTIONAL,
1985 IN DWORD ReturnBufferSize OPTIONAL,
1986 OUT PDWORD RequiredSize OPTIONAL)
1987 {
1988 HANDLE hSearch;
1989 LPWSTR pFullFileName = NULL;
1990 LPWSTR pFileName; /* Pointer into pFullFileName buffer */
1991 LPWSTR pBuffer = ReturnBuffer;
1992 WIN32_FIND_DATAW wfdFileInfo;
1993 size_t len;
1994 DWORD requiredSize = 0;
1995 BOOL ret = FALSE;
1996
1997 TRACE("%s %lx %p %ld %p\n", debugstr_w(DirectoryPath), InfStyle,
1998 ReturnBuffer, ReturnBufferSize, RequiredSize);
1999
2000 if (InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4))
2001 {
2002 TRACE("Unknown flags: 0x%08lx\n", InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4));
2003 SetLastError(ERROR_INVALID_PARAMETER);
2004 goto cleanup;
2005 }
2006 else if (ReturnBufferSize == 0 && ReturnBuffer != NULL)
2007 {
2008 SetLastError(ERROR_INVALID_PARAMETER);
2009 goto cleanup;
2010 }
2011 else if (ReturnBufferSize > 0 && ReturnBuffer == NULL)
2012 {
2013 SetLastError(ERROR_INVALID_PARAMETER);
2014 goto cleanup;
2015 }
2016
2017 /* Allocate memory for file filter */
2018 if (DirectoryPath != NULL)
2019 /* "DirectoryPath\" form */
2020 len = strlenW(DirectoryPath) + 1 + 1;
2021 else
2022 /* "%WINDIR%\Inf\" form */
2023 len = MAX_PATH + 1 + strlenW(InfDirectory) + 1;
2024 len += MAX_PATH; /* To contain file name or "*.inf" string */
2025 pFullFileName = MyMalloc(len * sizeof(WCHAR));
2026 if (pFullFileName == NULL)
2027 {
2028 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2029 goto cleanup;
2030 }
2031
2032 /* Fill file filter buffer */
2033 if (DirectoryPath)
2034 {
2035 strcpyW(pFullFileName, DirectoryPath);
2036 if (*pFullFileName && pFullFileName[strlenW(pFullFileName) - 1] != '\\')
2037 strcatW(pFullFileName, BackSlash);
2038 }
2039 else
2040 {
2041 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH);
2042 if (len == 0 || len > MAX_PATH)
2043 goto cleanup;
2044 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\')
2045 strcatW(pFullFileName, BackSlash);
2046 strcatW(pFullFileName, InfDirectory);
2047 }
2048 pFileName = &pFullFileName[strlenW(pFullFileName)];
2049
2050 /* Search for the first file */
2051 strcpyW(pFileName, InfFileSpecification);
2052 hSearch = FindFirstFileW(pFullFileName, &wfdFileInfo);
2053 if (hSearch == INVALID_HANDLE_VALUE)
2054 {
2055 TRACE("No file returned by %s\n", debugstr_w(pFullFileName));
2056 goto cleanup;
2057 }
2058
2059 do
2060 {
2061 HINF hInf;
2062
2063 strcpyW(pFileName, wfdFileInfo.cFileName);
2064 hInf = SetupOpenInfFileW(
2065 pFullFileName,
2066 NULL, /* Inf class */
2067 InfStyle,
2068 NULL /* Error line */);
2069 if (hInf == INVALID_HANDLE_VALUE)
2070 {
2071 if (GetLastError() == ERROR_CLASS_MISMATCH)
2072 {
2073 /* InfStyle was not correct. Skip this file */
2074 continue;
2075 }
2076 TRACE("Invalid .inf file %s\n", debugstr_w(pFullFileName));
2077 continue;
2078 }
2079
2080 len = strlenW(wfdFileInfo.cFileName) + 1;
2081 requiredSize += (DWORD)(len * sizeof(WCHAR));
2082 if (requiredSize <= ReturnBufferSize)
2083 {
2084 strcpyW(pBuffer, wfdFileInfo.cFileName);
2085 pBuffer = &pBuffer[len];
2086 }
2087 SetupCloseInfFile(hInf);
2088 } while (FindNextFileW(hSearch, &wfdFileInfo));
2089 FindClose(hSearch);
2090
2091 requiredSize += sizeof(WCHAR); /* Final NULL char */
2092 if (requiredSize <= ReturnBufferSize)
2093 {
2094 *pBuffer = '\0';
2095 ret = TRUE;
2096 }
2097 else
2098 {
2099 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2100 ret = FALSE;
2101 }
2102 if (RequiredSize)
2103 *RequiredSize = requiredSize;
2104
2105 cleanup:
2106 MyFree(pFullFileName);
2107 return ret;
2108 }
2109
2110 /***********************************************************************
2111 * SetupGetInfFileListA (SETUPAPI.@)
2112 */
2113 BOOL WINAPI
2114 SetupGetInfFileListA(
2115 IN PCSTR DirectoryPath OPTIONAL,
2116 IN DWORD InfStyle,
2117 IN OUT PSTR ReturnBuffer OPTIONAL,
2118 IN DWORD ReturnBufferSize OPTIONAL,
2119 OUT PDWORD RequiredSize OPTIONAL)
2120 {
2121 PWSTR DirectoryPathW = NULL;
2122 PWSTR ReturnBufferW = NULL;
2123 BOOL ret = FALSE;
2124
2125 TRACE("%s %lx %p %ld %p\n", debugstr_a(DirectoryPath), InfStyle,
2126 ReturnBuffer, ReturnBufferSize, RequiredSize);
2127
2128 if (DirectoryPath != NULL)
2129 {
2130 DirectoryPathW = MultiByteToUnicode(DirectoryPath, CP_ACP);
2131 if (DirectoryPathW == NULL) goto Cleanup;
2132 }
2133
2134 if (ReturnBuffer != NULL && ReturnBufferSize != 0)
2135 {
2136 ReturnBufferW = MyMalloc(ReturnBufferSize * sizeof(WCHAR));
2137 if (ReturnBufferW == NULL) goto Cleanup;
2138 }
2139
2140 ret = SetupGetInfFileListW(DirectoryPathW, InfStyle, ReturnBufferW, ReturnBufferSize, RequiredSize);
2141
2142 if (ret && ReturnBufferW != NULL)
2143 {
2144 ret = WideCharToMultiByte(CP_ACP, 0, ReturnBufferW, -1, ReturnBuffer, ReturnBufferSize, NULL, NULL) != 0;
2145 }
2146
2147 Cleanup:
2148 if (DirectoryPathW != NULL)
2149 MyFree(DirectoryPathW);
2150 if (ReturnBufferW != NULL)
2151 MyFree(ReturnBufferW);
2152
2153 return ret;
2154 }
2155
2156 /***********************************************************************
2157 * SetupDiGetINFClassW (SETUPAPI.@)
2158 */
2159 BOOL WINAPI
2160 SetupDiGetINFClassW(
2161 IN PCWSTR InfName,
2162 OUT LPGUID ClassGuid,
2163 OUT PWSTR ClassName,
2164 IN DWORD ClassNameSize,
2165 OUT PDWORD RequiredSize OPTIONAL)
2166 {
2167 HINF hInf = INVALID_HANDLE_VALUE;
2168 BOOL ret = FALSE;
2169
2170 TRACE("%s %p %p %ld %p\n", debugstr_w(InfName), ClassGuid,
2171 ClassName, ClassNameSize, RequiredSize);
2172
2173 /* Open .inf file */
2174 hInf = SetupOpenInfFileW(InfName, NULL, INF_STYLE_WIN4, NULL);
2175 if (hInf == INVALID_HANDLE_VALUE)
2176 goto cleanup;
2177
2178 ret = GetInfClassW(hInf, ClassGuid, ClassName, ClassNameSize, RequiredSize);
2179
2180 cleanup:
2181 if (hInf != INVALID_HANDLE_VALUE)
2182 SetupCloseInfFile(hInf);
2183
2184 TRACE("Returning %d\n", ret);
2185 return ret;
2186 }
2187
2188 /***********************************************************************
2189 * SetupDiGetINFClassA (SETUPAPI.@)
2190 */
2191 BOOL WINAPI SetupDiGetINFClassA(
2192 IN PCSTR InfName,
2193 OUT LPGUID ClassGuid,
2194 OUT PSTR ClassName,
2195 IN DWORD ClassNameSize,
2196 OUT PDWORD RequiredSize OPTIONAL)
2197 {
2198 PWSTR InfNameW = NULL;
2199 PWSTR ClassNameW = NULL;
2200 BOOL ret = FALSE;
2201
2202 TRACE("%s %p %p %ld %p\n", debugstr_a(InfName), ClassGuid,
2203 ClassName, ClassNameSize, RequiredSize);
2204
2205 if (InfName != NULL)
2206 {
2207 InfNameW = MultiByteToUnicode(InfName, CP_ACP);
2208 if (InfNameW == NULL) goto Cleanup;
2209 }
2210
2211 if (ClassName != NULL && ClassNameSize != 0)
2212 {
2213 ClassNameW = MyMalloc(ClassNameSize * sizeof(WCHAR));
2214 if (ClassNameW == NULL) goto Cleanup;
2215 }
2216
2217 ret = SetupDiGetINFClassW(InfNameW, ClassGuid, ClassNameW, ClassNameSize, RequiredSize);
2218
2219 if (ret && ClassNameW != NULL)
2220 {
2221 ret = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName, ClassNameSize, NULL, NULL) != 0;
2222 }
2223
2224 Cleanup:
2225 if (InfNameW != NULL)
2226 MyFree(InfNameW);
2227 if (ClassNameW != NULL)
2228 MyFree(ClassNameW);
2229
2230 return ret;
2231 }