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
22 #include "wine/port.h"
39 #include "setupapi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
46 #define CONTROL_Z '\x1a'
47 #define MAX_SECTION_NAME_LEN 255
48 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
49 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
50 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
52 /* inf file structure definitions */
56 const WCHAR
*text
; /* field text */
61 int first_field
; /* index of first field in field array */
62 int nb_fields
; /* number of fields in line */
63 int key_field
; /* index of field for key or -1 if no key */
68 const WCHAR
*name
; /* section name */
69 unsigned int nb_lines
; /* number of used lines */
70 unsigned int alloc_lines
; /* total number of allocated lines in array below */
71 struct line lines
[16]; /* lines information (grown dynamically, 16 is initial size) */
76 struct inf_file
*next
; /* next appended file */
77 WCHAR
*strings
; /* buffer for string data (section names and field values) */
78 WCHAR
*string_pos
; /* position of next available string in buffer */
79 unsigned int nb_sections
; /* number of used sections */
80 unsigned int alloc_sections
; /* total number of allocated section pointers */
81 struct section
**sections
; /* section pointers array */
82 unsigned int nb_fields
;
83 unsigned int alloc_fields
;
85 int strings_section
; /* index of [Strings] section or -1 if none */
86 WCHAR
*filename
; /* filename of the INF */
89 /* parser definitions */
93 LINE_START
, /* at beginning of a line */
94 SECTION_NAME
, /* parsing a section name */
95 KEY_NAME
, /* parsing a key name */
96 VALUE_NAME
, /* parsing a value name */
97 EOL_BACKSLASH
, /* backslash at end of line */
98 QUOTES
, /* inside quotes */
99 LEADING_SPACES
, /* leading spaces */
100 TRAILING_SPACES
, /* trailing spaces */
101 COMMENT
, /* inside a comment */
107 const WCHAR
*start
; /* start position of item being parsed */
108 const WCHAR
*end
; /* end of buffer */
109 struct inf_file
*file
; /* file being built */
110 enum parser_state state
; /* current parser state */
111 enum parser_state stack
[4]; /* state stack */
112 int stack_pos
; /* current pos in stack */
114 int cur_section
; /* index of section being parsed*/
115 struct line
*line
; /* current line */
116 unsigned int line_pos
; /* current line position in file */
117 unsigned int error
; /* error code */
118 unsigned int token_len
; /* current token len */
119 WCHAR token
[MAX_FIELD_LEN
+1]; /* current token */
122 typedef const WCHAR
* (*parser_state_func
)( struct parser
*parser
, const WCHAR
*pos
);
124 /* parser state machine functions */
125 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
);
126 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
);
127 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
);
128 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
);
129 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
);
130 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
);
131 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
132 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
133 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
);
135 static const parser_state_func parser_funcs
[NB_PARSER_STATES
] =
137 line_start_state
, /* LINE_START */
138 section_name_state
, /* SECTION_NAME */
139 key_name_state
, /* KEY_NAME */
140 value_name_state
, /* VALUE_NAME */
141 eol_backslash_state
, /* EOL_BACKSLASH */
142 quotes_state
, /* QUOTES */
143 leading_spaces_state
, /* LEADING_SPACES */
144 trailing_spaces_state
, /* TRAILING_SPACES */
145 comment_state
/* COMMENT */
149 /* Unicode string constants */
150 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
151 static const WCHAR Signature
[] = {'S','i','g','n','a','t','u','r','e',0};
152 static const WCHAR Chicago
[] = {'$','C','h','i','c','a','g','o','$',0};
153 static const WCHAR WindowsNT
[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
154 static const WCHAR Windows95
[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
155 static const WCHAR LayoutFile
[] = {'L','a','y','o','u','t','F','i','l','e',0};
157 /* extend an array, allocating more memory if necessary */
158 static void *grow_array( void *array
, unsigned int *count
, size_t elem
)
161 unsigned int new_count
= *count
+ *count
/ 2;
162 if (new_count
< 32) new_count
= 32;
165 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, array
, new_count
* elem
);
167 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* elem
);
172 HeapFree( GetProcessHeap(), 0, array
);
177 /* get the directory of the inf file (as counted string, not null-terminated) */
178 static const WCHAR
*get_inf_dir( struct inf_file
*file
, unsigned int *len
)
180 const WCHAR
*p
= strrchrW( file
->filename
, '\\' );
181 *len
= p
? (p
+ 1 - file
->filename
) : 0;
182 return file
->filename
;
186 /* find a section by name */
187 static int find_section( struct inf_file
*file
, const WCHAR
*name
)
191 for (i
= 0; i
< file
->nb_sections
; i
++)
192 if (!strcmpiW( name
, file
->sections
[i
]->name
)) return i
;
197 /* find a line by name */
198 static struct line
*find_line( struct inf_file
*file
, int section_index
, const WCHAR
*name
)
200 struct section
*section
;
204 if (section_index
< 0 || section_index
>= file
->nb_sections
) return NULL
;
205 section
= file
->sections
[section_index
];
206 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
208 if (line
->key_field
== -1) continue;
209 if (!strcmpiW( name
, file
->fields
[line
->key_field
].text
)) return line
;
215 /* add a section to the file and return the section index */
216 static int add_section( struct inf_file
*file
, const WCHAR
*name
)
218 struct section
*section
;
220 if (file
->nb_sections
>= file
->alloc_sections
)
222 if (!(file
->sections
= grow_array( file
->sections
, &file
->alloc_sections
,
223 sizeof(file
->sections
[0]) ))) return -1;
225 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) ))) return -1;
226 section
->name
= name
;
227 section
->nb_lines
= 0;
228 section
->alloc_lines
= sizeof(section
->lines
)/sizeof(section
->lines
[0]);
229 file
->sections
[file
->nb_sections
] = section
;
230 return file
->nb_sections
++;
234 /* add a line to a given section */
235 static struct line
*add_line( struct inf_file
*file
, int section_index
)
237 struct section
*section
;
240 assert( section_index
>= 0 && section_index
< file
->nb_sections
);
242 section
= file
->sections
[section_index
];
243 if (section
->nb_lines
== section
->alloc_lines
) /* need to grow the section */
245 int size
= sizeof(*section
) - sizeof(section
->lines
) + 2*section
->alloc_lines
*sizeof(*line
);
246 if (!(section
= HeapReAlloc( GetProcessHeap(), 0, section
, size
))) return NULL
;
247 section
->alloc_lines
*= 2;
248 file
->sections
[section_index
] = section
;
250 line
= §ion
->lines
[section
->nb_lines
++];
251 line
->first_field
= file
->nb_fields
;
253 line
->key_field
= -1;
258 /* retrieve a given line from section/line index */
259 static inline struct line
*get_line( struct inf_file
*file
, unsigned int section_index
,
260 unsigned int line_index
)
262 struct section
*section
;
264 if (section_index
>= file
->nb_sections
) return NULL
;
265 section
= file
->sections
[section_index
];
266 if (line_index
>= section
->nb_lines
) return NULL
;
267 return §ion
->lines
[line_index
];
271 /* retrieve a given field from section/line/field index */
272 static struct field
*get_field( struct inf_file
*file
, int section_index
, int line_index
,
275 struct line
*line
= get_line( file
, section_index
, line_index
);
277 if (!line
) return NULL
;
278 if (!field_index
) /* get the key */
280 if (line
->key_field
== -1) return NULL
;
281 return &file
->fields
[line
->key_field
];
284 if (field_index
>= line
->nb_fields
) return NULL
;
285 return &file
->fields
[line
->first_field
+ field_index
];
289 /* allocate a new field, growing the array if necessary */
290 static struct field
*add_field( struct inf_file
*file
, const WCHAR
*text
)
294 if (file
->nb_fields
>= file
->alloc_fields
)
296 if (!(file
->fields
= grow_array( file
->fields
, &file
->alloc_fields
,
297 sizeof(file
->fields
[0]) ))) return NULL
;
299 field
= &file
->fields
[file
->nb_fields
++];
305 /* retrieve the string substitution for a directory id */
306 static const WCHAR
*get_dirid_subst( struct inf_file
*file
, int dirid
, unsigned int *len
)
310 if (dirid
== DIRID_SRCPATH
) return get_inf_dir( file
, len
);
311 ret
= DIRID_get_string( dirid
);
312 if (ret
) *len
= strlenW(ret
);
317 /* retrieve the string substitution for a given string, or NULL if not found */
318 /* if found, len is set to the substitution length */
319 static const WCHAR
*get_string_subst( struct inf_file
*file
, const WCHAR
*str
, unsigned int *len
)
321 static const WCHAR percent
= '%';
323 struct section
*strings_section
;
328 WCHAR
*dirid_str
, *end
;
329 const WCHAR
*ret
= NULL
;
331 if (!*len
) /* empty string (%%) is replaced by single percent */
336 if (file
->strings_section
== -1) goto not_found
;
337 strings_section
= file
->sections
[file
->strings_section
];
338 for (i
= 0, line
= strings_section
->lines
; i
< strings_section
->nb_lines
; i
++, line
++)
340 if (line
->key_field
== -1) continue;
341 if (strncmpiW( str
, file
->fields
[line
->key_field
].text
, *len
)) continue;
342 if (!file
->fields
[line
->key_field
].text
[*len
]) break;
344 if (i
== strings_section
->nb_lines
|| !line
->nb_fields
) goto not_found
;
345 field
= &file
->fields
[line
->first_field
];
346 *len
= strlenW( field
->text
);
349 not_found
: /* check for integer id */
350 if ((dirid_str
= HeapAlloc( GetProcessHeap(), 0, (*len
+1) * sizeof(WCHAR
) )))
352 memcpy( dirid_str
, str
, *len
* sizeof(WCHAR
) );
354 dirid
= strtolW( dirid_str
, &end
, 10 );
355 if (!*end
) ret
= get_dirid_subst( file
, dirid
, len
);
356 HeapFree( GetProcessHeap(), 0, dirid_str
);
363 /* do string substitutions on the specified text */
364 /* the buffer is assumed to be large enough */
365 /* returns necessary length not including terminating null */
366 unsigned int PARSER_string_substW( struct inf_file
*file
, const WCHAR
*text
, WCHAR
*buffer
,
369 const WCHAR
*start
, *subst
, *p
;
370 unsigned int len
, total
= 0;
373 if (!buffer
) size
= MAX_STRING_LEN
+ 1;
374 for (p
= start
= text
; *p
; p
++)
376 if (*p
!= '%') continue;
378 if (inside
) /* start of a %xx% string */
381 if (len
> size
- 1) len
= size
- 1;
382 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
387 else /* end of the %xx% string, find substitution */
390 subst
= get_string_subst( file
, start
+ 1, &len
);
396 if (len
> size
- 1) len
= size
- 1;
397 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
404 if (start
!= p
) /* unfinished string, copy it */
407 if (len
> size
- 1) len
= size
- 1;
408 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
411 if (buffer
&& size
) buffer
[total
] = 0;
416 /* do string substitutions on the specified text */
417 /* the buffer is assumed to be large enough */
418 /* returns necessary length not including terminating null */
419 unsigned int PARSER_string_substA( struct inf_file
*file
, const WCHAR
*text
, char *buffer
,
422 WCHAR buffW
[MAX_STRING_LEN
+1];
425 unsigned int len
= PARSER_string_substW( file
, text
, buffW
, sizeof(buffW
)/sizeof(WCHAR
) );
426 if (!buffer
) RtlUnicodeToMultiByteSize( &ret
, buffW
, len
* sizeof(WCHAR
) );
429 RtlUnicodeToMultiByteN( buffer
, size
-1, &ret
, buffW
, len
* sizeof(WCHAR
) );
436 /* push some string data into the strings buffer */
437 static WCHAR
*push_string( struct inf_file
*file
, const WCHAR
*string
)
439 WCHAR
*ret
= file
->string_pos
;
440 strcpyW( ret
, string
);
441 file
->string_pos
+= strlenW( ret
) + 1;
446 /* push the current state on the parser stack */
447 static inline void push_state( struct parser
*parser
, enum parser_state state
)
449 assert( parser
->stack_pos
< sizeof(parser
->stack
)/sizeof(parser
->stack
[0]) );
450 parser
->stack
[parser
->stack_pos
++] = state
;
454 /* pop the current state */
455 static inline void pop_state( struct parser
*parser
)
457 assert( parser
->stack_pos
);
458 parser
->state
= parser
->stack
[--parser
->stack_pos
];
462 /* set the parser state and return the previous one */
463 static inline enum parser_state
set_state( struct parser
*parser
, enum parser_state state
)
465 enum parser_state ret
= parser
->state
;
466 parser
->state
= state
;
471 /* check if the pointer points to an end of file */
472 static inline int is_eof( struct parser
*parser
, const WCHAR
*ptr
)
474 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
);
478 /* check if the pointer points to an end of line */
479 static inline int is_eol( struct parser
*parser
, const WCHAR
*ptr
)
481 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
|| *ptr
== '\n');
485 /* push data from current token start up to pos into the current token */
486 static int push_token( struct parser
*parser
, const WCHAR
*pos
)
488 int len
= pos
- parser
->start
;
489 const WCHAR
*src
= parser
->start
;
490 WCHAR
*dst
= parser
->token
+ parser
->token_len
;
492 if (len
> MAX_FIELD_LEN
- parser
->token_len
) len
= MAX_FIELD_LEN
- parser
->token_len
;
494 parser
->token_len
+= len
;
495 for ( ; len
> 0; len
--, dst
++, src
++) *dst
= *src
? *src
: ' ';
502 /* add a section with the current token as name */
503 static int add_section_from_token( struct parser
*parser
)
507 if (parser
->token_len
> MAX_SECTION_NAME_LEN
)
509 parser
->error
= ERROR_SECTION_NAME_TOO_LONG
;
512 if ((section_index
= find_section( parser
->file
, parser
->token
)) == -1)
514 /* need to create a new one */
515 const WCHAR
*name
= push_string( parser
->file
, parser
->token
);
516 if ((section_index
= add_section( parser
->file
, name
)) == -1)
518 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
522 parser
->token_len
= 0;
523 parser
->cur_section
= section_index
;
524 return section_index
;
528 /* add a field containing the current token to the current line */
529 static struct field
*add_field_from_token( struct parser
*parser
, int is_key
)
534 if (!parser
->line
) /* need to start a new line */
536 if (parser
->cur_section
== -1) /* got a line before the first section */
538 parser
->error
= ERROR_EXPECTED_SECTION_NAME
;
541 if (!(parser
->line
= add_line( parser
->file
, parser
->cur_section
))) goto error
;
543 else assert(!is_key
);
545 text
= push_string( parser
->file
, parser
->token
);
546 if ((field
= add_field( parser
->file
, text
)))
548 if (!is_key
) parser
->line
->nb_fields
++;
551 /* replace first field by key field */
552 parser
->line
->key_field
= parser
->line
->first_field
;
553 parser
->line
->first_field
++;
555 parser
->token_len
= 0;
559 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
564 /* close the current line and prepare for parsing a new one */
565 static void close_current_line( struct parser
*parser
)
567 struct line
*cur_line
= parser
->line
;
571 /* if line has a single field and no key, the field is the key too */
572 if (cur_line
->nb_fields
== 1 && cur_line
->key_field
== -1)
573 cur_line
->key_field
= cur_line
->first_field
;
579 /* handler for parser LINE_START state */
580 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
)
584 for (p
= pos
; !is_eof( parser
, p
); p
++)
590 close_current_line( parser
);
593 push_state( parser
, LINE_START
);
594 set_state( parser
, COMMENT
);
597 parser
->start
= p
+ 1;
598 set_state( parser
, SECTION_NAME
);
604 set_state( parser
, KEY_NAME
);
610 close_current_line( parser
);
615 /* handler for parser SECTION_NAME state */
616 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
)
620 for (p
= pos
; !is_eol( parser
, p
); p
++)
624 push_token( parser
, p
);
625 if (add_section_from_token( parser
) == -1) return NULL
;
626 push_state( parser
, LINE_START
);
627 set_state( parser
, COMMENT
); /* ignore everything else on the line */
631 parser
->error
= ERROR_BAD_SECTION_NAME_LINE
; /* unfinished section name */
636 /* handler for parser KEY_NAME state */
637 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
)
639 const WCHAR
*p
, *token_end
= parser
->start
;
641 for (p
= pos
; !is_eol( parser
, p
); p
++)
643 if (*p
== ',') break;
648 push_token( parser
, token_end
);
649 if (!add_field_from_token( parser
, 1 )) return NULL
;
650 parser
->start
= p
+ 1;
651 push_state( parser
, VALUE_NAME
);
652 set_state( parser
, LEADING_SPACES
);
655 push_token( parser
, token_end
);
656 if (!add_field_from_token( parser
, 0 )) return NULL
;
657 push_state( parser
, LINE_START
);
658 set_state( parser
, COMMENT
);
661 push_token( parser
, p
);
662 parser
->start
= p
+ 1;
663 push_state( parser
, KEY_NAME
);
664 set_state( parser
, QUOTES
);
667 push_token( parser
, token_end
);
669 push_state( parser
, KEY_NAME
);
670 set_state( parser
, EOL_BACKSLASH
);
673 if (!isspaceW(*p
)) token_end
= p
+ 1;
676 push_token( parser
, p
);
677 push_state( parser
, KEY_NAME
);
678 set_state( parser
, TRAILING_SPACES
);
684 push_token( parser
, token_end
);
685 set_state( parser
, VALUE_NAME
);
690 /* handler for parser VALUE_NAME state */
691 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
)
693 const WCHAR
*p
, *token_end
= parser
->start
;
695 for (p
= pos
; !is_eol( parser
, p
); p
++)
700 push_token( parser
, token_end
);
701 if (!add_field_from_token( parser
, 0 )) return NULL
;
702 push_state( parser
, LINE_START
);
703 set_state( parser
, COMMENT
);
706 push_token( parser
, token_end
);
707 if (!add_field_from_token( parser
, 0 )) return NULL
;
708 parser
->start
= p
+ 1;
709 push_state( parser
, VALUE_NAME
);
710 set_state( parser
, LEADING_SPACES
);
713 push_token( parser
, p
);
714 parser
->start
= p
+ 1;
715 push_state( parser
, VALUE_NAME
);
716 set_state( parser
, QUOTES
);
719 push_token( parser
, token_end
);
721 push_state( parser
, VALUE_NAME
);
722 set_state( parser
, EOL_BACKSLASH
);
725 if (!isspaceW(*p
)) token_end
= p
+ 1;
728 push_token( parser
, p
);
729 push_state( parser
, VALUE_NAME
);
730 set_state( parser
, TRAILING_SPACES
);
736 push_token( parser
, token_end
);
737 if (!add_field_from_token( parser
, 0 )) return NULL
;
738 set_state( parser
, LINE_START
);
743 /* handler for parser EOL_BACKSLASH state */
744 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
)
748 for (p
= pos
; !is_eof( parser
, p
); p
++)
754 parser
->start
= p
+ 1;
755 set_state( parser
, LEADING_SPACES
);
760 push_state( parser
, EOL_BACKSLASH
);
761 set_state( parser
, COMMENT
);
764 if (isspaceW(*p
)) continue;
765 push_token( parser
, p
);
776 /* handler for parser QUOTES state */
777 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
)
779 const WCHAR
*p
, *token_end
= parser
->start
;
781 for (p
= pos
; !is_eol( parser
, p
); p
++)
785 if (p
+1 < parser
->end
&& p
[1] == '"') /* double quotes */
787 push_token( parser
, p
+ 1 );
788 parser
->start
= token_end
= p
+ 2;
791 else /* end of quotes */
793 push_token( parser
, p
);
794 parser
->start
= p
+ 1;
800 push_token( parser
, p
);
806 /* handler for parser LEADING_SPACES state */
807 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
811 for (p
= pos
; !is_eol( parser
, p
); p
++)
816 set_state( parser
, EOL_BACKSLASH
);
819 if (!isspaceW(*p
)) break;
827 /* handler for parser TRAILING_SPACES state */
828 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
832 for (p
= pos
; !is_eol( parser
, p
); p
++)
836 set_state( parser
, EOL_BACKSLASH
);
839 if (!isspaceW(*p
)) break;
846 /* handler for parser COMMENT state */
847 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
)
849 const WCHAR
*p
= pos
;
851 while (!is_eol( parser
, p
)) p
++;
857 /* parse a complete buffer */
858 static DWORD
parse_buffer( struct inf_file
*file
, const WCHAR
*buffer
, const WCHAR
*end
,
861 static const WCHAR Strings
[] = {'S','t','r','i','n','g','s',0};
863 struct parser parser
;
864 const WCHAR
*pos
= buffer
;
866 parser
.start
= buffer
;
870 parser
.state
= LINE_START
;
871 parser
.stack_pos
= 0;
872 parser
.cur_section
= -1;
875 parser
.token_len
= 0;
877 /* parser main loop */
878 while (pos
) pos
= (parser_funcs
[parser
.state
])( &parser
, pos
);
880 /* trim excess buffer space */
881 if (file
->alloc_sections
> file
->nb_sections
)
883 file
->sections
= HeapReAlloc( GetProcessHeap(), 0, file
->sections
,
884 file
->nb_sections
* sizeof(file
->sections
[0]) );
885 file
->alloc_sections
= file
->nb_sections
;
887 if (file
->alloc_fields
> file
->nb_fields
)
889 file
->fields
= HeapReAlloc( GetProcessHeap(), 0, file
->fields
,
890 file
->nb_fields
* sizeof(file
->fields
[0]) );
891 file
->alloc_fields
= file
->nb_fields
;
893 file
->strings
= HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY
, file
->strings
,
894 (file
->string_pos
- file
->strings
) * sizeof(WCHAR
) );
898 if (error_line
) *error_line
= parser
.line_pos
;
902 /* find the [strings] section */
903 file
->strings_section
= find_section( file
, Strings
);
908 /* append a child INF file to its parent list, in a thread-safe manner */
909 static void append_inf_file( struct inf_file
*parent
, struct inf_file
*child
)
911 struct inf_file
**ppnext
= &parent
->next
;
916 struct inf_file
*next
= InterlockedCompareExchangePointer( (void **)ppnext
, child
, NULL
);
918 ppnext
= &next
->next
;
923 /***********************************************************************
928 static struct inf_file
*parse_file( HANDLE handle
, const WCHAR
*class, DWORD style
, UINT
*error_line
)
932 struct inf_file
*file
;
934 DWORD size
= GetFileSize( handle
, NULL
);
935 HANDLE mapping
= CreateFileMappingW( handle
, NULL
, PAGE_READONLY
, 0, size
, NULL
);
936 if (!mapping
) return NULL
;
937 buffer
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, size
);
939 if (!buffer
) return NULL
;
941 if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) );
943 if (!(file
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*file
) )))
945 err
= ERROR_NOT_ENOUGH_MEMORY
;
949 /* we won't need more strings space than the size of the file,
950 * so we can preallocate it here
952 if (!(file
->strings
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
954 err
= ERROR_NOT_ENOUGH_MEMORY
;
957 file
->string_pos
= file
->strings
;
958 file
->strings_section
= -1;
960 if (!RtlIsTextUnicode( buffer
, size
, NULL
))
962 static const BYTE utf8_bom
[3] = { 0xef, 0xbb, 0xbf };
964 UINT codepage
= CP_ACP
;
967 if (size
> sizeof(utf8_bom
) && !memcmp( buffer
, utf8_bom
, sizeof(utf8_bom
) ))
970 offset
= sizeof(utf8_bom
);
973 if ((new_buff
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
975 DWORD len
= MultiByteToWideChar( codepage
, 0, (char *)buffer
+ offset
,
976 size
- offset
, new_buff
, size
);
977 err
= parse_buffer( file
, new_buff
, new_buff
+ len
, error_line
);
978 HeapFree( GetProcessHeap(), 0, new_buff
);
983 WCHAR
*new_buff
= (WCHAR
*)buffer
;
984 /* UCS-16 files should start with the Unicode BOM; we should skip it */
985 if (*new_buff
== 0xfeff)
987 err
= parse_buffer( file
, new_buff
, (WCHAR
*)((char *)buffer
+ size
), error_line
);
990 if (!err
) /* now check signature */
992 int version_index
= find_section( file
, Version
);
993 if (version_index
!= -1)
995 struct line
*line
= find_line( file
, version_index
, Signature
);
996 if (line
&& line
->nb_fields
> 0)
998 struct field
*field
= file
->fields
+ line
->first_field
;
999 if (!strcmpiW( field
->text
, Chicago
)) goto done
;
1000 if (!strcmpiW( field
->text
, WindowsNT
)) goto done
;
1001 if (!strcmpiW( field
->text
, Windows95
)) goto done
;
1004 if (error_line
) *error_line
= 0;
1005 if (style
& INF_STYLE_WIN4
) err
= ERROR_WRONG_INF_STYLE
;
1009 UnmapViewOfFile( buffer
);
1012 HeapFree( GetProcessHeap(), 0, file
);
1013 SetLastError( err
);
1020 /***********************************************************************
1021 * PARSER_get_inf_filename
1023 * Retrieve the filename of an inf file.
1025 const WCHAR
*PARSER_get_inf_filename( HINF hinf
)
1027 struct inf_file
*file
= hinf
;
1028 return file
->filename
;
1032 /***********************************************************************
1033 * PARSER_get_src_root
1035 * Retrieve the source directory of an inf file.
1037 WCHAR
*PARSER_get_src_root( HINF hinf
)
1040 const WCHAR
*dir
= get_inf_dir( hinf
, &len
);
1041 WCHAR
*ret
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) );
1044 memcpy( ret
, dir
, len
* sizeof(WCHAR
) );
1051 /***********************************************************************
1052 * PARSER_get_dest_dir
1054 * retrieve a destination dir of the form "dirid,relative_path" in the given entry.
1055 * returned buffer must be freed by caller.
1057 WCHAR
*PARSER_get_dest_dir( INFCONTEXT
*context
)
1065 if (!SetupGetIntField( context
, 1, &dirid
)) return NULL
;
1066 if (!(dir
= get_dirid_subst( context
->Inf
, dirid
, &len1
))) return NULL
;
1067 if (!SetupGetStringFieldW( context
, 2, NULL
, 0, &len2
)) len2
= 0;
1068 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, (len1
+len2
+1) * sizeof(WCHAR
) ))) return NULL
;
1069 memcpy( ret
, dir
, len1
* sizeof(WCHAR
) );
1071 if (len2
&& ptr
> ret
&& ptr
[-1] != '\\') *ptr
++ = '\\';
1072 if (!SetupGetStringFieldW( context
, 2, ptr
, len2
, NULL
)) *ptr
= 0;
1077 /***********************************************************************
1078 * SetupOpenInfFileA (SETUPAPI.@)
1080 HINF WINAPI
SetupOpenInfFileA( PCSTR name
, PCSTR
class, DWORD style
, UINT
*error
)
1082 UNICODE_STRING nameW
, classW
;
1083 HINF ret
= (HINF
)INVALID_HANDLE_VALUE
;
1085 classW
.Buffer
= NULL
;
1086 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW
, class ))
1088 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1091 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, name
))
1093 ret
= SetupOpenInfFileW( nameW
.Buffer
, classW
.Buffer
, style
, error
);
1094 RtlFreeUnicodeString( &nameW
);
1096 RtlFreeUnicodeString( &classW
);
1101 /***********************************************************************
1102 * SetupOpenInfFileW (SETUPAPI.@)
1104 HINF WINAPI
SetupOpenInfFileW( PCWSTR name
, PCWSTR
class, DWORD style
, UINT
*error
)
1106 struct inf_file
*file
= NULL
;
1111 if (strchrW( name
, '\\' ) || strchrW( name
, '/' ))
1113 if (!(len
= GetFullPathNameW( name
, 0, NULL
, NULL
))) return (HINF
)INVALID_HANDLE_VALUE
;
1114 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1116 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1117 return (HINF
)INVALID_HANDLE_VALUE
;
1119 GetFullPathNameW( name
, len
, path
, NULL
);
1120 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1122 else /* try Windows directory */
1124 static const WCHAR Inf
[] = {'\\','i','n','f','\\',0};
1125 static const WCHAR System32
[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
1127 len
= GetWindowsDirectoryW( NULL
, 0 ) + strlenW(name
) + 12;
1128 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1130 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1131 return (HINF
)INVALID_HANDLE_VALUE
;
1133 GetWindowsDirectoryW( path
, len
);
1134 p
= path
+ strlenW(path
);
1137 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1138 if (handle
== INVALID_HANDLE_VALUE
)
1140 strcpyW( p
, System32
);
1142 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1146 if (handle
!= INVALID_HANDLE_VALUE
)
1148 file
= parse_file( handle
, class, style
, error
);
1149 CloseHandle( handle
);
1153 HeapFree( GetProcessHeap(), 0, path
);
1154 return (HINF
)INVALID_HANDLE_VALUE
;
1156 TRACE( "%s -> %p\n", debugstr_w(path
), file
);
1157 file
->filename
= path
;
1163 /***********************************************************************
1164 * SetupOpenAppendInfFileA (SETUPAPI.@)
1166 BOOL WINAPI
SetupOpenAppendInfFileA( PCSTR name
, HINF parent_hinf
, UINT
*error
)
1170 if (!name
) return SetupOpenAppendInfFileW( NULL
, parent_hinf
, error
);
1171 child_hinf
= SetupOpenInfFileA( name
, NULL
, INF_STYLE_WIN4
, error
);
1172 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1173 append_inf_file( parent_hinf
, child_hinf
);
1174 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_a(name
), child_hinf
);
1179 /***********************************************************************
1180 * SetupOpenAppendInfFileW (SETUPAPI.@)
1182 BOOL WINAPI
SetupOpenAppendInfFileW( PCWSTR name
, HINF parent_hinf
, UINT
*error
)
1189 WCHAR filename
[MAX_PATH
];
1192 if (!SetupFindFirstLineW( parent_hinf
, Version
, LayoutFile
, &context
)) return FALSE
;
1193 while (SetupGetStringFieldW( &context
, idx
++, filename
,
1194 sizeof(filename
)/sizeof(WCHAR
), NULL
))
1196 child_hinf
= SetupOpenInfFileW( filename
, NULL
, INF_STYLE_WIN4
, error
);
1197 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1198 append_inf_file( parent_hinf
, child_hinf
);
1199 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(filename
), child_hinf
);
1203 child_hinf
= SetupOpenInfFileW( name
, NULL
, INF_STYLE_WIN4
, error
);
1204 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1205 append_inf_file( parent_hinf
, child_hinf
);
1206 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(name
), child_hinf
);
1211 /***********************************************************************
1212 * SetupOpenMasterInf (SETUPAPI.@)
1214 HINF WINAPI
SetupOpenMasterInf( VOID
)
1216 static const WCHAR Layout
[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0};
1217 WCHAR Buffer
[MAX_PATH
];
1219 GetWindowsDirectoryW( Buffer
, MAX_PATH
);
1220 strcatW( Buffer
, Layout
);
1221 return SetupOpenInfFileW( Buffer
, NULL
, INF_STYLE_WIN4
, NULL
);
1226 /***********************************************************************
1227 * SetupCloseInfFile (SETUPAPI.@)
1229 void WINAPI
SetupCloseInfFile( HINF hinf
)
1231 struct inf_file
*file
= hinf
;
1234 if (!hinf
|| (hinf
== INVALID_HANDLE_VALUE
)) return;
1236 for (i
= 0; i
< file
->nb_sections
; i
++) HeapFree( GetProcessHeap(), 0, file
->sections
[i
] );
1237 HeapFree( GetProcessHeap(), 0, file
->filename
);
1238 HeapFree( GetProcessHeap(), 0, file
->sections
);
1239 HeapFree( GetProcessHeap(), 0, file
->fields
);
1240 HeapFree( GetProcessHeap(), 0, file
->strings
);
1241 HeapFree( GetProcessHeap(), 0, file
);
1245 /***********************************************************************
1246 * SetupGetLineCountA (SETUPAPI.@)
1248 LONG WINAPI
SetupGetLineCountA( HINF hinf
, PCSTR name
)
1250 UNICODE_STRING sectionW
;
1253 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, name
))
1254 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1257 ret
= SetupGetLineCountW( hinf
, sectionW
.Buffer
);
1258 RtlFreeUnicodeString( §ionW
);
1264 /***********************************************************************
1265 * SetupGetLineCountW (SETUPAPI.@)
1267 LONG WINAPI
SetupGetLineCountW( HINF hinf
, PCWSTR section
)
1269 struct inf_file
*file
= hinf
;
1273 for (file
= hinf
; file
; file
= file
->next
)
1275 if ((section_index
= find_section( file
, section
)) == -1) continue;
1276 if (ret
== -1) ret
= 0;
1277 ret
+= file
->sections
[section_index
]->nb_lines
;
1279 TRACE( "(%p,%s) returning %d\n", hinf
, debugstr_w(section
), ret
);
1280 SetLastError( (ret
== -1) ? ERROR_SECTION_NOT_FOUND
: 0 );
1285 /***********************************************************************
1286 * SetupGetLineByIndexA (SETUPAPI.@)
1288 BOOL WINAPI
SetupGetLineByIndexA( HINF hinf
, PCSTR section
, DWORD index
, INFCONTEXT
*context
)
1290 UNICODE_STRING sectionW
;
1293 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1294 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1297 ret
= SetupGetLineByIndexW( hinf
, sectionW
.Buffer
, index
, context
);
1298 RtlFreeUnicodeString( §ionW
);
1304 /***********************************************************************
1305 * SetupGetLineByIndexW (SETUPAPI.@)
1307 BOOL WINAPI
SetupGetLineByIndexW( HINF hinf
, PCWSTR section
, DWORD index
, INFCONTEXT
*context
)
1309 struct inf_file
*file
= hinf
;
1312 SetLastError( ERROR_SECTION_NOT_FOUND
);
1313 for (file
= hinf
; file
; file
= file
->next
)
1315 if ((section_index
= find_section( file
, section
)) == -1) continue;
1316 SetLastError( ERROR_LINE_NOT_FOUND
);
1317 if (index
< file
->sections
[section_index
]->nb_lines
)
1319 context
->Inf
= hinf
;
1320 context
->CurrentInf
= file
;
1321 context
->Section
= section_index
;
1322 context
->Line
= index
;
1324 TRACE( "(%p,%s): returning %d/%d\n",
1325 hinf
, debugstr_w(section
), section_index
, index
);
1328 index
-= file
->sections
[section_index
]->nb_lines
;
1330 TRACE( "(%p,%s) not found\n", hinf
, debugstr_w(section
) );
1335 /***********************************************************************
1336 * SetupFindFirstLineA (SETUPAPI.@)
1338 BOOL WINAPI
SetupFindFirstLineA( HINF hinf
, PCSTR section
, PCSTR key
, INFCONTEXT
*context
)
1340 UNICODE_STRING sectionW
, keyW
;
1343 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1345 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1349 if (!key
) ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, NULL
, context
);
1352 if (RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1354 ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, keyW
.Buffer
, context
);
1355 RtlFreeUnicodeString( &keyW
);
1357 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1359 RtlFreeUnicodeString( §ionW
);
1364 /***********************************************************************
1365 * SetupFindFirstLineW (SETUPAPI.@)
1367 BOOL WINAPI
SetupFindFirstLineW( HINF hinf
, PCWSTR section
, PCWSTR key
, INFCONTEXT
*context
)
1369 struct inf_file
*file
;
1372 SetLastError( ERROR_SECTION_NOT_FOUND
);
1373 for (file
= hinf
; file
; file
= file
->next
)
1375 if ((section_index
= find_section( file
, section
)) == -1) continue;
1380 ctx
.CurrentInf
= file
;
1381 ctx
.Section
= section_index
;
1383 return SetupFindNextMatchLineW( &ctx
, key
, context
);
1385 SetLastError( ERROR_LINE_NOT_FOUND
); /* found at least one section */
1386 if (file
->sections
[section_index
]->nb_lines
)
1388 context
->Inf
= hinf
;
1389 context
->CurrentInf
= file
;
1390 context
->Section
= section_index
;
1393 TRACE( "(%p,%s,%s): returning %d/0\n",
1394 hinf
, debugstr_w(section
), debugstr_w(key
), section_index
);
1398 TRACE( "(%p,%s,%s): not found\n", hinf
, debugstr_w(section
), debugstr_w(key
) );
1403 /***********************************************************************
1404 * SetupFindNextLine (SETUPAPI.@)
1406 BOOL WINAPI
SetupFindNextLine( PINFCONTEXT context_in
, PINFCONTEXT context_out
)
1408 struct inf_file
*file
= context_in
->CurrentInf
;
1409 struct section
*section
;
1411 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1413 section
= file
->sections
[context_in
->Section
];
1414 if (context_in
->Line
+1 < section
->nb_lines
)
1416 if (context_out
!= context_in
) *context_out
= *context_in
;
1417 context_out
->Line
++;
1422 /* now search the appended files */
1424 for (file
= file
->next
; file
; file
= file
->next
)
1426 int section_index
= find_section( file
, section
->name
);
1427 if (section_index
== -1) continue;
1428 if (file
->sections
[section_index
]->nb_lines
)
1430 context_out
->Inf
= context_in
->Inf
;
1431 context_out
->CurrentInf
= file
;
1432 context_out
->Section
= section_index
;
1433 context_out
->Line
= 0;
1439 SetLastError( ERROR_LINE_NOT_FOUND
);
1444 /***********************************************************************
1445 * SetupFindNextMatchLineA (SETUPAPI.@)
1447 BOOL WINAPI
SetupFindNextMatchLineA( PINFCONTEXT context_in
, PCSTR key
,
1448 PINFCONTEXT context_out
)
1450 UNICODE_STRING keyW
;
1453 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1455 if (!RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1456 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1459 ret
= SetupFindNextMatchLineW( context_in
, keyW
.Buffer
, context_out
);
1460 RtlFreeUnicodeString( &keyW
);
1466 /***********************************************************************
1467 * SetupFindNextMatchLineW (SETUPAPI.@)
1469 BOOL WINAPI
SetupFindNextMatchLineW( PINFCONTEXT context_in
, PCWSTR key
,
1470 PINFCONTEXT context_out
)
1472 struct inf_file
*file
= context_in
->CurrentInf
;
1473 struct section
*section
;
1477 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1479 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1481 section
= file
->sections
[context_in
->Section
];
1483 for (i
= context_in
->Line
+1, line
= §ion
->lines
[i
]; i
< section
->nb_lines
; i
++, line
++)
1485 if (line
->key_field
== -1) continue;
1486 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1488 if (context_out
!= context_in
) *context_out
= *context_in
;
1489 context_out
->Line
= i
;
1491 TRACE( "(%p,%s,%s): returning %d\n",
1492 file
, debugstr_w(section
->name
), debugstr_w(key
), i
);
1497 /* now search the appended files */
1499 for (file
= file
->next
; file
; file
= file
->next
)
1501 int section_index
= find_section( file
, section
->name
);
1502 if (section_index
== -1) continue;
1503 section
= file
->sections
[section_index
];
1504 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
1506 if (line
->key_field
== -1) continue;
1507 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1509 context_out
->Inf
= context_in
->Inf
;
1510 context_out
->CurrentInf
= file
;
1511 context_out
->Section
= section_index
;
1512 context_out
->Line
= i
;
1514 TRACE( "(%p,%s,%s): returning %d/%d\n",
1515 file
, debugstr_w(section
->name
), debugstr_w(key
), section_index
, i
);
1520 TRACE( "(%p,%s,%s): not found\n",
1521 context_in
->CurrentInf
, debugstr_w(section
->name
), debugstr_w(key
) );
1523 SetLastError( ERROR_LINE_NOT_FOUND
);
1528 /***********************************************************************
1529 * SetupGetLineTextW (SETUPAPI.@)
1531 BOOL WINAPI
SetupGetLineTextW( PINFCONTEXT context
, HINF hinf
, PCWSTR section_name
,
1532 PCWSTR key_name
, PWSTR buffer
, DWORD size
, PDWORD required
)
1534 struct inf_file
*file
;
1536 struct field
*field
;
1542 INFCONTEXT new_context
;
1543 if (!SetupFindFirstLineW( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1544 file
= new_context
.CurrentInf
;
1545 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1549 file
= context
->CurrentInf
;
1550 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1552 SetLastError( ERROR_LINE_NOT_FOUND
);
1557 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1558 total
+= PARSER_string_substW( file
, field
->text
, NULL
, 0 ) + 1;
1560 if (required
) *required
= total
;
1565 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1568 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1570 unsigned int len
= PARSER_string_substW( file
, field
->text
, buffer
, size
);
1571 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1579 /***********************************************************************
1580 * SetupGetLineTextA (SETUPAPI.@)
1582 BOOL WINAPI
SetupGetLineTextA( PINFCONTEXT context
, HINF hinf
, PCSTR section_name
,
1583 PCSTR key_name
, PSTR buffer
, DWORD size
, PDWORD required
)
1585 struct inf_file
*file
;
1587 struct field
*field
;
1593 INFCONTEXT new_context
;
1594 if (!SetupFindFirstLineA( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1595 file
= new_context
.CurrentInf
;
1596 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1600 file
= context
->CurrentInf
;
1601 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1603 SetLastError( ERROR_LINE_NOT_FOUND
);
1608 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1609 total
+= PARSER_string_substA( file
, field
->text
, NULL
, 0 ) + 1;
1611 if (required
) *required
= total
;
1616 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1619 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1621 unsigned int len
= PARSER_string_substA( file
, field
->text
, buffer
, size
);
1622 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1630 /***********************************************************************
1631 * SetupGetFieldCount (SETUPAPI.@)
1633 DWORD WINAPI
SetupGetFieldCount( PINFCONTEXT context
)
1635 struct inf_file
*file
= context
->CurrentInf
;
1636 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1638 if (!line
) return 0;
1639 return line
->nb_fields
;
1643 /***********************************************************************
1644 * SetupGetStringFieldA (SETUPAPI.@)
1646 BOOL WINAPI
SetupGetStringFieldA( PINFCONTEXT context
, DWORD index
, PSTR buffer
,
1647 DWORD size
, PDWORD required
)
1649 struct inf_file
*file
= context
->CurrentInf
;
1650 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1654 if (!field
) return FALSE
;
1655 len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 );
1656 if (required
) *required
= len
+ 1;
1661 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1664 PARSER_string_substA( file
, field
->text
, buffer
, size
);
1666 TRACE( "context %p/%p/%d/%d index %d returning %s\n",
1667 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1668 index
, debugstr_a(buffer
) );
1674 /***********************************************************************
1675 * SetupGetStringFieldW (SETUPAPI.@)
1677 BOOL WINAPI
SetupGetStringFieldW( PINFCONTEXT context
, DWORD index
, PWSTR buffer
,
1678 DWORD size
, PDWORD required
)
1680 struct inf_file
*file
= context
->CurrentInf
;
1681 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1685 if (!field
) return FALSE
;
1686 len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 );
1687 if (required
) *required
= len
+ 1;
1692 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1695 PARSER_string_substW( file
, field
->text
, buffer
, size
);
1697 TRACE( "context %p/%p/%d/%d index %d returning %s\n",
1698 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1699 index
, debugstr_w(buffer
) );
1705 /***********************************************************************
1706 * SetupGetIntField (SETUPAPI.@)
1708 BOOL WINAPI
SetupGetIntField( PINFCONTEXT context
, DWORD index
, PINT result
)
1711 char *end
, *buffer
= localbuff
;
1716 if (!SetupGetStringFieldA( context
, index
, localbuff
, sizeof(localbuff
), &required
))
1718 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
1719 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
))) return FALSE
;
1720 if (!SetupGetStringFieldA( context
, index
, buffer
, required
, NULL
)) goto done
;
1722 res
= strtol( buffer
, &end
, 0 );
1723 if (end
!= buffer
&& !*end
)
1728 else SetLastError( ERROR_INVALID_DATA
);
1731 if (buffer
!= localbuff
) HeapFree( GetProcessHeap(), 0, buffer
);
1736 /***********************************************************************
1737 * SetupGetBinaryField (SETUPAPI.@)
1739 BOOL WINAPI
SetupGetBinaryField( PINFCONTEXT context
, DWORD index
, BYTE
*buffer
,
1740 DWORD size
, LPDWORD required
)
1742 struct inf_file
*file
= context
->CurrentInf
;
1743 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1744 struct field
*field
;
1749 SetLastError( ERROR_LINE_NOT_FOUND
);
1752 if (!index
|| index
> line
->nb_fields
)
1754 SetLastError( ERROR_INVALID_PARAMETER
);
1757 index
--; /* fields start at 0 */
1758 if (required
) *required
= line
->nb_fields
- index
;
1759 if (!buffer
) return TRUE
;
1760 if (size
< line
->nb_fields
- index
)
1762 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1765 field
= &file
->fields
[line
->first_field
+ index
];
1766 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1770 for (p
= field
->text
; *p
&& isxdigitW(*p
); p
++)
1772 if ((value
<<= 4) > 255)
1774 SetLastError( ERROR_INVALID_DATA
);
1777 if (*p
<= '9') value
|= (*p
- '0');
1778 else value
|= (tolowerW(*p
) - 'a' + 10);
1780 buffer
[i
- index
] = value
;
1782 if (TRACE_ON(setupapi
))
1784 TRACE( "%p/%p/%d/%d index %d returning",
1785 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
, index
);
1786 for (i
= index
; i
< line
->nb_fields
; i
++) TRACE( " %02x", buffer
[i
- index
] );
1793 /***********************************************************************
1794 * SetupGetMultiSzFieldA (SETUPAPI.@)
1796 BOOL WINAPI
SetupGetMultiSzFieldA( PINFCONTEXT context
, DWORD index
, PSTR buffer
,
1797 DWORD size
, LPDWORD required
)
1799 struct inf_file
*file
= context
->CurrentInf
;
1800 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1801 struct field
*field
;
1808 SetLastError( ERROR_LINE_NOT_FOUND
);
1811 if (!index
|| index
> line
->nb_fields
)
1813 SetLastError( ERROR_INVALID_PARAMETER
);
1816 index
--; /* fields start at 0 */
1817 field
= &file
->fields
[line
->first_field
+ index
];
1818 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1820 if (!(len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 ))) break;
1824 if (required
) *required
= total
;
1825 if (!buffer
) return TRUE
;
1828 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1831 field
= &file
->fields
[line
->first_field
+ index
];
1832 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1834 if (!(len
= PARSER_string_substA( file
, field
->text
, buffer
, size
))) break;
1837 *buffer
= 0; /* add final null */
1842 /***********************************************************************
1843 * SetupGetMultiSzFieldW (SETUPAPI.@)
1845 BOOL WINAPI
SetupGetMultiSzFieldW( PINFCONTEXT context
, DWORD index
, PWSTR buffer
,
1846 DWORD size
, LPDWORD required
)
1848 struct inf_file
*file
= context
->CurrentInf
;
1849 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1850 struct field
*field
;
1857 SetLastError( ERROR_LINE_NOT_FOUND
);
1860 if (!index
|| index
> line
->nb_fields
)
1862 SetLastError( ERROR_INVALID_PARAMETER
);
1865 index
--; /* fields start at 0 */
1866 field
= &file
->fields
[line
->first_field
+ index
];
1867 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1869 if (!(len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 ))) break;
1873 if (required
) *required
= total
;
1874 if (!buffer
) return TRUE
;
1877 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1880 field
= &file
->fields
[line
->first_field
+ index
];
1881 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1883 if (!(len
= PARSER_string_substW( file
, field
->text
, buffer
, size
))) break;
1886 *buffer
= 0; /* add final null */
1890 /***********************************************************************
1891 * pSetupGetField (SETUPAPI.@)
1893 LPCWSTR WINAPI
pSetupGetField( PINFCONTEXT context
, DWORD index
)
1895 struct inf_file
*file
= context
->CurrentInf
;
1896 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1900 SetLastError( ERROR_INVALID_PARAMETER
);