include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / setupapi / parser.c
blob22dc23c54fdcbc66d078334226b5eeaad4ffe64a
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <stdlib.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "winreg.h"
33 #include "winternl.h"
34 #include "winerror.h"
35 #include "setupapi.h"
36 #include "setupapi_private.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
42 #define CONTROL_Z '\x1a'
43 #define MAX_SECTION_NAME_LEN 255
44 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
45 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
46 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
48 /* inf file structure definitions */
50 struct field
52 const WCHAR *text; /* field text */
55 struct line
57 int first_field; /* index of first field in field array */
58 int nb_fields; /* number of fields in line */
59 int key_field; /* index of field for key or -1 if no key */
62 struct section
64 const WCHAR *name; /* section name */
65 unsigned int nb_lines; /* number of used lines */
66 unsigned int alloc_lines; /* total number of allocated lines in array below */
67 struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */
70 struct inf_file
72 struct inf_file *next; /* next appended file */
73 WCHAR *strings; /* buffer for string data (section names and field values) */
74 WCHAR *string_pos; /* position of next available string in buffer */
75 unsigned int nb_sections; /* number of used sections */
76 unsigned int alloc_sections; /* total number of allocated section pointers */
77 struct section **sections; /* section pointers array */
78 unsigned int nb_fields;
79 unsigned int alloc_fields;
80 struct field *fields;
81 int strings_section; /* index of [Strings] section or -1 if none */
82 WCHAR *filename; /* filename of the INF */
85 /* parser definitions */
87 enum parser_state
89 LINE_START, /* at beginning of a line */
90 SECTION_NAME, /* parsing a section name */
91 KEY_NAME, /* parsing a key name */
92 VALUE_NAME, /* parsing a value name */
93 EOL_BACKSLASH, /* backslash at end of line */
94 QUOTES, /* inside quotes */
95 LEADING_SPACES, /* leading spaces */
96 TRAILING_SPACES, /* trailing spaces */
97 COMMENT, /* inside a comment */
98 NB_PARSER_STATES
101 struct parser
103 const WCHAR *start; /* start position of item being parsed */
104 const WCHAR *end; /* end of buffer */
105 struct inf_file *file; /* file being built */
106 enum parser_state state; /* current parser state */
107 enum parser_state stack[4]; /* state stack */
108 int stack_pos; /* current pos in stack */
110 int cur_section; /* index of section being parsed*/
111 struct line *line; /* current line */
112 unsigned int line_pos; /* current line position in file */
113 unsigned int broken_line; /* first line containing invalid data (if any) */
114 unsigned int error; /* error code */
115 unsigned int token_len; /* current token len */
116 WCHAR token[MAX_FIELD_LEN+1]; /* current token */
119 typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos );
121 /* parser state machine functions */
122 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos );
123 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos );
124 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos );
125 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos );
126 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos );
127 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos );
128 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos );
129 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos );
130 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos );
132 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
134 line_start_state, /* LINE_START */
135 section_name_state, /* SECTION_NAME */
136 key_name_state, /* KEY_NAME */
137 value_name_state, /* VALUE_NAME */
138 eol_backslash_state, /* EOL_BACKSLASH */
139 quotes_state, /* QUOTES */
140 leading_spaces_state, /* LEADING_SPACES */
141 trailing_spaces_state, /* TRAILING_SPACES */
142 comment_state /* COMMENT */
146 /* Unicode string constants */
147 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
148 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
149 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
150 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
151 static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
152 static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0};
154 /* extend an array, allocating more memory if necessary */
155 static void *grow_array( void *array, unsigned int *count, size_t elem )
157 void *new_array;
158 unsigned int new_count = *count + *count / 2;
159 if (new_count < 32) new_count = 32;
161 new_array = _recalloc( array, new_count, elem );
163 if (new_array)
164 *count = new_count;
165 else
166 free( array );
167 return new_array;
171 /* get the directory of the inf file (as counted string, not null-terminated) */
172 static const WCHAR *get_inf_dir( const struct inf_file *file, unsigned int *len )
174 const WCHAR *p = wcsrchr( file->filename, '\\' );
175 *len = p ? (p + 1 - file->filename) : 0;
176 return file->filename;
180 /* find a section by name */
181 static int find_section( const struct inf_file *file, const WCHAR *name )
183 unsigned int i;
185 for (i = 0; i < file->nb_sections; i++)
186 if (!wcsicmp( name, file->sections[i]->name )) return i;
187 return -1;
191 /* find a line by name */
192 static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name )
194 struct section *section;
195 struct line *line;
196 unsigned int i;
198 if (section_index < 0 || section_index >= file->nb_sections) return NULL;
199 section = file->sections[section_index];
200 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
202 if (line->key_field == -1) continue;
203 if (!wcsicmp( name, file->fields[line->key_field].text )) return line;
205 return NULL;
209 /* add a section to the file and return the section index */
210 static int add_section( struct inf_file *file, const WCHAR *name )
212 struct section *section;
214 if (file->nb_sections >= file->alloc_sections)
216 if (!(file->sections = grow_array( file->sections, &file->alloc_sections,
217 sizeof(file->sections[0]) ))) return -1;
219 if (!(section = malloc( sizeof(*section) ))) return -1;
220 section->name = name;
221 section->nb_lines = 0;
222 section->alloc_lines = ARRAY_SIZE( section->lines );
223 file->sections[file->nb_sections] = section;
224 return file->nb_sections++;
228 /* add a line to a given section */
229 static struct line *add_line( struct inf_file *file, int section_index )
231 struct section *section;
232 struct line *line;
234 assert( section_index >= 0 && section_index < file->nb_sections );
236 section = file->sections[section_index];
237 if (section->nb_lines == section->alloc_lines) /* need to grow the section */
239 int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line);
240 if (!(section = realloc( section, size ))) return NULL;
241 section->alloc_lines *= 2;
242 file->sections[section_index] = section;
244 line = &section->lines[section->nb_lines++];
245 line->first_field = file->nb_fields;
246 line->nb_fields = 0;
247 line->key_field = -1;
248 return line;
252 /* retrieve a given line from section/line index */
253 static inline struct line *get_line( struct inf_file *file, unsigned int section_index,
254 unsigned int line_index )
256 struct section *section;
258 if (section_index >= file->nb_sections) return NULL;
259 section = file->sections[section_index];
260 if (line_index >= section->nb_lines) return NULL;
261 return &section->lines[line_index];
265 /* retrieve a given field from section/line/field index */
266 static struct field *get_field( struct inf_file *file, int section_index, int line_index,
267 int field_index )
269 struct line *line = get_line( file, section_index, line_index );
271 if (!line) return NULL;
272 if (!field_index) /* get the key */
274 if (line->key_field == -1) return NULL;
275 return &file->fields[line->key_field];
277 field_index--;
278 if (field_index >= line->nb_fields) return NULL;
279 return &file->fields[line->first_field + field_index];
283 /* allocate a new field, growing the array if necessary */
284 static struct field *add_field( struct inf_file *file, const WCHAR *text )
286 struct field *field;
288 if (file->nb_fields >= file->alloc_fields)
290 if (!(file->fields = grow_array( file->fields, &file->alloc_fields,
291 sizeof(file->fields[0]) ))) return NULL;
293 field = &file->fields[file->nb_fields++];
294 field->text = text;
295 return field;
299 /* retrieve the string substitution for a directory id */
300 static const WCHAR *get_dirid_subst( const struct inf_file *file, int dirid, unsigned int *len )
302 const WCHAR *ret;
304 if (dirid == DIRID_SRCPATH) return get_inf_dir( file, len );
305 ret = DIRID_get_string( dirid );
306 if (ret) *len = lstrlenW(ret);
307 return ret;
311 /* retrieve the string substitution for a given string, or NULL if not found */
312 /* if found, len is set to the substitution length */
313 static const WCHAR *get_string_subst( const struct inf_file *file, const WCHAR *str, unsigned int *len,
314 BOOL no_trailing_slash )
316 static const WCHAR percent = '%';
318 struct section *strings_section;
319 struct line *line;
320 struct field *field;
321 unsigned int i;
322 int dirid;
323 WCHAR *dirid_str, *end;
324 const WCHAR *ret = NULL;
326 if (!*len) /* empty string (%%) is replaced by single percent */
328 *len = 1;
329 return &percent;
331 if (file->strings_section == -1) goto not_found;
332 strings_section = file->sections[file->strings_section];
333 for (i = 0, line = strings_section->lines; i < strings_section->nb_lines; i++, line++)
335 if (line->key_field == -1) continue;
336 if (wcsnicmp( str, file->fields[line->key_field].text, *len )) continue;
337 if (!file->fields[line->key_field].text[*len]) break;
339 if (i == strings_section->nb_lines || !line->nb_fields) goto not_found;
340 field = &file->fields[line->first_field];
341 *len = lstrlenW( field->text );
342 return field->text;
344 not_found: /* check for integer id */
345 if ((dirid_str = malloc( (*len + 1) * sizeof(WCHAR) )))
347 memcpy( dirid_str, str, *len * sizeof(WCHAR) );
348 dirid_str[*len] = 0;
349 dirid = wcstol( dirid_str, &end, 10 );
350 if (!*end) ret = get_dirid_subst( file, dirid, len );
351 if (no_trailing_slash && ret && *len && ret[*len - 1] == '\\') *len -= 1;
352 free( dirid_str );
353 return ret;
355 return NULL;
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 static unsigned int PARSER_string_substW( const struct inf_file *file, const WCHAR *text,
363 WCHAR *buffer, unsigned int size )
365 const WCHAR *start, *subst, *p;
366 unsigned int len, total = 0;
367 BOOL inside = FALSE;
369 if (!buffer) size = MAX_STRING_LEN + 1;
370 for (p = start = text; *p; p++)
372 if (*p != '%') continue;
373 inside = !inside;
374 if (inside) /* start of a %xx% string */
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;
383 else /* end of the %xx% string, find substitution */
385 len = p - start - 1;
386 subst = get_string_subst( file, start + 1, &len, p[1] == '\\' );
387 if (!subst)
389 subst = start;
390 len = p - start + 1;
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;
400 if (start != p) /* unfinished string, copy it */
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;
407 if (buffer && size) buffer[total] = 0;
408 return total;
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 static unsigned int PARSER_string_substA( const struct inf_file *file, const WCHAR *text,
416 char *buffer, unsigned int size )
418 WCHAR buffW[MAX_STRING_LEN+1];
419 DWORD ret;
421 unsigned int len = PARSER_string_substW( file, text, buffW, ARRAY_SIZE( buffW ));
422 if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) );
423 else
425 RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) );
426 buffer[ret] = 0;
428 return ret;
432 /* push some string data into the strings buffer */
433 static WCHAR *push_string( struct inf_file *file, const WCHAR *string )
435 WCHAR *ret = file->string_pos;
436 lstrcpyW( ret, string );
437 file->string_pos += lstrlenW( ret ) + 1;
438 return ret;
442 /* push the current state on the parser stack */
443 static inline void push_state( struct parser *parser, enum parser_state state )
445 assert( parser->stack_pos < ARRAY_SIZE( parser->stack ));
446 parser->stack[parser->stack_pos++] = state;
450 /* pop the current state */
451 static inline void pop_state( struct parser *parser )
453 assert( parser->stack_pos );
454 parser->state = parser->stack[--parser->stack_pos];
458 /* set the parser state and return the previous one */
459 static inline enum parser_state set_state( struct parser *parser, enum parser_state state )
461 enum parser_state ret = parser->state;
462 parser->state = state;
463 return ret;
467 /* check if the pointer points to an end of file */
468 static inline BOOL is_eof( const struct parser *parser, const WCHAR *ptr )
470 return (ptr >= parser->end || *ptr == CONTROL_Z);
474 /* check if the pointer points to an end of line */
475 static inline BOOL is_eol( const struct parser *parser, const WCHAR *ptr )
477 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n');
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 )
484 int len = pos - parser->start;
485 const WCHAR *src = parser->start;
486 WCHAR *dst = parser->token + parser->token_len;
488 if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len;
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;
498 /* add a section with the current token as name */
499 static int add_section_from_token( struct parser *parser )
501 int section_index;
503 if (parser->token_len > MAX_SECTION_NAME_LEN)
505 parser->error = ERROR_SECTION_NAME_TOO_LONG;
506 return -1;
508 if ((section_index = find_section( parser->file, parser->token )) == -1)
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)
514 parser->error = ERROR_NOT_ENOUGH_MEMORY;
515 return -1;
518 parser->token_len = 0;
519 parser->cur_section = section_index;
520 return section_index;
524 /* add a field containing the current token to the current line */
525 static struct field *add_field_from_token( struct parser *parser, BOOL is_key )
527 struct field *field;
528 WCHAR *text;
530 if (!parser->line) /* need to start a new line */
532 if (parser->cur_section == -1) /* got a line before the first section */
534 parser->error = ERROR_EXPECTED_SECTION_NAME;
535 return NULL;
537 if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error;
539 else assert(!is_key);
541 text = push_string( parser->file, parser->token );
542 if ((field = add_field( parser->file, text )))
544 if (!is_key) parser->line->nb_fields++;
545 else
547 /* replace first field by key field */
548 parser->line->key_field = parser->line->first_field;
549 parser->line->first_field++;
551 parser->token_len = 0;
552 return field;
554 error:
555 parser->error = ERROR_NOT_ENOUGH_MEMORY;
556 return NULL;
560 /* close the current line and prepare for parsing a new one */
561 static void close_current_line( struct parser *parser )
563 struct line *cur_line = parser->line;
565 if (cur_line)
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;
571 parser->line = NULL;
575 /* handler for parser LINE_START state */
576 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
578 const WCHAR *p;
580 for (p = pos; !is_eof( parser, p ); p++)
582 switch(*p)
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 (iswspace(*p)) break;
598 if (parser->cur_section != -1)
600 parser->start = p;
601 set_state( parser, KEY_NAME );
602 return p;
604 if (!parser->broken_line)
605 parser->broken_line = parser->line_pos;
606 break;
609 close_current_line( parser );
610 return NULL;
614 /* handler for parser SECTION_NAME state */
615 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos )
617 const WCHAR *p;
619 for (p = pos; !is_eol( parser, p ); p++)
621 if (*p == ']')
623 push_token( parser, p );
624 if (add_section_from_token( parser ) == -1) return NULL;
625 push_state( parser, LINE_START );
626 set_state( parser, COMMENT ); /* ignore everything else on the line */
627 return p + 1;
630 parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */
631 return NULL;
635 /* handler for parser KEY_NAME state */
636 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
638 const WCHAR *p, *token_end = parser->start;
640 for (p = pos; !is_eol( parser, p ); p++)
642 if (*p == ',') break;
643 switch(*p)
646 case '=':
647 push_token( parser, token_end );
648 if (!add_field_from_token( parser, TRUE )) return NULL;
649 parser->start = p + 1;
650 push_state( parser, VALUE_NAME );
651 set_state( parser, LEADING_SPACES );
652 return p + 1;
653 case ';':
654 push_token( parser, token_end );
655 if (!add_field_from_token( parser, FALSE )) return NULL;
656 push_state( parser, LINE_START );
657 set_state( parser, COMMENT );
658 return p + 1;
659 case '"':
660 push_token( parser, p );
661 parser->start = p + 1;
662 push_state( parser, KEY_NAME );
663 set_state( parser, QUOTES );
664 return p + 1;
665 case '\\':
666 push_token( parser, token_end );
667 parser->start = p;
668 push_state( parser, KEY_NAME );
669 set_state( parser, EOL_BACKSLASH );
670 return p;
671 default:
672 if (!iswspace(*p)) token_end = p + 1;
673 else
675 push_token( parser, p );
676 push_state( parser, KEY_NAME );
677 set_state( parser, TRAILING_SPACES );
678 return p;
680 break;
683 push_token( parser, token_end );
684 set_state( parser, VALUE_NAME );
685 return p;
689 /* handler for parser VALUE_NAME state */
690 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
692 const WCHAR *p, *token_end = parser->start;
694 for (p = pos; !is_eol( parser, p ); p++)
696 switch(*p)
698 case ';':
699 push_token( parser, token_end );
700 if (!add_field_from_token( parser, FALSE )) return NULL;
701 push_state( parser, LINE_START );
702 set_state( parser, COMMENT );
703 return p + 1;
704 case ',':
705 push_token( parser, token_end );
706 if (!add_field_from_token( parser, FALSE )) return NULL;
707 parser->start = p + 1;
708 push_state( parser, VALUE_NAME );
709 set_state( parser, LEADING_SPACES );
710 return p + 1;
711 case '"':
712 push_token( parser, p );
713 parser->start = p + 1;
714 push_state( parser, VALUE_NAME );
715 set_state( parser, QUOTES );
716 return p + 1;
717 case '\\':
718 push_token( parser, token_end );
719 parser->start = p;
720 push_state( parser, VALUE_NAME );
721 set_state( parser, EOL_BACKSLASH );
722 return p;
723 default:
724 if (*p && !iswspace(*p)) token_end = p + 1;
725 else
727 push_token( parser, p );
728 push_state( parser, VALUE_NAME );
729 set_state( parser, TRAILING_SPACES );
730 return p;
732 break;
735 push_token( parser, token_end );
736 if (!add_field_from_token( parser, FALSE )) return NULL;
737 set_state( parser, LINE_START );
738 return p;
742 /* handler for parser EOL_BACKSLASH state */
743 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos )
745 const WCHAR *p;
747 for (p = pos; !is_eof( parser, p ); p++)
749 switch(*p)
751 case '\n':
752 parser->line_pos++;
753 parser->start = p + 1;
754 set_state( parser, LEADING_SPACES );
755 return p + 1;
756 case '\\':
757 continue;
758 case ';':
759 push_state( parser, EOL_BACKSLASH );
760 set_state( parser, COMMENT );
761 return p + 1;
762 default:
763 if (iswspace(*p)) continue;
764 push_token( parser, p );
765 pop_state( parser );
766 return p;
769 parser->start = p;
770 pop_state( parser );
771 return p;
775 /* handler for parser QUOTES state */
776 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
778 const WCHAR *p;
780 for (p = pos; !is_eol( parser, p ); p++)
782 if (*p == '"')
784 if (p+1 < parser->end && p[1] == '"') /* double quotes */
786 push_token( parser, p + 1 );
787 parser->start = p + 2;
788 p++;
790 else /* end of quotes */
792 push_token( parser, p );
793 parser->start = p + 1;
794 pop_state( parser );
795 return p + 1;
799 push_token( parser, p );
800 pop_state( parser );
801 return p;
805 /* handler for parser LEADING_SPACES state */
806 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
808 const WCHAR *p;
810 for (p = pos; !is_eol( parser, p ); p++)
812 if (*p == '\\')
814 parser->start = p;
815 set_state( parser, EOL_BACKSLASH );
816 return p;
818 if (!iswspace(*p)) break;
820 parser->start = p;
821 pop_state( parser );
822 return p;
826 /* handler for parser TRAILING_SPACES state */
827 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos )
829 const WCHAR *p;
831 for (p = pos; !is_eol( parser, p ); p++)
833 if (*p == '\\')
835 set_state( parser, EOL_BACKSLASH );
836 return p;
838 if (*p && !iswspace(*p)) break;
840 pop_state( parser );
841 return p;
845 /* handler for parser COMMENT state */
846 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos )
848 const WCHAR *p = pos;
850 while (!is_eol( parser, p )) p++;
851 pop_state( parser );
852 return p;
856 static void free_inf_file( struct inf_file *file )
858 unsigned int i;
860 for (i = 0; i < file->nb_sections; i++) free( file->sections[i] );
861 free( file->filename );
862 free( file->sections );
863 free( file->fields );
864 HeapFree( GetProcessHeap(), 0, file->strings );
865 free( file );
869 /* parse a complete buffer */
870 static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end,
871 UINT *error_line )
873 static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0};
875 struct parser parser;
876 const WCHAR *pos = buffer;
878 parser.start = buffer;
879 parser.end = end;
880 parser.file = file;
881 parser.line = NULL;
882 parser.state = LINE_START;
883 parser.stack_pos = 0;
884 parser.cur_section = -1;
885 parser.line_pos = 1;
886 parser.broken_line = 0;
887 parser.error = 0;
888 parser.token_len = 0;
890 /* parser main loop */
891 while (pos) pos = (parser_funcs[parser.state])( &parser, pos );
893 /* trim excess buffer space */
894 if (file->alloc_sections > file->nb_sections)
896 file->sections = realloc( file->sections, file->nb_sections * sizeof(file->sections[0]) );
897 file->alloc_sections = file->nb_sections;
899 if (file->alloc_fields > file->nb_fields)
901 file->fields = realloc( file->fields, file->nb_fields * sizeof(file->fields[0]) );
902 file->alloc_fields = file->nb_fields;
904 file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings,
905 (file->string_pos - file->strings) * sizeof(WCHAR) );
907 if (parser.error)
909 if (error_line) *error_line = parser.line_pos;
910 return parser.error;
913 /* find the [strings] section */
914 file->strings_section = find_section( file, Strings );
916 if (file->strings_section == -1 && parser.broken_line)
918 if (error_line) *error_line = parser.broken_line;
919 return ERROR_EXPECTED_SECTION_NAME;
922 return 0;
926 /* append a child INF file to its parent list, in a thread-safe manner */
927 static void append_inf_file( struct inf_file *parent, struct inf_file *child )
929 struct inf_file **ppnext = &parent->next;
930 child->next = NULL;
932 for (;;)
934 struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL );
935 if (!next) return;
936 ppnext = &next->next;
941 /***********************************************************************
942 * parse_file
944 * parse an INF file.
946 static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, DWORD style, UINT *error_line )
948 void *buffer;
949 DWORD err = 0;
950 struct inf_file *file;
952 DWORD size = GetFileSize( handle, NULL );
953 HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL );
954 if (!mapping) return NULL;
955 buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size );
956 NtClose( mapping );
957 if (!buffer) return NULL;
959 if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) );
961 if (!(file = calloc( 1, sizeof(*file) )))
963 err = ERROR_NOT_ENOUGH_MEMORY;
964 goto done;
967 /* we won't need more strings space than the size of the file,
968 * so we can preallocate it here
970 if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
972 err = ERROR_NOT_ENOUGH_MEMORY;
973 goto done;
975 file->string_pos = file->strings;
976 file->strings_section = -1;
978 if (!RtlIsTextUnicode( buffer, size, NULL ))
980 static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf };
981 WCHAR *new_buff;
982 UINT codepage = CP_ACP;
983 UINT offset = 0;
985 if (size > sizeof(utf8_bom) && !memcmp( buffer, utf8_bom, sizeof(utf8_bom) ))
987 codepage = CP_UTF8;
988 offset = sizeof(utf8_bom);
991 if ((new_buff = malloc( size * sizeof(WCHAR) )))
993 DWORD len = MultiByteToWideChar( codepage, 0, (char *)buffer + offset,
994 size - offset, new_buff, size );
995 err = parse_buffer( file, new_buff, new_buff + len, error_line );
996 free( new_buff );
999 else
1001 WCHAR *new_buff = buffer;
1002 /* UCS-16 files should start with the Unicode BOM; we should skip it */
1003 if (*new_buff == 0xfeff)
1004 new_buff++;
1005 err = parse_buffer( file, new_buff, (WCHAR *)((char *)buffer + size), error_line );
1008 if (!err) /* now check signature */
1010 int version_index = find_section( file, Version );
1011 if (version_index != -1)
1013 struct line *line = find_line( file, version_index, Signature );
1014 if (line && line->nb_fields > 0)
1016 struct field *field = file->fields + line->first_field;
1017 if (!wcsicmp( field->text, Chicago )) goto done;
1018 if (!wcsicmp( field->text, WindowsNT )) goto done;
1019 if (!wcsicmp( field->text, Windows95 )) goto done;
1022 if (error_line) *error_line = 0;
1023 if (style & INF_STYLE_WIN4) err = ERROR_WRONG_INF_STYLE;
1026 done:
1027 UnmapViewOfFile( buffer );
1028 if (err)
1030 if (file) free_inf_file( file );
1031 SetLastError( err );
1032 file = NULL;
1034 return file;
1038 /***********************************************************************
1039 * PARSER_get_inf_filename
1041 * Retrieve the filename of an inf file.
1043 const WCHAR *PARSER_get_inf_filename( HINF hinf )
1045 struct inf_file *file = hinf;
1046 return file->filename;
1049 /***********************************************************************
1050 * PARSER_get_dest_dir
1052 * retrieve a destination dir of the form "dirid,relative_path" in the given entry.
1053 * returned buffer must be freed by caller.
1055 WCHAR *PARSER_get_dest_dir( INFCONTEXT *context )
1057 const WCHAR *dir;
1058 WCHAR *ptr, *ret;
1059 INT dirid;
1060 unsigned int len1;
1061 DWORD len2;
1063 if (!SetupGetIntField( context, 1, &dirid )) return NULL;
1064 if (!(dir = get_dirid_subst( context->Inf, dirid, &len1 ))) return NULL;
1065 if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0;
1066 if (!(ret = malloc( (len1 + len2 + 1) * sizeof(WCHAR) ))) return NULL;
1067 memcpy( ret, dir, len1 * sizeof(WCHAR) );
1068 ptr = ret + len1;
1069 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
1070 if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0;
1071 return ret;
1075 /***********************************************************************
1076 * SetupOpenInfFileA (SETUPAPI.@)
1078 HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error )
1080 UNICODE_STRING nameW, classW;
1081 HINF ret = INVALID_HANDLE_VALUE;
1083 classW.Buffer = NULL;
1084 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class ))
1086 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1087 return ret;
1089 if (RtlCreateUnicodeStringFromAsciiz( &nameW, name ))
1091 ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error );
1092 RtlFreeUnicodeString( &nameW );
1094 RtlFreeUnicodeString( &classW );
1095 return ret;
1099 /***********************************************************************
1100 * SetupOpenInfFileW (SETUPAPI.@)
1102 HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error )
1104 struct inf_file *file = NULL;
1105 HANDLE handle;
1106 WCHAR *path, *p;
1107 UINT len;
1109 if (wcschr( name, '\\' ) || wcschr( name, '/' ))
1111 if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return INVALID_HANDLE_VALUE;
1112 if (!(path = malloc( len * sizeof(WCHAR) )))
1114 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1115 return INVALID_HANDLE_VALUE;
1117 GetFullPathNameW( name, len, path, NULL );
1118 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1120 else /* try Windows directory */
1122 static const WCHAR Inf[] = {'\\','i','n','f','\\',0};
1123 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
1125 len = GetWindowsDirectoryW( NULL, 0 ) + lstrlenW(name) + 12;
1126 if (!(path = malloc( len * sizeof(WCHAR) )))
1128 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1129 return INVALID_HANDLE_VALUE;
1131 GetWindowsDirectoryW( path, len );
1132 p = path + lstrlenW(path);
1133 lstrcpyW( p, Inf );
1134 lstrcatW( p, name );
1135 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1136 if (handle == INVALID_HANDLE_VALUE)
1138 lstrcpyW( p, System32 );
1139 lstrcatW( p, name );
1140 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1144 if (handle != INVALID_HANDLE_VALUE)
1146 file = parse_file( handle, class, style, error );
1147 CloseHandle( handle );
1149 if (!file)
1151 free( path );
1152 return INVALID_HANDLE_VALUE;
1154 TRACE( "%s -> %p\n", debugstr_w(path), file );
1155 file->filename = path;
1156 SetLastError( 0 );
1157 return file;
1161 /***********************************************************************
1162 * SetupOpenAppendInfFileA (SETUPAPI.@)
1164 BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error )
1166 HINF child_hinf;
1168 if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error );
1169 child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error );
1170 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE;
1171 append_inf_file( parent_hinf, child_hinf );
1172 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf );
1173 return TRUE;
1177 /***********************************************************************
1178 * SetupOpenAppendInfFileW (SETUPAPI.@)
1180 BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error )
1182 HINF child_hinf;
1184 if (!name)
1186 INFCONTEXT context;
1187 WCHAR filename[MAX_PATH];
1188 int idx = 1;
1190 if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE;
1191 while (SetupGetStringFieldW( &context, idx++, filename, ARRAY_SIZE( filename ), NULL ))
1193 child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error );
1194 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE;
1195 append_inf_file( parent_hinf, child_hinf );
1196 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf );
1198 return TRUE;
1200 child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error );
1201 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE;
1202 append_inf_file( parent_hinf, child_hinf );
1203 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf );
1204 return TRUE;
1208 /***********************************************************************
1209 * SetupOpenMasterInf (SETUPAPI.@)
1211 HINF WINAPI SetupOpenMasterInf( VOID )
1213 static const WCHAR Layout[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0};
1214 WCHAR Buffer[MAX_PATH];
1216 GetWindowsDirectoryW( Buffer, MAX_PATH );
1217 lstrcatW( Buffer, Layout );
1218 return SetupOpenInfFileW( Buffer, NULL, INF_STYLE_WIN4, NULL);
1223 /***********************************************************************
1224 * SetupCloseInfFile (SETUPAPI.@)
1226 void WINAPI SetupCloseInfFile( HINF hinf )
1228 struct inf_file *file = hinf;
1230 if (!hinf || (hinf == INVALID_HANDLE_VALUE)) return;
1232 free_inf_file( file );
1236 /***********************************************************************
1237 * SetupEnumInfSectionsA (SETUPAPI.@)
1239 BOOL WINAPI SetupEnumInfSectionsA( HINF hinf, UINT index, PSTR buffer, DWORD size, DWORD *need )
1241 struct inf_file *file = hinf;
1243 for (file = hinf; file; file = file->next)
1245 if (index < file->nb_sections)
1247 DWORD len = WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1,
1248 NULL, 0, NULL, NULL );
1249 if (need) *need = len;
1250 if (!buffer)
1252 if (!size) return TRUE;
1253 SetLastError( ERROR_INVALID_USER_BUFFER );
1254 return FALSE;
1256 if (len > size)
1258 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1259 return FALSE;
1261 WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1, buffer, size, NULL, NULL );
1262 return TRUE;
1264 index -= file->nb_sections;
1266 SetLastError( ERROR_NO_MORE_ITEMS );
1267 return FALSE;
1271 /***********************************************************************
1272 * SetupEnumInfSectionsW (SETUPAPI.@)
1274 BOOL WINAPI SetupEnumInfSectionsW( HINF hinf, UINT index, PWSTR buffer, DWORD size, DWORD *need )
1276 struct inf_file *file = hinf;
1278 for (file = hinf; file; file = file->next)
1280 if (index < file->nb_sections)
1282 DWORD len = lstrlenW( file->sections[index]->name ) + 1;
1283 if (need) *need = len;
1284 if (!buffer)
1286 if (!size) return TRUE;
1287 SetLastError( ERROR_INVALID_USER_BUFFER );
1288 return FALSE;
1290 if (len > size)
1292 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1293 return FALSE;
1295 memcpy( buffer, file->sections[index]->name, len * sizeof(WCHAR) );
1296 return TRUE;
1298 index -= file->nb_sections;
1300 SetLastError( ERROR_NO_MORE_ITEMS );
1301 return FALSE;
1305 /***********************************************************************
1306 * SetupGetLineCountA (SETUPAPI.@)
1308 LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name )
1310 UNICODE_STRING sectionW;
1311 LONG ret = -1;
1313 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, name ))
1314 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1315 else
1317 ret = SetupGetLineCountW( hinf, sectionW.Buffer );
1318 RtlFreeUnicodeString( &sectionW );
1320 return ret;
1324 /***********************************************************************
1325 * SetupGetLineCountW (SETUPAPI.@)
1327 LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section )
1329 struct inf_file *file = hinf;
1330 int section_index;
1331 LONG ret = -1;
1333 for (file = hinf; file; file = file->next)
1335 if ((section_index = find_section( file, section )) == -1) continue;
1336 if (ret == -1) ret = 0;
1337 ret += file->sections[section_index]->nb_lines;
1339 TRACE( "(%p,%s) returning %ld\n", hinf, debugstr_w(section), ret );
1340 SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 );
1341 return ret;
1345 /***********************************************************************
1346 * SetupGetLineByIndexA (SETUPAPI.@)
1348 BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context )
1350 UNICODE_STRING sectionW;
1351 BOOL ret = FALSE;
1353 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1354 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1355 else
1357 ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context );
1358 RtlFreeUnicodeString( &sectionW );
1360 return ret;
1364 /***********************************************************************
1365 * SetupGetLineByIndexW (SETUPAPI.@)
1367 BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context )
1369 struct inf_file *file = hinf;
1370 int section_index;
1372 for (file = hinf; file; file = file->next)
1374 if ((section_index = find_section( file, section )) == -1) continue;
1375 if (index < file->sections[section_index]->nb_lines)
1377 context->Inf = hinf;
1378 context->CurrentInf = file;
1379 context->Section = section_index;
1380 context->Line = index;
1381 SetLastError( 0 );
1382 TRACE( "(%p,%s): returning %d/%ld\n",
1383 hinf, debugstr_w(section), section_index, index );
1384 return TRUE;
1386 index -= file->sections[section_index]->nb_lines;
1388 TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) );
1389 SetLastError( ERROR_LINE_NOT_FOUND );
1390 return FALSE;
1394 /***********************************************************************
1395 * SetupFindFirstLineA (SETUPAPI.@)
1397 BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context )
1399 UNICODE_STRING sectionW, keyW;
1400 BOOL ret = FALSE;
1402 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1404 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1405 return FALSE;
1408 if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context );
1409 else
1411 if (RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1413 ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context );
1414 RtlFreeUnicodeString( &keyW );
1416 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1418 RtlFreeUnicodeString( &sectionW );
1419 return ret;
1423 /***********************************************************************
1424 * SetupFindFirstLineW (SETUPAPI.@)
1426 BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context )
1428 struct inf_file *file;
1429 int section_index;
1431 for (file = hinf; file; file = file->next)
1433 if ((section_index = find_section( file, section )) == -1) continue;
1434 if (key)
1436 INFCONTEXT ctx;
1437 ctx.Inf = hinf;
1438 ctx.CurrentInf = file;
1439 ctx.Section = section_index;
1440 ctx.Line = -1;
1441 return SetupFindNextMatchLineW( &ctx, key, context );
1443 if (file->sections[section_index]->nb_lines)
1445 context->Inf = hinf;
1446 context->CurrentInf = file;
1447 context->Section = section_index;
1448 context->Line = 0;
1449 SetLastError( 0 );
1450 TRACE( "(%p,%s,%s): returning %d/0\n",
1451 hinf, debugstr_w(section), debugstr_w(key), section_index );
1452 return TRUE;
1455 TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) );
1456 SetLastError( ERROR_LINE_NOT_FOUND );
1457 return FALSE;
1461 /***********************************************************************
1462 * SetupFindNextLine (SETUPAPI.@)
1464 BOOL WINAPI SetupFindNextLine( PINFCONTEXT context_in, PINFCONTEXT context_out )
1466 struct inf_file *file = context_in->CurrentInf;
1467 struct section *section;
1469 if (context_in->Section >= file->nb_sections) goto error;
1471 section = file->sections[context_in->Section];
1472 if (context_in->Line+1 < section->nb_lines)
1474 if (context_out != context_in) *context_out = *context_in;
1475 context_out->Line++;
1476 SetLastError( 0 );
1477 return TRUE;
1480 /* now search the appended files */
1482 for (file = file->next; file; file = file->next)
1484 int section_index = find_section( file, section->name );
1485 if (section_index == -1) continue;
1486 if (file->sections[section_index]->nb_lines)
1488 context_out->Inf = context_in->Inf;
1489 context_out->CurrentInf = file;
1490 context_out->Section = section_index;
1491 context_out->Line = 0;
1492 SetLastError( 0 );
1493 return TRUE;
1496 error:
1497 SetLastError( ERROR_LINE_NOT_FOUND );
1498 return FALSE;
1502 /***********************************************************************
1503 * SetupFindNextMatchLineA (SETUPAPI.@)
1505 BOOL WINAPI SetupFindNextMatchLineA( PINFCONTEXT context_in, PCSTR key,
1506 PINFCONTEXT context_out )
1508 UNICODE_STRING keyW;
1509 BOOL ret = FALSE;
1511 if (!key) return SetupFindNextLine( context_in, context_out );
1513 if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key ))
1514 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1515 else
1517 ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out );
1518 RtlFreeUnicodeString( &keyW );
1520 return ret;
1524 /***********************************************************************
1525 * SetupFindNextMatchLineW (SETUPAPI.@)
1527 BOOL WINAPI SetupFindNextMatchLineW( PINFCONTEXT context_in, PCWSTR key,
1528 PINFCONTEXT context_out )
1530 struct inf_file *file = context_in->CurrentInf;
1531 WCHAR buffer[MAX_STRING_LEN + 1];
1532 struct section *section;
1533 struct line *line;
1534 unsigned int i;
1536 if (!key) return SetupFindNextLine( context_in, context_out );
1538 if (context_in->Section >= file->nb_sections) goto error;
1540 section = file->sections[context_in->Section];
1542 for (i = context_in->Line+1, line = &section->lines[i]; i < section->nb_lines; i++, line++)
1544 if (line->key_field == -1) continue;
1545 PARSER_string_substW( file, file->fields[line->key_field].text, buffer, ARRAY_SIZE(buffer) );
1546 if (!wcsicmp( key, buffer ))
1548 if (context_out != context_in) *context_out = *context_in;
1549 context_out->Line = i;
1550 SetLastError( 0 );
1551 TRACE( "(%p,%s,%s): returning %d\n",
1552 file, debugstr_w(section->name), debugstr_w(key), i );
1553 return TRUE;
1557 /* now search the appended files */
1559 for (file = file->next; file; file = file->next)
1561 int section_index = find_section( file, section->name );
1562 if (section_index == -1) continue;
1563 section = file->sections[section_index];
1564 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++)
1566 if (line->key_field == -1) continue;
1567 if (!wcsicmp( key, file->fields[line->key_field].text ))
1569 context_out->Inf = context_in->Inf;
1570 context_out->CurrentInf = file;
1571 context_out->Section = section_index;
1572 context_out->Line = i;
1573 SetLastError( 0 );
1574 TRACE( "(%p,%s,%s): returning %d/%d\n",
1575 file, debugstr_w(section->name), debugstr_w(key), section_index, i );
1576 return TRUE;
1580 TRACE( "(%p,%s,%s): not found\n",
1581 context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) );
1582 error:
1583 SetLastError( ERROR_LINE_NOT_FOUND );
1584 return FALSE;
1588 /***********************************************************************
1589 * SetupGetLineTextW (SETUPAPI.@)
1591 BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_name,
1592 PCWSTR key_name, PWSTR buffer, DWORD size, PDWORD required )
1594 struct inf_file *file;
1595 struct line *line;
1596 struct field *field;
1597 int i;
1598 DWORD total = 0;
1600 if (!context)
1602 INFCONTEXT new_context;
1603 if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE;
1604 file = new_context.CurrentInf;
1605 line = get_line( file, new_context.Section, new_context.Line );
1607 else
1609 file = context->CurrentInf;
1610 if (!(line = get_line( file, context->Section, context->Line )))
1612 SetLastError( ERROR_LINE_NOT_FOUND );
1613 return FALSE;
1617 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1618 total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1;
1620 if (required) *required = total;
1621 if (buffer)
1623 if (total > size)
1625 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1626 return FALSE;
1628 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1630 unsigned int len = PARSER_string_substW( file, field->text, buffer, size );
1631 if (i+1 < line->nb_fields) buffer[len] = ',';
1632 buffer += len + 1;
1635 return TRUE;
1639 /***********************************************************************
1640 * SetupGetLineTextA (SETUPAPI.@)
1642 BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_name,
1643 PCSTR key_name, PSTR buffer, DWORD size, PDWORD required )
1645 struct inf_file *file;
1646 struct line *line;
1647 struct field *field;
1648 int i;
1649 DWORD total = 0;
1651 if (!context)
1653 INFCONTEXT new_context;
1654 if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE;
1655 file = new_context.CurrentInf;
1656 line = get_line( file, new_context.Section, new_context.Line );
1658 else
1660 file = context->CurrentInf;
1661 if (!(line = get_line( file, context->Section, context->Line )))
1663 SetLastError( ERROR_LINE_NOT_FOUND );
1664 return FALSE;
1668 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1669 total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1;
1671 if (required) *required = total;
1672 if (buffer)
1674 if (total > size)
1676 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1677 return FALSE;
1679 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
1681 unsigned int len = PARSER_string_substA( file, field->text, buffer, size );
1682 if (i+1 < line->nb_fields) buffer[len] = ',';
1683 buffer += len + 1;
1686 return TRUE;
1690 /***********************************************************************
1691 * SetupGetFieldCount (SETUPAPI.@)
1693 DWORD WINAPI SetupGetFieldCount( PINFCONTEXT context )
1695 struct inf_file *file = context->CurrentInf;
1696 struct line *line = get_line( file, context->Section, context->Line );
1698 if (!line) return 0;
1699 return line->nb_fields;
1703 /***********************************************************************
1704 * SetupGetStringFieldA (SETUPAPI.@)
1706 BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer,
1707 DWORD size, PDWORD required )
1709 struct inf_file *file = context->CurrentInf;
1710 struct field *field = get_field( file, context->Section, context->Line, index );
1711 unsigned int len;
1713 SetLastError(0);
1714 if (!field) return FALSE;
1715 len = PARSER_string_substA( file, field->text, NULL, 0 );
1716 if (required) *required = len + 1;
1717 if (buffer)
1719 if (size <= len)
1721 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1722 return FALSE;
1724 PARSER_string_substA( file, field->text, buffer, size );
1726 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1727 context->Inf, context->CurrentInf, context->Section, context->Line,
1728 index, debugstr_a(buffer) );
1730 return TRUE;
1734 /***********************************************************************
1735 * SetupGetStringFieldW (SETUPAPI.@)
1737 BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer,
1738 DWORD size, PDWORD required )
1740 struct inf_file *file = context->CurrentInf;
1741 struct field *field = get_field( file, context->Section, context->Line, index );
1742 unsigned int len;
1744 SetLastError(0);
1745 if (!field) return FALSE;
1746 len = PARSER_string_substW( file, field->text, NULL, 0 );
1747 if (required) *required = len + 1;
1748 if (buffer)
1750 if (size <= len)
1752 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1753 return FALSE;
1755 PARSER_string_substW( file, field->text, buffer, size );
1757 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1758 context->Inf, context->CurrentInf, context->Section, context->Line,
1759 index, debugstr_w(buffer) );
1761 return TRUE;
1765 /***********************************************************************
1766 * SetupGetIntField (SETUPAPI.@)
1768 BOOL WINAPI SetupGetIntField( PINFCONTEXT context, DWORD index, PINT result )
1770 char localbuff[20];
1771 char *end, *buffer = localbuff;
1772 DWORD required;
1773 INT res;
1774 BOOL ret;
1776 if (!(ret = SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required )))
1778 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
1779 if (!(buffer = malloc( required ))) return FALSE;
1780 if (!(ret = SetupGetStringFieldA( context, index, buffer, required, NULL ))) goto done;
1782 /* The call to SetupGetStringFieldA succeeded. If buffer is empty we have an optional field */
1783 if (!*buffer) *result = 0;
1784 else
1786 res = strtol( buffer, &end, 0 );
1787 if (end != buffer && !*end) *result = res;
1788 else
1790 SetLastError( ERROR_INVALID_DATA );
1791 ret = FALSE;
1795 done:
1796 if (buffer != localbuff) free( buffer );
1797 return ret;
1801 static int xdigit_to_int(WCHAR c)
1803 if ('0' <= c && c <= '9') return c - '0';
1804 if ('a' <= c && c <= 'f') return c - 'a' + 10;
1805 if ('A' <= c && c <= 'F') return c - 'A' + 10;
1806 return -1;
1810 /***********************************************************************
1811 * SetupGetBinaryField (SETUPAPI.@)
1813 BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer,
1814 DWORD size, LPDWORD required )
1816 struct inf_file *file = context->CurrentInf;
1817 struct line *line = get_line( file, context->Section, context->Line );
1818 struct field *field;
1819 int i;
1821 if (!line)
1823 SetLastError( ERROR_LINE_NOT_FOUND );
1824 return FALSE;
1826 if (!index || index > line->nb_fields)
1828 SetLastError( ERROR_INVALID_PARAMETER );
1829 return FALSE;
1831 index--; /* fields start at 0 */
1832 if (required) *required = line->nb_fields - index;
1833 if (!buffer) return TRUE;
1834 if (size < line->nb_fields - index)
1836 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1837 return FALSE;
1839 field = &file->fields[line->first_field + index];
1840 for (i = index; i < line->nb_fields; i++, field++)
1842 const WCHAR *p;
1843 DWORD value = 0;
1844 int d;
1845 for (p = field->text; *p && (d = xdigit_to_int(*p)) != -1; p++)
1847 if ((value <<= 4) > 255)
1849 SetLastError( ERROR_INVALID_DATA );
1850 return FALSE;
1852 value |= d;
1854 buffer[i - index] = value;
1856 TRACE( "%p/%p/%d/%d index %ld\n",
1857 context->Inf, context->CurrentInf, context->Section, context->Line, index );
1858 return TRUE;
1862 /***********************************************************************
1863 * SetupGetMultiSzFieldA (SETUPAPI.@)
1865 BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer,
1866 DWORD size, LPDWORD required )
1868 struct inf_file *file = context->CurrentInf;
1869 struct line *line = get_line( file, context->Section, context->Line );
1870 struct field *field;
1871 unsigned int len;
1872 int i;
1873 DWORD total = 1;
1875 if (!line)
1877 SetLastError( ERROR_LINE_NOT_FOUND );
1878 return FALSE;
1880 if (!index || index > line->nb_fields)
1882 SetLastError( ERROR_INVALID_PARAMETER );
1883 return FALSE;
1885 index--; /* fields start at 0 */
1886 field = &file->fields[line->first_field + index];
1887 for (i = index; i < line->nb_fields; i++, field++)
1889 if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break;
1890 total += len + 1;
1893 if (required) *required = total;
1894 if (!buffer) return TRUE;
1895 if (total > size)
1897 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1898 return FALSE;
1900 field = &file->fields[line->first_field + index];
1901 for (i = index; i < line->nb_fields; i++, field++)
1903 if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break;
1904 buffer += len + 1;
1906 *buffer = 0; /* add final null */
1907 return TRUE;
1911 /***********************************************************************
1912 * SetupGetMultiSzFieldW (SETUPAPI.@)
1914 BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer,
1915 DWORD size, LPDWORD required )
1917 struct inf_file *file = context->CurrentInf;
1918 struct line *line = get_line( file, context->Section, context->Line );
1919 struct field *field;
1920 unsigned int len;
1921 int i;
1922 DWORD total = 1;
1924 if (!line)
1926 SetLastError( ERROR_LINE_NOT_FOUND );
1927 return FALSE;
1929 if (!index || index > line->nb_fields)
1931 SetLastError( ERROR_INVALID_PARAMETER );
1932 return FALSE;
1934 index--; /* fields start at 0 */
1935 field = &file->fields[line->first_field + index];
1936 for (i = index; i < line->nb_fields; i++, field++)
1938 if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break;
1939 total += len + 1;
1942 if (required) *required = total;
1943 if (!buffer) return TRUE;
1944 if (total > size)
1946 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1947 return FALSE;
1949 field = &file->fields[line->first_field + index];
1950 for (i = index; i < line->nb_fields; i++, field++)
1952 if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break;
1953 buffer += len + 1;
1955 *buffer = 0; /* add final null */
1956 return TRUE;
1959 /***********************************************************************
1960 * pSetupGetField (SETUPAPI.@)
1962 LPCWSTR WINAPI pSetupGetField( PINFCONTEXT context, DWORD index )
1964 struct inf_file *file = context->CurrentInf;
1965 struct field *field = get_field( file, context->Section, context->Line, index );
1967 if (!field)
1969 SetLastError( ERROR_INVALID_PARAMETER );
1970 return NULL;
1972 return field->text;