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
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 */
52 const WCHAR
*text
; /* field text */
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 */
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) */
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
;
81 int strings_section
; /* index of [Strings] section or -1 if none */
82 WCHAR
*filename
; /* filename of the INF */
85 /* parser definitions */
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 */
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
)
158 unsigned int new_count
= *count
+ *count
/ 2;
159 if (new_count
< 32) new_count
= 32;
161 new_array
= _recalloc( array
, new_count
, elem
);
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
)
185 for (i
= 0; i
< file
->nb_sections
; i
++)
186 if (!wcsicmp( name
, file
->sections
[i
]->name
)) return i
;
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
;
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
;
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
;
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
= §ion
->lines
[section
->nb_lines
++];
245 line
->first_field
= file
->nb_fields
;
247 line
->key_field
= -1;
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 §ion
->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
,
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
];
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
)
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
++];
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
)
304 if (dirid
== DIRID_SRCPATH
) return get_inf_dir( file
, len
);
305 ret
= DIRID_get_string( dirid
);
306 if (ret
) *len
= lstrlenW(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
;
323 WCHAR
*dirid_str
, *end
;
324 const WCHAR
*ret
= NULL
;
326 if (!*len
) /* empty string (%%) is replaced by single 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
);
344 not_found
: /* check for integer id */
345 if ((dirid_str
= malloc( (*len
+ 1) * sizeof(WCHAR
) )))
347 memcpy( dirid_str
, str
, *len
* sizeof(WCHAR
) );
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;
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;
369 if (!buffer
) size
= MAX_STRING_LEN
+ 1;
370 for (p
= start
= text
; *p
; p
++)
372 if (*p
!= '%') continue;
374 if (inside
) /* start of a %xx% string */
377 if (len
> size
- 1) len
= size
- 1;
378 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
383 else /* end of the %xx% string, find substitution */
386 subst
= get_string_subst( file
, start
+ 1, &len
, p
[1] == '\\' );
392 if (len
> size
- 1) len
= size
- 1;
393 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
400 if (start
!= p
) /* unfinished string, copy it */
403 if (len
> size
- 1) len
= size
- 1;
404 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
407 if (buffer
&& size
) buffer
[total
] = 0;
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];
421 unsigned int len
= PARSER_string_substW( file
, text
, buffW
, ARRAY_SIZE( buffW
));
422 if (!buffer
) RtlUnicodeToMultiByteSize( &ret
, buffW
, len
* sizeof(WCHAR
) );
425 RtlUnicodeToMultiByteN( buffer
, size
-1, &ret
, buffW
, len
* sizeof(WCHAR
) );
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;
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
;
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
: ' ';
498 /* add a section with the current token as name */
499 static int add_section_from_token( struct parser
*parser
)
503 if (parser
->token_len
> MAX_SECTION_NAME_LEN
)
505 parser
->error
= ERROR_SECTION_NAME_TOO_LONG
;
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
;
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
)
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
;
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
++;
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;
555 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
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
;
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
;
575 /* handler for parser LINE_START state */
576 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
)
580 for (p
= pos
; !is_eof( parser
, p
); p
++)
586 close_current_line( parser
);
589 push_state( parser
, LINE_START
);
590 set_state( parser
, COMMENT
);
593 parser
->start
= p
+ 1;
594 set_state( parser
, SECTION_NAME
);
597 if (iswspace(*p
)) break;
598 if (parser
->cur_section
!= -1)
601 set_state( parser
, KEY_NAME
);
604 if (!parser
->broken_line
)
605 parser
->broken_line
= parser
->line_pos
;
609 close_current_line( parser
);
614 /* handler for parser SECTION_NAME state */
615 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
)
619 for (p
= pos
; !is_eol( parser
, p
); 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 */
630 parser
->error
= ERROR_BAD_SECTION_NAME_LINE
; /* unfinished section name */
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;
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
);
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
);
660 push_token( parser
, p
);
661 parser
->start
= p
+ 1;
662 push_state( parser
, KEY_NAME
);
663 set_state( parser
, QUOTES
);
666 push_token( parser
, token_end
);
668 push_state( parser
, KEY_NAME
);
669 set_state( parser
, EOL_BACKSLASH
);
672 if (!iswspace(*p
)) token_end
= p
+ 1;
675 push_token( parser
, p
);
676 push_state( parser
, KEY_NAME
);
677 set_state( parser
, TRAILING_SPACES
);
683 push_token( parser
, token_end
);
684 set_state( parser
, VALUE_NAME
);
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
++)
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
);
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
);
712 push_token( parser
, p
);
713 parser
->start
= p
+ 1;
714 push_state( parser
, VALUE_NAME
);
715 set_state( parser
, QUOTES
);
718 push_token( parser
, token_end
);
720 push_state( parser
, VALUE_NAME
);
721 set_state( parser
, EOL_BACKSLASH
);
724 if (*p
&& !iswspace(*p
)) token_end
= p
+ 1;
727 push_token( parser
, p
);
728 push_state( parser
, VALUE_NAME
);
729 set_state( parser
, TRAILING_SPACES
);
735 push_token( parser
, token_end
);
736 if (!add_field_from_token( parser
, FALSE
)) return NULL
;
737 set_state( parser
, LINE_START
);
742 /* handler for parser EOL_BACKSLASH state */
743 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
)
747 for (p
= pos
; !is_eof( parser
, p
); p
++)
753 parser
->start
= p
+ 1;
754 set_state( parser
, LEADING_SPACES
);
759 push_state( parser
, EOL_BACKSLASH
);
760 set_state( parser
, COMMENT
);
763 if (iswspace(*p
)) continue;
764 push_token( parser
, p
);
775 /* handler for parser QUOTES state */
776 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
)
780 for (p
= pos
; !is_eol( parser
, p
); p
++)
784 if (p
+1 < parser
->end
&& p
[1] == '"') /* double quotes */
786 push_token( parser
, p
+ 1 );
787 parser
->start
= p
+ 2;
790 else /* end of quotes */
792 push_token( parser
, p
);
793 parser
->start
= p
+ 1;
799 push_token( parser
, p
);
805 /* handler for parser LEADING_SPACES state */
806 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
810 for (p
= pos
; !is_eol( parser
, p
); p
++)
815 set_state( parser
, EOL_BACKSLASH
);
818 if (!iswspace(*p
)) break;
826 /* handler for parser TRAILING_SPACES state */
827 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
831 for (p
= pos
; !is_eol( parser
, p
); p
++)
835 set_state( parser
, EOL_BACKSLASH
);
838 if (*p
&& !iswspace(*p
)) break;
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
++;
856 static void free_inf_file( struct inf_file
*file
)
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
);
869 /* parse a complete buffer */
870 static DWORD
parse_buffer( struct inf_file
*file
, const WCHAR
*buffer
, const WCHAR
*end
,
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
;
882 parser
.state
= LINE_START
;
883 parser
.stack_pos
= 0;
884 parser
.cur_section
= -1;
886 parser
.broken_line
= 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
) );
909 if (error_line
) *error_line
= parser
.line_pos
;
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
;
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
;
934 struct inf_file
*next
= InterlockedCompareExchangePointer( (void **)ppnext
, child
, NULL
);
936 ppnext
= &next
->next
;
941 /***********************************************************************
946 static struct inf_file
*parse_file( HANDLE handle
, const WCHAR
*class, DWORD style
, UINT
*error_line
)
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
);
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
;
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
;
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 };
982 UINT codepage
= CP_ACP
;
985 if (size
> sizeof(utf8_bom
) && !memcmp( buffer
, utf8_bom
, sizeof(utf8_bom
) ))
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
);
1001 WCHAR
*new_buff
= buffer
;
1002 /* UCS-16 files should start with the Unicode BOM; we should skip it */
1003 if (*new_buff
== 0xfeff)
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
;
1027 UnmapViewOfFile( buffer
);
1030 if (file
) free_inf_file( file
);
1031 SetLastError( err
);
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
)
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
) );
1069 if (len2
&& ptr
> ret
&& ptr
[-1] != '\\') *ptr
++ = '\\';
1070 if (!SetupGetStringFieldW( context
, 2, ptr
, len2
, NULL
)) *ptr
= 0;
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
);
1089 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, name
))
1091 ret
= SetupOpenInfFileW( nameW
.Buffer
, classW
.Buffer
, style
, error
);
1092 RtlFreeUnicodeString( &nameW
);
1094 RtlFreeUnicodeString( &classW
);
1099 /***********************************************************************
1100 * SetupOpenInfFileW (SETUPAPI.@)
1102 HINF WINAPI
SetupOpenInfFileW( PCWSTR name
, PCWSTR
class, DWORD style
, UINT
*error
)
1104 struct inf_file
*file
= NULL
;
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
);
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
);
1152 return INVALID_HANDLE_VALUE
;
1154 TRACE( "%s -> %p\n", debugstr_w(path
), file
);
1155 file
->filename
= path
;
1161 /***********************************************************************
1162 * SetupOpenAppendInfFileA (SETUPAPI.@)
1164 BOOL WINAPI
SetupOpenAppendInfFileA( PCSTR name
, HINF parent_hinf
, UINT
*error
)
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
);
1177 /***********************************************************************
1178 * SetupOpenAppendInfFileW (SETUPAPI.@)
1180 BOOL WINAPI
SetupOpenAppendInfFileW( PCWSTR name
, HINF parent_hinf
, UINT
*error
)
1187 WCHAR filename
[MAX_PATH
];
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
);
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
);
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
;
1252 if (!size
) return TRUE
;
1253 SetLastError( ERROR_INVALID_USER_BUFFER
);
1258 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1261 WideCharToMultiByte( CP_ACP
, 0, file
->sections
[index
]->name
, -1, buffer
, size
, NULL
, NULL
);
1264 index
-= file
->nb_sections
;
1266 SetLastError( ERROR_NO_MORE_ITEMS
);
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
;
1286 if (!size
) return TRUE
;
1287 SetLastError( ERROR_INVALID_USER_BUFFER
);
1292 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1295 memcpy( buffer
, file
->sections
[index
]->name
, len
* sizeof(WCHAR
) );
1298 index
-= file
->nb_sections
;
1300 SetLastError( ERROR_NO_MORE_ITEMS
);
1305 /***********************************************************************
1306 * SetupGetLineCountA (SETUPAPI.@)
1308 LONG WINAPI
SetupGetLineCountA( HINF hinf
, PCSTR name
)
1310 UNICODE_STRING sectionW
;
1313 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, name
))
1314 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1317 ret
= SetupGetLineCountW( hinf
, sectionW
.Buffer
);
1318 RtlFreeUnicodeString( §ionW
);
1324 /***********************************************************************
1325 * SetupGetLineCountW (SETUPAPI.@)
1327 LONG WINAPI
SetupGetLineCountW( HINF hinf
, PCWSTR section
)
1329 struct inf_file
*file
= hinf
;
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 );
1345 /***********************************************************************
1346 * SetupGetLineByIndexA (SETUPAPI.@)
1348 BOOL WINAPI
SetupGetLineByIndexA( HINF hinf
, PCSTR section
, DWORD index
, INFCONTEXT
*context
)
1350 UNICODE_STRING sectionW
;
1353 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1354 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1357 ret
= SetupGetLineByIndexW( hinf
, sectionW
.Buffer
, index
, context
);
1358 RtlFreeUnicodeString( §ionW
);
1364 /***********************************************************************
1365 * SetupGetLineByIndexW (SETUPAPI.@)
1367 BOOL WINAPI
SetupGetLineByIndexW( HINF hinf
, PCWSTR section
, DWORD index
, INFCONTEXT
*context
)
1369 struct inf_file
*file
= hinf
;
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
;
1382 TRACE( "(%p,%s): returning %d/%ld\n",
1383 hinf
, debugstr_w(section
), section_index
, index
);
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
);
1394 /***********************************************************************
1395 * SetupFindFirstLineA (SETUPAPI.@)
1397 BOOL WINAPI
SetupFindFirstLineA( HINF hinf
, PCSTR section
, PCSTR key
, INFCONTEXT
*context
)
1399 UNICODE_STRING sectionW
, keyW
;
1402 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1404 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1408 if (!key
) ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, NULL
, context
);
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( §ionW
);
1423 /***********************************************************************
1424 * SetupFindFirstLineW (SETUPAPI.@)
1426 BOOL WINAPI
SetupFindFirstLineW( HINF hinf
, PCWSTR section
, PCWSTR key
, INFCONTEXT
*context
)
1428 struct inf_file
*file
;
1431 for (file
= hinf
; file
; file
= file
->next
)
1433 if ((section_index
= find_section( file
, section
)) == -1) continue;
1438 ctx
.CurrentInf
= file
;
1439 ctx
.Section
= section_index
;
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
;
1450 TRACE( "(%p,%s,%s): returning %d/0\n",
1451 hinf
, debugstr_w(section
), debugstr_w(key
), section_index
);
1455 TRACE( "(%p,%s,%s): not found\n", hinf
, debugstr_w(section
), debugstr_w(key
) );
1456 SetLastError( ERROR_LINE_NOT_FOUND
);
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
++;
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;
1497 SetLastError( ERROR_LINE_NOT_FOUND
);
1502 /***********************************************************************
1503 * SetupFindNextMatchLineA (SETUPAPI.@)
1505 BOOL WINAPI
SetupFindNextMatchLineA( PINFCONTEXT context_in
, PCSTR key
,
1506 PINFCONTEXT context_out
)
1508 UNICODE_STRING keyW
;
1511 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1513 if (!RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1514 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1517 ret
= SetupFindNextMatchLineW( context_in
, keyW
.Buffer
, context_out
);
1518 RtlFreeUnicodeString( &keyW
);
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
;
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
= §ion
->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
;
1551 TRACE( "(%p,%s,%s): returning %d\n",
1552 file
, debugstr_w(section
->name
), debugstr_w(key
), i
);
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
;
1574 TRACE( "(%p,%s,%s): returning %d/%d\n",
1575 file
, debugstr_w(section
->name
), debugstr_w(key
), section_index
, i
);
1580 TRACE( "(%p,%s,%s): not found\n",
1581 context_in
->CurrentInf
, debugstr_w(section
->name
), debugstr_w(key
) );
1583 SetLastError( ERROR_LINE_NOT_FOUND
);
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
;
1596 struct field
*field
;
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
);
1609 file
= context
->CurrentInf
;
1610 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1612 SetLastError( ERROR_LINE_NOT_FOUND
);
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
;
1625 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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
] = ',';
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
;
1647 struct field
*field
;
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
);
1660 file
= context
->CurrentInf
;
1661 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1663 SetLastError( ERROR_LINE_NOT_FOUND
);
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
;
1676 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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
] = ',';
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
);
1714 if (!field
) return FALSE
;
1715 len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 );
1716 if (required
) *required
= len
+ 1;
1721 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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
) );
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
);
1745 if (!field
) return FALSE
;
1746 len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 );
1747 if (required
) *required
= len
+ 1;
1752 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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
) );
1765 /***********************************************************************
1766 * SetupGetIntField (SETUPAPI.@)
1768 BOOL WINAPI
SetupGetIntField( PINFCONTEXT context
, DWORD index
, PINT result
)
1771 char *end
, *buffer
= localbuff
;
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;
1786 res
= strtol( buffer
, &end
, 0 );
1787 if (end
!= buffer
&& !*end
) *result
= res
;
1790 SetLastError( ERROR_INVALID_DATA
);
1796 if (buffer
!= localbuff
) free( buffer
);
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;
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
;
1823 SetLastError( ERROR_LINE_NOT_FOUND
);
1826 if (!index
|| index
> line
->nb_fields
)
1828 SetLastError( ERROR_INVALID_PARAMETER
);
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
);
1839 field
= &file
->fields
[line
->first_field
+ index
];
1840 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1845 for (p
= field
->text
; *p
&& (d
= xdigit_to_int(*p
)) != -1; p
++)
1847 if ((value
<<= 4) > 255)
1849 SetLastError( ERROR_INVALID_DATA
);
1854 buffer
[i
- index
] = value
;
1856 TRACE( "%p/%p/%d/%d index %ld\n",
1857 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
, index
);
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
;
1877 SetLastError( ERROR_LINE_NOT_FOUND
);
1880 if (!index
|| index
> line
->nb_fields
)
1882 SetLastError( ERROR_INVALID_PARAMETER
);
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;
1893 if (required
) *required
= total
;
1894 if (!buffer
) return TRUE
;
1897 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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;
1906 *buffer
= 0; /* add final null */
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
;
1926 SetLastError( ERROR_LINE_NOT_FOUND
);
1929 if (!index
|| index
> line
->nb_fields
)
1931 SetLastError( ERROR_INVALID_PARAMETER
);
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;
1942 if (required
) *required
= total
;
1943 if (!buffer
) return TRUE
;
1946 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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;
1955 *buffer
= 0; /* add final null */
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
);
1969 SetLastError( ERROR_INVALID_PARAMETER
);