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