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