Initialize Xlib threading support to see what it breaks...
[wine.git] / dlls / setupapi / parser.c
blob9369f21011e3636939c8fb3549796f9f50ad7c25
1 /*
2 * INF file parsing
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <limits.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "winternl.h"
37 #include "winerror.h"
38 #include "setupapi.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
45 #define CONTROL_Z '\x1a'
46 #define MAX_SECTION_NAME_LEN 255
47 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
48 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
49 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
51 /* inf file structure definitions */
53 struct field
55 const WCHAR *text; /* field text */
58 struct line
60 int first_field; /* index of first field in field array */
61 int nb_fields; /* number of fields in line */
62 int key_field; /* index of field for key or -1 if no key */
65 struct section
67 const WCHAR *name; /* section name */
68 unsigned int nb_lines; /* number of used lines */
69 unsigned int alloc_lines; /* total number of allocated lines in array below */
70 struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */
73 struct inf_file
75 struct inf_file *next; /* next appended file */
76 WCHAR *strings; /* buffer for string data (section names and field values) */
77 WCHAR *string_pos; /* position of next available string in buffer */
78 unsigned int nb_sections; /* number of used sections */
79 unsigned int alloc_sections; /* total number of allocated section pointers */
80 struct section **sections; /* section pointers array */
81 unsigned int nb_fields;
82 unsigned int alloc_fields;
83 struct field *fields;
84 int strings_section; /* index of [Strings] section or -1 if none */
85 WCHAR *src_root; /* source root directory */
88 /* parser definitions */
90 enum parser_state
92 LINE_START, /* at beginning of a line */
93 SECTION_NAME, /* parsing a section name */
94 KEY_NAME, /* parsing a key name */
95 VALUE_NAME, /* parsing a value name */
96 EOL_BACKSLASH, /* backslash at end of line */
97 QUOTES, /* inside quotes */
98 LEADING_SPACES, /* leading spaces */
99 TRAILING_SPACES, /* trailing spaces */
100 COMMENT, /* inside a comment */
101 NB_PARSER_STATES
104 struct parser
106 const WCHAR *start; /* start position of item being parsed */
107 const WCHAR *end; /* end of buffer */
108 struct inf_file *file; /* file being built */
109 enum parser_state state; /* current parser state */
110 enum parser_state stack[4]; /* state stack */
111 int stack_pos; /* current pos in stack */
113 int cur_section; /* index of section being parsed*/
114 struct line *line; /* current line */
115 unsigned int line_pos; /* current line position in file */
116 unsigned int error; /* error code */
117 unsigned int token_len; /* current token len */
118 WCHAR token[MAX_FIELD_LEN+1]; /* current token */
121 typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos );
123 /* parser state machine functions */
124 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos );
125 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos );
126 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos );
127 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos );
128 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos );
129 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos );
130 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos );
131 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos );
132 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos );
134 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
136 line_start_state, /* LINE_START */
137 section_name_state, /* SECTION_NAME */
138 key_name_state, /* KEY_NAME */
139 value_name_state, /* VALUE_NAME */
140 eol_backslash_state, /* EOL_BACKSLASH */
141 quotes_state, /* QUOTES */
142 leading_spaces_state, /* LEADING_SPACES */
143 trailing_spaces_state, /* TRAILING_SPACES */
144 comment_state /* COMMENT */
148 /* Unicode string constants */
149 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
150 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
151 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
152 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
153 static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
154 static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0};
156 /* extend an array, allocating more memory if necessary */
157 static void *grow_array( void *array, unsigned int *count, size_t elem )
159 void *new_array;
160 unsigned int new_count = *count + *count / 2;
161 if (new_count < 32) new_count = 32;
163 if (array)
164 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, array, new_count * elem );
165 else
166 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * elem );
168 if (new_array)
169 *count = new_count;
170 else
171 if (array)
172 HeapFree( GetProcessHeap(), 0, array );
173 return new_array;
177 /* find a section by name */
178 static int find_section( struct inf_file *file, const WCHAR *name )
180 int i;
182 for (i = 0; i < file->nb_sections; i++)
183 if (!strcmpiW( name, file->sections[i]->name )) return i;
184 return -1;
188 /* find a line by name */
189 static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name )
191 struct section *section;
192 struct line *line;
193 int i;
195 if (section_index < 0 || section_index >= file->nb_sections) return NULL;
196 section = file->sections[section_index];
197 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
199 if (line->key_field == -1) continue;
200 if (!strcmpiW( name, file->fields[line->key_field].text )) return line;
202 return NULL;
206 /* add a section to the file and return the section index */
207 static int add_section( struct inf_file *file, const WCHAR *name )
209 struct section *section;
211 if (file->nb_sections >= file->alloc_sections)
213 if (!(file->sections = grow_array( file->sections, &file->alloc_sections,
214 sizeof(file->sections[0]) ))) return -1;
216 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ))) return -1;
217 section->name = name;
218 section->nb_lines = 0;
219 section->alloc_lines = sizeof(section->lines)/sizeof(section->lines[0]);
220 file->sections[file->nb_sections] = section;
221 return file->nb_sections++;
225 /* add a line to a given section */
226 static struct line *add_line( struct inf_file *file, int section_index )
228 struct section *section;
229 struct line *line;
231 assert( section_index >= 0 && section_index < file->nb_sections );
233 section = file->sections[section_index];
234 if (section->nb_lines == section->alloc_lines) /* need to grow the section */
236 int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line);
237 if (!(section = HeapReAlloc( GetProcessHeap(), 0, section, size ))) return NULL;
238 section->alloc_lines *= 2;
239 file->sections[section_index] = section;
241 line = &section->lines[section->nb_lines++];
242 line->first_field = file->nb_fields;
243 line->nb_fields = 0;
244 line->key_field = -1;
245 return line;
249 /* retrieve a given line from section/line index */
250 inline static struct line *get_line( struct inf_file *file, unsigned int section_index,
251 unsigned int line_index )
253 struct section *section;
255 if (section_index >= file->nb_sections) return NULL;
256 section = file->sections[section_index];
257 if (line_index >= section->nb_lines) return NULL;
258 return &section->lines[line_index];
262 /* retrieve a given field from section/line/field index */
263 static struct field *get_field( struct inf_file *file, int section_index, int line_index,
264 int field_index )
266 struct line *line = get_line( file, section_index, line_index );
268 if (!line) return NULL;
269 if (!field_index) /* get the key */
271 if (line->key_field == -1) return NULL;
272 return &file->fields[line->key_field];
274 field_index--;
275 if (field_index >= line->nb_fields) return NULL;
276 return &file->fields[line->first_field + field_index];
280 /* allocate a new field, growing the array if necessary */
281 static struct field *add_field( struct inf_file *file, const WCHAR *text )
283 struct field *field;
285 if (file->nb_fields >= file->alloc_fields)
287 if (!(file->fields = grow_array( file->fields, &file->alloc_fields,
288 sizeof(file->fields[0]) ))) return NULL;
290 field = &file->fields[file->nb_fields++];
291 field->text = text;
292 return field;
296 /* retrieve the string substitution for a directory id */
297 static const WCHAR *get_dirid_subst( int dirid, unsigned int *len )
299 extern const WCHAR *DIRID_get_string( HINF hinf, int dirid );
300 const WCHAR *ret = DIRID_get_string( 0, dirid );
301 if (ret) *len = strlenW(ret);
302 return ret;
306 /* retrieve the string substitution for a given string, or NULL if not found */
307 /* if found, len is set to the substitution length */
308 static const WCHAR *get_string_subst( struct inf_file *file, const WCHAR *str, unsigned int *len )
310 static const WCHAR percent = '%';
312 struct section *strings_section;
313 struct line *line;
314 struct field *field;
315 int i, dirid;
316 WCHAR *dirid_str, *end;
317 const WCHAR *ret = NULL;
319 if (!*len) /* empty string (%%) is replaced by single percent */
321 *len = 1;
322 return &percent;
324 if (file->strings_section == -1) goto not_found;
325 strings_section = file->sections[file->strings_section];
326 for (i = 0, line = strings_section->lines; i < strings_section->nb_lines; i++, line++)
328 if (line->key_field == -1) continue;
329 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue;
330 if (!file->fields[line->key_field].text[*len]) break;
332 if (i == strings_section->nb_lines || !line->nb_fields) goto not_found;
333 field = &file->fields[line->first_field];
334 *len = strlenW( field->text );
335 return field->text;
337 not_found: /* check for integer id */
338 if ((dirid_str = HeapAlloc( GetProcessHeap(), 0, (*len+1) * sizeof(WCHAR) )))
340 memcpy( dirid_str, str, *len * sizeof(WCHAR) );
341 dirid_str[*len] = 0;
342 dirid = strtolW( dirid_str, &end, 10 );
343 if (!*end) ret = get_dirid_subst( dirid, len );
344 HeapFree( GetProcessHeap(), 0, dirid_str );
345 return ret;
347 return NULL;
351 /* do string substitutions on the specified text */
352 /* the buffer is assumed to be large enough */
353 /* returns necessary length not including terminating null */
354 unsigned int PARSER_string_substW( struct inf_file *file, const WCHAR *text, WCHAR *buffer,
355 unsigned int size )
357 const WCHAR *start, *subst, *p;
358 unsigned int len, total = 0;
359 int inside = 0;
361 if (!buffer) size = MAX_STRING_LEN + 1;
362 for (p = start = text; *p; p++)
364 if (*p != '%') continue;
365 inside = !inside;
366 if (inside) /* start of a %xx% string */
368 len = p - start;
369 if (len > size - 1) len = size - 1;
370 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
371 total += len;
372 size -= len;
373 start = p;
375 else /* end of the %xx% string, find substitution */
377 len = p - start - 1;
378 subst = get_string_subst( file, start + 1, &len );
379 if (!subst)
381 subst = start;
382 len = p - start + 1;
384 if (len > size - 1) len = size - 1;
385 if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) );
386 total += len;
387 size -= len;
388 start = p + 1;
392 if (start != p) /* unfinished string, copy it */
394 len = p - start;
395 if (len > size - 1) len = size - 1;
396 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
397 total += len;
399 if (buffer && size) buffer[total] = 0;
400 return total;
404 /* do string substitutions on the specified text */
405 /* the buffer is assumed to be large enough */
406 /* returns necessary length not including terminating null */
407 unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *text, char *buffer,
408 unsigned int size )
410 WCHAR buffW[MAX_STRING_LEN+1];
411 DWORD ret;
413 unsigned int len = PARSER_string_substW( file, text, buffW, sizeof(buffW)/sizeof(WCHAR) );
414 if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) );
415 else
417 RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) );
418 buffer[ret] = 0;
420 return ret;
424 /* push some string data into the strings buffer */
425 static WCHAR *push_string( struct inf_file *file, const WCHAR *string )
427 WCHAR *ret = file->string_pos;
428 strcpyW( ret, string );
429 file->string_pos += strlenW( ret ) + 1;
430 return ret;
434 /* push the current state on the parser stack */
435 inline static void push_state( struct parser *parser, enum parser_state state )
437 assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
438 parser->stack[parser->stack_pos++] = state;
442 /* pop the current state */
443 inline static void pop_state( struct parser *parser )
445 assert( parser->stack_pos );
446 parser->state = parser->stack[--parser->stack_pos];
450 /* set the parser state and return the previous one */
451 inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
453 enum parser_state ret = parser->state;
454 parser->state = state;
455 return ret;
459 /* check if the pointer points to an end of file */
460 inline static int is_eof( struct parser *parser, const WCHAR *ptr )
462 return (ptr >= parser->end || *ptr == CONTROL_Z);
466 /* check if the pointer points to an end of line */
467 inline static int is_eol( struct parser *parser, const WCHAR *ptr )
469 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n');
473 /* push data from current token start up to pos into the current token */
474 static int push_token( struct parser *parser, const WCHAR *pos )
476 int len = pos - parser->start;
477 const WCHAR *src = parser->start;
478 WCHAR *dst = parser->token + parser->token_len;
480 if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len;
482 parser->token_len += len;
483 for ( ; len > 0; len--, dst++, src++) *dst = *src ? *src : ' ';
484 *dst = 0;
485 parser->start = pos;
486 return 0;
490 /* add a section with the current token as name */
491 static int add_section_from_token( struct parser *parser )
493 int section_index;
495 if (parser->token_len > MAX_SECTION_NAME_LEN)
497 parser->error = ERROR_SECTION_NAME_TOO_LONG;
498 return -1;
500 if ((section_index = find_section( parser->file, parser->token )) == -1)
502 /* need to create a new one */
503 const WCHAR *name = push_string( parser->file, parser->token );
504 if ((section_index = add_section( parser->file, name )) == -1)
506 parser->error = ERROR_NOT_ENOUGH_MEMORY;
507 return -1;
510 parser->token_len = 0;
511 parser->cur_section = section_index;
512 return section_index;
516 /* add a field containing the current token to the current line */
517 static struct field *add_field_from_token( struct parser *parser, int is_key )
519 struct field *field;
520 WCHAR *text;
522 if (!parser->line) /* need to start a new line */
524 if (parser->cur_section == -1) /* got a line before the first section */
526 parser->error = ERROR_WRONG_INF_STYLE;
527 return NULL;
529 if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error;
531 else assert(!is_key);
533 text = push_string( parser->file, parser->token );
534 if ((field = add_field( parser->file, text )))
536 if (!is_key) parser->line->nb_fields++;
537 else
539 /* replace first field by key field */
540 parser->line->key_field = parser->line->first_field;
541 parser->line->first_field++;
543 parser->token_len = 0;
544 return field;
546 error:
547 parser->error = ERROR_NOT_ENOUGH_MEMORY;
548 return NULL;
552 /* close the current line and prepare for parsing a new one */
553 static void close_current_line( struct parser *parser )
555 struct line *cur_line = parser->line;
557 if (cur_line)
559 /* if line has a single field and no key, the field is the key too */
560 if (cur_line->nb_fields == 1 && cur_line->key_field == -1)
561 cur_line->key_field = cur_line->first_field;
563 parser->line = NULL;
567 /* handler for parser LINE_START state */
568 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
570 const WCHAR *p;
572 for (p = pos; !is_eof( parser, p ); p++)
574 switch(*p)
576 case '\n':
577 parser->line_pos++;
578 close_current_line( parser );
579 break;
580 case ';':
581 push_state( parser, LINE_START );
582 set_state( parser, COMMENT );
583 return p + 1;
584 case '[':
585 parser->start = p + 1;
586 set_state( parser, SECTION_NAME );
587 return p + 1;
588 default:
589 if (!isspaceW(*p))
591 parser->start = p;
592 set_state( parser, KEY_NAME );
593 return p;
595 break;
598 close_current_line( parser );
599 return NULL;
603 /* handler for parser SECTION_NAME state */
604 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos )
606 const WCHAR *p;
608 for (p = pos; !is_eol( parser, p ); p++)
610 if (*p == ']')
612 push_token( parser, p );
613 if (add_section_from_token( parser ) == -1) return NULL;
614 push_state( parser, LINE_START );
615 set_state( parser, COMMENT ); /* ignore everything else on the line */
616 return p + 1;
619 parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */
620 return NULL;
624 /* handler for parser KEY_NAME state */
625 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
627 const WCHAR *p, *token_end = parser->start;
629 for (p = pos; !is_eol( parser, p ); p++)
631 if (*p == ',') break;
632 switch(*p)
635 case '=':
636 push_token( parser, token_end );
637 if (!add_field_from_token( parser, 1 )) return NULL;
638 parser->start = p + 1;
639 push_state( parser, VALUE_NAME );
640 set_state( parser, LEADING_SPACES );
641 return p + 1;
642 case ';':
643 push_token( parser, token_end );
644 if (!add_field_from_token( parser, 0 )) return NULL;
645 push_state( parser, LINE_START );
646 set_state( parser, COMMENT );
647 return p + 1;
648 case '"':
649 push_token( parser, token_end );
650 parser->start = p + 1;
651 push_state( parser, KEY_NAME );
652 set_state( parser, QUOTES );
653 return p + 1;
654 case '\\':
655 push_token( parser, token_end );
656 parser->start = p;
657 push_state( parser, KEY_NAME );
658 set_state( parser, EOL_BACKSLASH );
659 return p;
660 default:
661 if (!isspaceW(*p)) token_end = p + 1;
662 else
664 push_token( parser, p );
665 push_state( parser, KEY_NAME );
666 set_state( parser, TRAILING_SPACES );
667 return p;
669 break;
672 push_token( parser, token_end );
673 set_state( parser, VALUE_NAME );
674 return p;
678 /* handler for parser VALUE_NAME state */
679 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
681 const WCHAR *p, *token_end = parser->start;
683 for (p = pos; !is_eol( parser, p ); p++)
685 switch(*p)
687 case ';':
688 push_token( parser, token_end );
689 if (!add_field_from_token( parser, 0 )) return NULL;
690 push_state( parser, LINE_START );
691 set_state( parser, COMMENT );
692 return p + 1;
693 case ',':
694 push_token( parser, token_end );
695 if (!add_field_from_token( parser, 0 )) return NULL;
696 parser->start = p + 1;
697 push_state( parser, VALUE_NAME );
698 set_state( parser, LEADING_SPACES );
699 return p + 1;
700 case '"':
701 push_token( parser, token_end );
702 parser->start = p + 1;
703 push_state( parser, VALUE_NAME );
704 set_state( parser, QUOTES );
705 return p + 1;
706 case '\\':
707 push_token( parser, token_end );
708 parser->start = p;
709 push_state( parser, VALUE_NAME );
710 set_state( parser, EOL_BACKSLASH );
711 return p;
712 default:
713 if (!isspaceW(*p)) token_end = p + 1;
714 else
716 push_token( parser, p );
717 push_state( parser, VALUE_NAME );
718 set_state( parser, TRAILING_SPACES );
719 return p;
721 break;
724 push_token( parser, token_end );
725 if (!add_field_from_token( parser, 0 )) return NULL;
726 set_state( parser, LINE_START );
727 return p;
731 /* handler for parser EOL_BACKSLASH state */
732 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos )
734 const WCHAR *p;
736 for (p = pos; !is_eof( parser, p ); p++)
738 switch(*p)
740 case '\n':
741 parser->line_pos++;
742 parser->start = p + 1;
743 set_state( parser, LEADING_SPACES );
744 return p + 1;
745 case '\\':
746 continue;
747 case ';':
748 push_state( parser, EOL_BACKSLASH );
749 set_state( parser, COMMENT );
750 return p + 1;
751 default:
752 if (isspaceW(*p)) continue;
753 push_token( parser, p );
754 pop_state( parser );
755 return p;
758 parser->start = p;
759 pop_state( parser );
760 return p;
764 /* handler for parser QUOTES state */
765 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
767 const WCHAR *p, *token_end = parser->start;
769 for (p = pos; !is_eol( parser, p ); p++)
771 if (*p == '"')
773 if (p+1 < parser->end && p[1] == '"') /* double quotes */
775 push_token( parser, p + 1 );
776 parser->start = token_end = p + 2;
777 p++;
779 else /* end of quotes */
781 push_token( parser, p );
782 parser->start = p + 1;
783 pop_state( parser );
784 return p + 1;
788 push_token( parser, p );
789 pop_state( parser );
790 return p;
794 /* handler for parser LEADING_SPACES state */
795 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
797 const WCHAR *p;
799 for (p = pos; !is_eol( parser, p ); p++)
801 if (*p == '\\')
803 parser->start = p;
804 set_state( parser, EOL_BACKSLASH );
805 return p;
807 if (!isspaceW(*p)) break;
809 parser->start = p;
810 pop_state( parser );
811 return p;
815 /* handler for parser TRAILING_SPACES state */
816 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos )
818 const WCHAR *p;
820 for (p = pos; !is_eol( parser, p ); p++)
822 if (*p == '\\')
824 set_state( parser, EOL_BACKSLASH );
825 return p;
827 if (!isspaceW(*p)) break;
829 pop_state( parser );
830 return p;
834 /* handler for parser COMMENT state */
835 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos )
837 const WCHAR *p = pos;
839 while (!is_eol( parser, p )) p++;
840 pop_state( parser );
841 return p;
845 /* parse a complete buffer */
846 static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end,
847 UINT *error_line )
849 static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0};
851 struct parser parser;
852 const WCHAR *pos = buffer;
854 parser.start = buffer;
855 parser.end = end;
856 parser.file = file;
857 parser.line = NULL;
858 parser.state = LINE_START;
859 parser.stack_pos = 0;
860 parser.cur_section = -1;
861 parser.line_pos = 1;
862 parser.error = 0;
863 parser.token_len = 0;
865 /* parser main loop */
866 while (pos) pos = (parser_funcs[parser.state])( &parser, pos );
868 /* trim excess buffer space */
869 if (file->alloc_sections > file->nb_sections)
871 file->sections = HeapReAlloc( GetProcessHeap(), 0, file->sections,
872 file->nb_sections * sizeof(file->sections[0]) );
873 file->alloc_sections = file->nb_sections;
875 if (file->alloc_fields > file->nb_fields)
877 file->fields = HeapReAlloc( GetProcessHeap(), 0, file->fields,
878 file->nb_fields * sizeof(file->fields[0]) );
879 file->alloc_fields = file->nb_fields;
881 file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings,
882 (file->string_pos - file->strings) * sizeof(WCHAR) );
884 if (parser.error)
886 if (error_line) *error_line = parser.line_pos;
887 return parser.error;
890 /* find the [strings] section */
891 file->strings_section = find_section( file, Strings );
892 return 0;
896 /* append a child INF file to its parent list, in a thread-safe manner */
897 static void append_inf_file( struct inf_file *parent, struct inf_file *child )
899 struct inf_file **ppnext = &parent->next;
900 child->next = NULL;
902 for (;;)
904 struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL );
905 if (!next) return;
906 ppnext = &next->next;
911 /***********************************************************************
912 * parse_file
914 * parse an INF file.
916 static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *error_line )
918 void *buffer;
919 DWORD err = 0;
920 struct inf_file *file;
922 DWORD size = GetFileSize( handle, NULL );
923 HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL );
924 if (!mapping) return NULL;
925 buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size );
926 NtClose( mapping );
927 if (!buffer) return NULL;
929 if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) );
931 if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) )))
933 err = ERROR_NOT_ENOUGH_MEMORY;
934 goto done;
937 /* we won't need more strings space than the size of the file,
938 * so we can preallocate it here
940 if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
942 err = ERROR_NOT_ENOUGH_MEMORY;
943 goto done;
945 file->string_pos = file->strings;
946 file->strings_section = -1;
948 if (!RtlIsTextUnicode( buffer, size, NULL ))
950 WCHAR *new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
951 if (new_buff)
953 DWORD len = MultiByteToWideChar( CP_ACP, 0, buffer, size, new_buff,
954 size * sizeof(WCHAR) );
955 err = parse_buffer( file, new_buff, new_buff + len, error_line );
956 HeapFree( GetProcessHeap(), 0, new_buff );
959 else err = parse_buffer( file, buffer, (WCHAR *)((char *)buffer + size), error_line );
961 if (!err) /* now check signature */
963 int version_index = find_section( file, Version );
964 if (version_index != -1)
966 struct line *line = find_line( file, version_index, Signature );
967 if (line && line->nb_fields > 0)
969 struct field *field = file->fields + line->first_field;
970 if (!strcmpiW( field->text, Chicago )) goto done;
971 if (!strcmpiW( field->text, WindowsNT )) goto done;
972 if (!strcmpiW( field->text, Windows95 )) goto done;
975 err = ERROR_WRONG_INF_STYLE;
978 done:
979 UnmapViewOfFile( buffer );
980 if (err)
982 HeapFree( GetProcessHeap(), 0, file );
983 SetLastError( err );
984 file = NULL;
986 return file;
990 /***********************************************************************
991 * PARSER_get_src_root
993 * Retrieve the source directory of an inf file.
995 const WCHAR *PARSER_get_src_root( HINF hinf )
997 struct inf_file *file = hinf;
998 return file->src_root;
1002 /***********************************************************************
1003 * SetupOpenInfFileA (SETUPAPI.@)
1005 HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error )
1007 UNICODE_STRING nameW, classW;
1008 HINF ret = (HINF)INVALID_HANDLE_VALUE;
1010 classW.Buffer = NULL;
1011 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class ))
1013 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1014 return ret;
1016 if (RtlCreateUnicodeStringFromAsciiz( &nameW, name ))
1018 ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error );
1019 RtlFreeUnicodeString( &nameW );
1021 RtlFreeUnicodeString( &classW );
1022 return ret;
1026 /***********************************************************************
1027 * SetupOpenInfFileW (SETUPAPI.@)
1029 HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error )
1031 struct inf_file *file = NULL;
1032 HANDLE handle;
1033 WCHAR *path, *p;
1034 UINT len;
1036 if (strchrW( name, '\\' ) || strchrW( name, '/' ))
1038 if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return (HINF)INVALID_HANDLE_VALUE;
1039 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1041 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1042 return (HINF)INVALID_HANDLE_VALUE;
1044 GetFullPathNameW( name, len, path, NULL );
1045 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1047 else /* try Windows directory */
1049 static const WCHAR Inf[] = {'\\','i','n','f','\\',0};
1050 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
1052 len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12;
1053 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1055 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1056 return (HINF)INVALID_HANDLE_VALUE;
1058 GetWindowsDirectoryW( path, len );
1059 p = path + strlenW(path);
1060 strcpyW( p, Inf );
1061 strcatW( p, name );
1062 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1063 if (handle == INVALID_HANDLE_VALUE)
1065 strcpyW( p, System32 );
1066 strcatW( p, name );
1067 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1071 if (handle != INVALID_HANDLE_VALUE)
1073 file = parse_file( handle, class, error );
1074 CloseHandle( handle );
1076 if (!file)
1078 HeapFree( GetProcessHeap(), 0, path );
1079 return (HINF)INVALID_HANDLE_VALUE;
1081 TRACE( "%s -> %p\n", debugstr_w(path), file );
1082 file->src_root = path;
1083 if ((p = strrchrW( path, '\\' ))) p[1] = 0; /* remove file name */
1084 SetLastError( 0 );
1085 return (HINF)file;
1089 /***********************************************************************
1090 * SetupOpenAppendInfFileA (SETUPAPI.@)
1092 BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error )
1094 HINF child_hinf;
1096 if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error );
1097 child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error );
1098 if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
1099 append_inf_file( parent_hinf, child_hinf );
1100 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf );
1101 return TRUE;
1105 /***********************************************************************
1106 * SetupOpenAppendInfFileW (SETUPAPI.@)
1108 BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error )
1110 HINF child_hinf;
1112 if (!name)
1114 INFCONTEXT context;
1115 WCHAR filename[MAX_PATH];
1116 int idx = 1;
1118 if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE;
1119 while (SetupGetStringFieldW( &context, idx++, filename,
1120 sizeof(filename)/sizeof(WCHAR), NULL ))
1122 child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error );
1123 if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
1124 append_inf_file( parent_hinf, child_hinf );
1125 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf );
1127 return TRUE;
1129 child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error );
1130 if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE;
1131 append_inf_file( parent_hinf, child_hinf );
1132 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf );
1133 return TRUE;
1137 /***********************************************************************
1138 * SetupCloseInfFile (SETUPAPI.@)
1140 void WINAPI SetupCloseInfFile( HINF hinf )
1142 struct inf_file *file = hinf;
1143 int i;
1145 for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] );
1146 HeapFree( GetProcessHeap(), 0, file->src_root );
1147 HeapFree( GetProcessHeap(), 0, file->sections );
1148 HeapFree( GetProcessHeap(), 0, file->fields );
1149 HeapFree( GetProcessHeap(), 0, file->strings );
1150 HeapFree( GetProcessHeap(), 0, file );
1154 /***********************************************************************
1155 * SetupGetLineCountA (SETUPAPI.@)
1157 LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name )
1159 UNICODE_STRING sectionW;
1160 LONG ret = -1;
1162 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, name ))
1163 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1164 else
1166 ret = SetupGetLineCountW( hinf, sectionW.Buffer );
1167 RtlFreeUnicodeString( &sectionW );
1169 return ret;
1173 /***********************************************************************
1174 * SetupGetLineCountW (SETUPAPI.@)
1176 LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section )
1178 struct inf_file *file = hinf;
1179 int section_index;
1180 LONG ret = -1;
1182 for (file = hinf; file; file = file->next)
1184 if ((section_index = find_section( file, section )) == -1) continue;
1185 if (ret == -1) ret = 0;
1186 ret += file->sections[section_index]->nb_lines;
1188 TRACE( "(%p,%s) returning %ld\n", hinf, debugstr_w(section), ret );
1189 SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 );
1190 return ret;
1194 /***********************************************************************
1195 * SetupGetLineByIndexA (SETUPAPI.@)
1197 BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context )
1199 UNICODE_STRING sectionW;
1200 BOOL ret = FALSE;
1202 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1203 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1204 else
1206 ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context );
1207 RtlFreeUnicodeString( &sectionW );
1209 return ret;
1213 /***********************************************************************
1214 * SetupGetLineByIndexW (SETUPAPI.@)
1216 BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context )
1218 struct inf_file *file = hinf;
1219 int section_index;
1221 SetLastError( ERROR_SECTION_NOT_FOUND );
1222 for (file = hinf; file; file = file->next)
1224 if ((section_index = find_section( file, section )) == -1) continue;
1225 SetLastError( ERROR_LINE_NOT_FOUND );
1226 if (index < file->sections[section_index]->nb_lines)
1228 context->Inf = hinf;
1229 context->CurrentInf = file;
1230 context->Section = section_index;
1231 context->Line = index;
1232 SetLastError( 0 );
1233 TRACE( "(%p,%s): returning %d/%ld\n",
1234 hinf, debugstr_w(section), section_index, index );
1235 return TRUE;
1237 index -= file->sections[section_index]->nb_lines;
1239 TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) );
1240 return FALSE;
1244 /***********************************************************************
1245 * SetupFindFirstLineA (SETUPAPI.@)
1247 BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context )
1249 UNICODE_STRING sectionW, keyW;
1250 BOOL ret = FALSE;
1252 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1254 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1255 return FALSE;
1258 if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context );
1259 else
1261 if (RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1263 ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context );
1264 RtlFreeUnicodeString( &keyW );
1266 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1268 RtlFreeUnicodeString( &sectionW );
1269 return ret;
1273 /***********************************************************************
1274 * SetupFindFirstLineW (SETUPAPI.@)
1276 BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context )
1278 struct inf_file *file;
1279 int section_index;
1281 SetLastError( ERROR_SECTION_NOT_FOUND );
1282 for (file = hinf; file; file = file->next)
1284 if ((section_index = find_section( file, section )) == -1) continue;
1285 if (key)
1287 INFCONTEXT ctx;
1288 ctx.Inf = hinf;
1289 ctx.CurrentInf = file;
1290 ctx.Section = section_index;
1291 ctx.Line = -1;
1292 return SetupFindNextMatchLineW( &ctx, key, context );
1294 SetLastError( ERROR_LINE_NOT_FOUND ); /* found at least one section */
1295 if (file->sections[section_index]->nb_lines)
1297 context->Inf = hinf;
1298 context->CurrentInf = file;
1299 context->Section = section_index;
1300 context->Line = 0;
1301 SetLastError( 0 );
1302 TRACE( "(%p,%s,%s): returning %d/0\n",
1303 hinf, debugstr_w(section), debugstr_w(key), section_index );
1304 return TRUE;
1307 TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) );
1308 return FALSE;
1312 /***********************************************************************
1313 * SetupFindNextLine (SETUPAPI.@)
1315 BOOL WINAPI SetupFindNextLine( const INFCONTEXT *context_in, INFCONTEXT *context_out )
1317 struct inf_file *file = context_in->CurrentInf;
1318 struct section *section;
1320 if (context_in->Section >= file->nb_sections) goto error;
1322 section = file->sections[context_in->Section];
1323 if (context_in->Line+1 < section->nb_lines)
1325 if (context_out != context_in) *context_out = *context_in;
1326 context_out->Line++;
1327 SetLastError( 0 );
1328 return TRUE;
1331 /* now search the appended files */
1333 for (file = file->next; file; file = file->next)
1335 int section_index = find_section( file, section->name );
1336 if (section_index == -1) continue;
1337 if (file->sections[section_index]->nb_lines)
1339 context_out->Inf = context_in->Inf;
1340 context_out->CurrentInf = file;
1341 context_out->Section = section_index;
1342 context_out->Line = 0;
1343 SetLastError( 0 );
1344 return TRUE;
1347 error:
1348 SetLastError( ERROR_LINE_NOT_FOUND );
1349 return FALSE;
1353 /***********************************************************************
1354 * SetupFindNextMatchLineA (SETUPAPI.@)
1356 BOOL WINAPI SetupFindNextMatchLineA( const INFCONTEXT *context_in, PCSTR key,
1357 INFCONTEXT *context_out )
1359 UNICODE_STRING keyW;
1360 BOOL ret = FALSE;
1362 if (!key) return SetupFindNextLine( context_in, context_out );
1364 if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1365 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1366 else
1368 ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out );
1369 RtlFreeUnicodeString( &keyW );
1371 return ret;
1375 /***********************************************************************
1376 * SetupFindNextMatchLineW (SETUPAPI.@)
1378 BOOL WINAPI SetupFindNextMatchLineW( const INFCONTEXT *context_in, PCWSTR key,
1379 INFCONTEXT *context_out )
1381 struct inf_file *file = context_in->CurrentInf;
1382 struct section *section;
1383 struct line *line;
1384 unsigned int i;
1386 if (!key) return SetupFindNextLine( context_in, context_out );
1388 if (context_in->Section >= file->nb_sections) goto error;
1390 section = file->sections[context_in->Section];
1392 for (i = context_in->Line+1, line = &section->lines[i]; i < section->nb_lines; i++, line++)
1394 if (line->key_field == -1) continue;
1395 if (!strcmpiW( key, file->fields[line->key_field].text ))
1397 if (context_out != context_in) *context_out = *context_in;
1398 context_out->Line = i;
1399 SetLastError( 0 );
1400 TRACE( "(%p,%s,%s): returning %d\n",
1401 file, debugstr_w(section->name), debugstr_w(key), i );
1402 return TRUE;
1406 /* now search the appended files */
1408 for (file = file->next; file; file = file->next)
1410 int section_index = find_section( file, section->name );
1411 if (section_index == -1) continue;
1412 section = file->sections[section_index];
1413 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
1415 if (line->key_field == -1) continue;
1416 if (!strcmpiW( key, file->fields[line->key_field].text ))
1418 context_out->Inf = context_in->Inf;
1419 context_out->CurrentInf = file;
1420 context_out->Section = section_index;
1421 context_out->Line = i;
1422 SetLastError( 0 );
1423 TRACE( "(%p,%s,%s): returning %d/%d\n",
1424 file, debugstr_w(section->name), debugstr_w(key), section_index, i );
1425 return TRUE;
1429 TRACE( "(%p,%s,%s): not found\n",
1430 context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) );
1431 error:
1432 SetLastError( ERROR_LINE_NOT_FOUND );
1433 return FALSE;
1437 /***********************************************************************
1438 * SetupGetLineTextW (SETUPAPI.@)
1440 BOOL WINAPI SetupGetLineTextW( const INFCONTEXT *context, HINF hinf, PCWSTR section_name,
1441 PCWSTR key_name, PWSTR buffer, DWORD size, DWORD *required )
1443 struct inf_file *file;
1444 struct line *line;
1445 struct field *field;
1446 int i;
1447 DWORD total = 0;
1449 if (!context)
1451 INFCONTEXT new_context;
1452 if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE;
1453 file = new_context.CurrentInf;
1454 line = get_line( file, new_context.Section, new_context.Line );
1456 else
1458 file = context->CurrentInf;
1459 if (!(line = get_line( file, context->Section, context->Line )))
1461 SetLastError( ERROR_LINE_NOT_FOUND );
1462 return FALSE;
1466 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1467 total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1;
1469 if (required) *required = total;
1470 if (buffer)
1472 if (total > size)
1474 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1475 return FALSE;
1477 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1479 unsigned int len = PARSER_string_substW( file, field->text, buffer, size );
1480 if (i+1 < line->nb_fields) buffer[len] = ',';
1481 buffer += len + 1;
1484 return TRUE;
1488 /***********************************************************************
1489 * SetupGetLineTextA (SETUPAPI.@)
1491 BOOL WINAPI SetupGetLineTextA( const INFCONTEXT *context, HINF hinf, PCSTR section_name,
1492 PCSTR key_name, PSTR buffer, DWORD size, DWORD *required )
1494 struct inf_file *file;
1495 struct line *line;
1496 struct field *field;
1497 int i;
1498 DWORD total = 0;
1500 if (!context)
1502 INFCONTEXT new_context;
1503 if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE;
1504 file = new_context.CurrentInf;
1505 line = get_line( file, new_context.Section, new_context.Line );
1507 else
1509 file = context->CurrentInf;
1510 if (!(line = get_line( file, context->Section, context->Line )))
1512 SetLastError( ERROR_LINE_NOT_FOUND );
1513 return FALSE;
1517 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1518 total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1;
1520 if (required) *required = total;
1521 if (buffer)
1523 if (total > size)
1525 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1526 return FALSE;
1528 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1530 unsigned int len = PARSER_string_substA( file, field->text, buffer, size );
1531 if (i+1 < line->nb_fields) buffer[len] = ',';
1532 buffer += len + 1;
1535 return TRUE;
1539 /***********************************************************************
1540 * SetupGetFieldCount (SETUPAPI.@)
1542 DWORD WINAPI SetupGetFieldCount( const INFCONTEXT *context )
1544 struct inf_file *file = context->CurrentInf;
1545 struct line *line = get_line( file, context->Section, context->Line );
1547 if (!line) return 0;
1548 return line->nb_fields;
1552 /***********************************************************************
1553 * SetupGetStringFieldA (SETUPAPI.@)
1555 BOOL WINAPI SetupGetStringFieldA( const INFCONTEXT *context, DWORD index, PSTR buffer,
1556 DWORD size, DWORD *required )
1558 struct inf_file *file = context->CurrentInf;
1559 struct field *field = get_field( file, context->Section, context->Line, index );
1560 unsigned int len;
1562 SetLastError(0);
1563 if (!field) return FALSE;
1564 len = PARSER_string_substA( file, field->text, NULL, 0 );
1565 if (required) *required = len + 1;
1566 if (buffer)
1568 if (size <= len)
1570 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1571 return FALSE;
1573 PARSER_string_substA( file, field->text, buffer, size );
1575 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1576 context->Inf, context->CurrentInf, context->Section, context->Line,
1577 index, debugstr_a(buffer) );
1579 return TRUE;
1583 /***********************************************************************
1584 * SetupGetStringFieldW (SETUPAPI.@)
1586 BOOL WINAPI SetupGetStringFieldW( const INFCONTEXT *context, DWORD index, PWSTR buffer,
1587 DWORD size, DWORD *required )
1589 struct inf_file *file = context->CurrentInf;
1590 struct field *field = get_field( file, context->Section, context->Line, index );
1591 unsigned int len;
1593 SetLastError(0);
1594 if (!field) return FALSE;
1595 len = PARSER_string_substW( file, field->text, NULL, 0 );
1596 if (required) *required = len + 1;
1597 if (buffer)
1599 if (size <= len)
1601 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1602 return FALSE;
1604 PARSER_string_substW( file, field->text, buffer, size );
1606 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1607 context->Inf, context->CurrentInf, context->Section, context->Line,
1608 index, debugstr_w(buffer) );
1610 return TRUE;
1614 /***********************************************************************
1615 * SetupGetIntField (SETUPAPI.@)
1617 BOOL WINAPI SetupGetIntField( const INFCONTEXT *context, DWORD index, INT *result )
1619 char localbuff[20];
1620 char *end, *buffer = localbuff;
1621 DWORD required;
1622 INT res;
1623 BOOL ret = FALSE;
1625 if (!SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required ))
1627 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
1628 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE;
1629 if (!SetupGetStringFieldA( context, index, buffer, required, NULL )) goto done;
1631 res = strtol( buffer, &end, 0 );
1632 if (end != buffer && !*end)
1634 *result = res;
1635 ret = TRUE;
1637 else SetLastError( ERROR_INVALID_DATA );
1639 done:
1640 if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer );
1641 return ret;
1645 /***********************************************************************
1646 * SetupGetBinaryField (SETUPAPI.@)
1648 BOOL WINAPI SetupGetBinaryField( const INFCONTEXT *context, DWORD index, BYTE *buffer,
1649 DWORD size, DWORD *required )
1651 struct inf_file *file = context->CurrentInf;
1652 struct line *line = get_line( file, context->Section, context->Line );
1653 struct field *field;
1654 int i;
1656 if (!line)
1658 SetLastError( ERROR_LINE_NOT_FOUND );
1659 return FALSE;
1661 if (!index || index >= line->nb_fields)
1663 SetLastError( ERROR_INVALID_PARAMETER );
1664 return FALSE;
1666 index--; /* fields start at 0 */
1667 if (required) *required = line->nb_fields - index;
1668 if (!buffer) return TRUE;
1669 if (size < line->nb_fields - index)
1671 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1672 return FALSE;
1674 field = &file->fields[line->first_field + index];
1675 for (i = index; i < line->nb_fields; i++, field++)
1677 const WCHAR *p;
1678 DWORD value = 0;
1679 for (p = field->text; *p && isxdigitW(*p); p++)
1681 if ((value <<= 4) > 255)
1683 SetLastError( ERROR_INVALID_DATA );
1684 return FALSE;
1686 if (*p <= '9') value |= (*p - '0');
1687 else value |= (tolowerW(*p) - 'a' + 10);
1689 buffer[i - index] = value;
1691 if (TRACE_ON(setupapi))
1693 TRACE( "%p/%p/%d/%d index %ld returning",
1694 context->Inf, context->CurrentInf, context->Section, context->Line, index );
1695 for (i = index; i < line->nb_fields; i++) TRACE( " %02x", buffer[i - index] );
1696 TRACE( "\n" );
1698 return TRUE;
1702 /***********************************************************************
1703 * SetupGetMultiSzFieldA (SETUPAPI.@)
1705 BOOL WINAPI SetupGetMultiSzFieldA( const INFCONTEXT *context, DWORD index, PSTR buffer,
1706 DWORD size, DWORD *required )
1708 struct inf_file *file = context->CurrentInf;
1709 struct line *line = get_line( file, context->Section, context->Line );
1710 struct field *field;
1711 unsigned int len;
1712 int i;
1713 DWORD total = 1;
1715 if (!line)
1717 SetLastError( ERROR_LINE_NOT_FOUND );
1718 return FALSE;
1720 if (!index || index >= line->nb_fields)
1722 SetLastError( ERROR_INVALID_PARAMETER );
1723 return FALSE;
1725 index--; /* fields start at 0 */
1726 field = &file->fields[line->first_field + index];
1727 for (i = index; i < line->nb_fields; i++, field++)
1729 if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break;
1730 total += len + 1;
1733 if (required) *required = total;
1734 if (!buffer) return TRUE;
1735 if (total > size)
1737 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1738 return FALSE;
1740 field = &file->fields[line->first_field + index];
1741 for (i = index; i < line->nb_fields; i++, field++)
1743 if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break;
1744 buffer += len + 1;
1746 *buffer = 0; /* add final null */
1747 return TRUE;
1751 /***********************************************************************
1752 * SetupGetMultiSzFieldW (SETUPAPI.@)
1754 BOOL WINAPI SetupGetMultiSzFieldW( const INFCONTEXT *context, DWORD index, PWSTR buffer,
1755 DWORD size, DWORD *required )
1757 struct inf_file *file = context->CurrentInf;
1758 struct line *line = get_line( file, context->Section, context->Line );
1759 struct field *field;
1760 unsigned int len;
1761 int i;
1762 DWORD total = 1;
1764 if (!line)
1766 SetLastError( ERROR_LINE_NOT_FOUND );
1767 return FALSE;
1769 if (!index || index >= line->nb_fields)
1771 SetLastError( ERROR_INVALID_PARAMETER );
1772 return FALSE;
1774 index--; /* fields start at 0 */
1775 field = &file->fields[line->first_field + index];
1776 for (i = index; i < line->nb_fields; i++, field++)
1778 if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break;
1779 total += len + 1;
1782 if (required) *required = total;
1783 if (!buffer) return TRUE;
1784 if (total > size)
1786 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1787 return FALSE;
1789 field = &file->fields[line->first_field + index];
1790 for (i = index; i < line->nb_fields; i++, field++)
1792 if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break;
1793 buffer += len + 1;
1795 *buffer = 0; /* add final null */
1796 return TRUE;