4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
33 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
40 #define CONTROL_Z '\x1a'
41 #define MAX_SECTION_NAME_LEN 255
42 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
43 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
44 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
46 /* inf file structure definitions */
50 const WCHAR
*text
; /* field text */
55 int first_field
; /* index of first field in field array */
56 int nb_fields
; /* number of fields in line */
57 int key_field
; /* index of field for key or -1 if no key */
62 const WCHAR
*name
; /* section name */
63 unsigned int nb_lines
; /* number of used lines */
64 unsigned int alloc_lines
; /* total number of allocated lines in array below */
65 struct line lines
[16]; /* lines information (grown dynamically, 16 is initial size) */
70 struct inf_file
*next
; /* next appended file */
71 WCHAR
*strings
; /* buffer for string data (section names and field values) */
72 WCHAR
*string_pos
; /* position of next available string in buffer */
73 unsigned int nb_sections
; /* number of used sections */
74 unsigned int alloc_sections
; /* total number of allocated section pointers */
75 struct section
**sections
; /* section pointers array */
76 unsigned int nb_fields
;
77 unsigned int alloc_fields
;
79 int strings_section
; /* index of [Strings] section or -1 if none */
80 WCHAR
*src_root
; /* source root directory */
83 /* parser definitions */
87 LINE_START
, /* at beginning of a line */
88 SECTION_NAME
, /* parsing a section name */
89 KEY_NAME
, /* parsing a key name */
90 VALUE_NAME
, /* parsing a value name */
91 EOL_BACKSLASH
, /* backslash at end of line */
92 QUOTES
, /* inside quotes */
93 LEADING_SPACES
, /* leading spaces */
94 TRAILING_SPACES
, /* trailing spaces */
95 COMMENT
, /* inside a comment */
101 const WCHAR
*start
; /* start position of item being parsed */
102 const WCHAR
*end
; /* end of buffer */
103 struct inf_file
*file
; /* file being built */
104 enum parser_state state
; /* current parser state */
105 enum parser_state stack
[4]; /* state stack */
106 int stack_pos
; /* current pos in stack */
108 int cur_section
; /* index of section being parsed*/
109 struct line
*line
; /* current line */
110 unsigned int line_pos
; /* current line position in file */
111 unsigned int error
; /* error code */
112 unsigned int token_len
; /* current token len */
113 WCHAR token
[MAX_FIELD_LEN
+1]; /* current token */
116 typedef const WCHAR
* (*parser_state_func
)( struct parser
*parser
, const WCHAR
*pos
);
118 /* parser state machine functions */
119 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
);
120 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
);
121 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
);
122 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
);
123 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
);
124 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
);
125 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
126 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
127 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
);
129 static const parser_state_func parser_funcs
[NB_PARSER_STATES
] =
131 line_start_state
, /* LINE_START */
132 section_name_state
, /* SECTION_NAME */
133 key_name_state
, /* KEY_NAME */
134 value_name_state
, /* VALUE_NAME */
135 eol_backslash_state
, /* EOL_BACKSLASH */
136 quotes_state
, /* QUOTES */
137 leading_spaces_state
, /* LEADING_SPACES */
138 trailing_spaces_state
, /* TRAILING_SPACES */
139 comment_state
/* COMMENT */
143 /* Unicode string constants */
144 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
145 static const WCHAR Signature
[] = {'S','i','g','n','a','t','u','r','e',0};
146 static const WCHAR Chicago
[] = {'$','C','h','i','c','a','g','o','$',0};
147 static const WCHAR WindowsNT
[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
148 static const WCHAR Windows95
[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
149 static const WCHAR LayoutFile
[] = {'L','a','y','o','u','t','F','i','l','e',0};
151 /* extend an array, allocating more memory if necessary */
152 static void *grow_array( void *array
, unsigned int *count
, size_t elem
)
155 unsigned int new_count
= *count
+ *count
/ 2;
156 if (new_count
< 32) new_count
= 32;
157 if ((new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, array
, new_count
* elem
)))
160 HeapFree( GetProcessHeap(), 0, array
);
165 /* find a section by name */
166 static int find_section( struct inf_file
*file
, const WCHAR
*name
)
170 for (i
= 0; i
< file
->nb_sections
; i
++)
171 if (!strcmpiW( name
, file
->sections
[i
]->name
)) return i
;
176 /* find a line by name */
177 static struct line
*find_line( struct inf_file
*file
, int section_index
, const WCHAR
*name
)
179 struct section
*section
;
183 if (section_index
< 0 || section_index
>= file
->nb_sections
) return NULL
;
184 section
= file
->sections
[section_index
];
185 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
187 if (line
->key_field
== -1) continue;
188 if (!strcmpiW( name
, file
->fields
[line
->key_field
].text
)) return line
;
194 /* add a section to the file and return the section index */
195 static int add_section( struct inf_file
*file
, const WCHAR
*name
)
197 struct section
*section
;
199 if (file
->nb_sections
>= file
->alloc_sections
)
201 if (!(file
->sections
= grow_array( file
->sections
, &file
->alloc_sections
,
202 sizeof(file
->sections
[0]) ))) return -1;
204 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) ))) return -1;
205 section
->name
= name
;
206 section
->nb_lines
= 0;
207 section
->alloc_lines
= sizeof(section
->lines
)/sizeof(section
->lines
[0]);
208 file
->sections
[file
->nb_sections
] = section
;
209 return file
->nb_sections
++;
213 /* add a line to a given section */
214 static struct line
*add_line( struct inf_file
*file
, int section_index
)
216 struct section
*section
;
219 assert( section_index
>= 0 && section_index
< file
->nb_sections
);
221 section
= file
->sections
[section_index
];
222 if (section
->nb_lines
== section
->alloc_lines
) /* need to grow the section */
224 int size
= sizeof(*section
) - sizeof(section
->lines
) + 2*section
->alloc_lines
*sizeof(*line
);
225 if (!(section
= HeapReAlloc( GetProcessHeap(), 0, section
, size
))) return NULL
;
226 section
->alloc_lines
*= 2;
227 file
->sections
[section_index
] = section
;
229 line
= §ion
->lines
[section
->nb_lines
++];
230 line
->first_field
= file
->nb_fields
;
232 line
->key_field
= -1;
237 /* retrieve a given line from section/line index */
238 inline static struct line
*get_line( struct inf_file
*file
, unsigned int section_index
,
239 unsigned int line_index
)
241 struct section
*section
;
243 if (section_index
>= file
->nb_sections
) return NULL
;
244 section
= file
->sections
[section_index
];
245 if (line_index
>= section
->nb_lines
) return NULL
;
246 return §ion
->lines
[line_index
];
250 /* retrieve a given field from section/line/field index */
251 static struct field
*get_field( struct inf_file
*file
, int section_index
, int line_index
,
254 struct line
*line
= get_line( file
, section_index
, line_index
);
256 if (!line
) return NULL
;
257 if (!field_index
) /* get the key */
259 if (line
->key_field
== -1) return NULL
;
260 return &file
->fields
[line
->key_field
];
263 if (field_index
>= line
->nb_fields
) return NULL
;
264 return &file
->fields
[line
->first_field
+ field_index
];
268 /* allocate a new field, growing the array if necessary */
269 static struct field
*add_field( struct inf_file
*file
, const WCHAR
*text
)
273 if (file
->nb_fields
>= file
->alloc_fields
)
275 if (!(file
->fields
= grow_array( file
->fields
, &file
->alloc_fields
,
276 sizeof(file
->fields
[0]) ))) return NULL
;
278 field
= &file
->fields
[file
->nb_fields
++];
284 /* retrieve the string substitution for a directory id */
285 static const WCHAR
*get_dirid_subst( int dirid
, unsigned int *len
)
287 extern const WCHAR
*DIRID_get_string( HINF hinf
, int dirid
);
288 const WCHAR
*ret
= DIRID_get_string( 0, dirid
);
289 if (ret
) *len
= strlenW(ret
);
294 /* retrieve the string substitution for a given string, or NULL if not found */
295 /* if found, len is set to the substitution length */
296 static const WCHAR
*get_string_subst( struct inf_file
*file
, const WCHAR
*str
, unsigned int *len
)
298 static const WCHAR percent
= '%';
300 struct section
*strings_section
;
304 WCHAR
*dirid_str
, *end
;
305 const WCHAR
*ret
= NULL
;
307 if (!*len
) /* empty string (%%) is replaced by single percent */
312 if (file
->strings_section
== -1) goto not_found
;
313 strings_section
= file
->sections
[file
->strings_section
];
314 for (i
= 0, line
= strings_section
->lines
; i
< strings_section
->nb_lines
; i
++, line
++)
316 if (line
->key_field
== -1) continue;
317 if (strncmpiW( str
, file
->fields
[line
->key_field
].text
, *len
)) continue;
318 if (!file
->fields
[line
->key_field
].text
[*len
]) break;
320 if (i
== strings_section
->nb_lines
|| !line
->nb_fields
) goto not_found
;
321 field
= &file
->fields
[line
->first_field
];
322 *len
= strlenW( field
->text
);
325 not_found
: /* check for integer id */
326 if ((dirid_str
= HeapAlloc( GetProcessHeap(), 0, (*len
+1) * sizeof(WCHAR
) )))
328 memcpy( dirid_str
, str
, *len
* sizeof(WCHAR
) );
330 dirid
= strtolW( dirid_str
, &end
, 10 );
331 if (!*end
) ret
= get_dirid_subst( dirid
, len
);
332 HeapFree( GetProcessHeap(), 0, dirid_str
);
339 /* do string substitutions on the specified text */
340 /* the buffer is assumed to be large enough */
341 /* returns necessary length not including terminating null */
342 unsigned int PARSER_string_substW( struct inf_file
*file
, const WCHAR
*text
, WCHAR
*buffer
,
345 const WCHAR
*start
, *subst
, *p
;
346 unsigned int len
, total
= 0;
349 if (!buffer
) size
= MAX_STRING_LEN
+ 1;
350 for (p
= start
= text
; *p
; p
++)
352 if (*p
!= '%') continue;
354 if (inside
) /* start of a %xx% string */
357 if (len
> size
- 1) len
= size
- 1;
358 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
363 else /* end of the %xx% string, find substitution */
366 subst
= get_string_subst( file
, start
+ 1, &len
);
372 if (len
> size
- 1) len
= size
- 1;
373 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
380 if (start
!= p
) /* unfinished string, copy it */
383 if (len
> size
- 1) len
= size
- 1;
384 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
387 if (buffer
&& size
) buffer
[total
] = 0;
392 /* do string substitutions on the specified text */
393 /* the buffer is assumed to be large enough */
394 /* returns necessary length not including terminating null */
395 unsigned int PARSER_string_substA( struct inf_file
*file
, const WCHAR
*text
, char *buffer
,
398 WCHAR buffW
[MAX_STRING_LEN
+1];
401 unsigned int len
= PARSER_string_substW( file
, text
, buffW
, sizeof(buffW
)/sizeof(WCHAR
) );
402 if (!buffer
) RtlUnicodeToMultiByteSize( &ret
, buffW
, len
* sizeof(WCHAR
) );
405 RtlUnicodeToMultiByteN( buffer
, size
-1, &ret
, buffW
, len
* sizeof(WCHAR
) );
412 /* push some string data into the strings buffer */
413 static WCHAR
*push_string( struct inf_file
*file
, const WCHAR
*string
)
415 WCHAR
*ret
= file
->string_pos
;
416 strcpyW( ret
, string
);
417 file
->string_pos
+= strlenW( ret
) + 1;
422 /* push the current state on the parser stack */
423 inline static void push_state( struct parser
*parser
, enum parser_state state
)
425 assert( parser
->stack_pos
< sizeof(parser
->stack
)/sizeof(parser
->stack
[0]) );
426 parser
->stack
[parser
->stack_pos
++] = state
;
430 /* pop the current state */
431 inline static void pop_state( struct parser
*parser
)
433 assert( parser
->stack_pos
);
434 parser
->state
= parser
->stack
[--parser
->stack_pos
];
438 /* set the parser state and return the previous one */
439 inline static enum parser_state
set_state( struct parser
*parser
, enum parser_state state
)
441 enum parser_state ret
= parser
->state
;
442 parser
->state
= state
;
447 /* check if the pointer points to an end of file */
448 inline static int is_eof( struct parser
*parser
, const WCHAR
*ptr
)
450 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
);
454 /* check if the pointer points to an end of line */
455 inline static int is_eol( struct parser
*parser
, const WCHAR
*ptr
)
457 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
|| *ptr
== '\n');
461 /* push data from current token start up to pos into the current token */
462 static int push_token( struct parser
*parser
, const WCHAR
*pos
)
464 int len
= pos
- parser
->start
;
465 const WCHAR
*src
= parser
->start
;
466 WCHAR
*dst
= parser
->token
+ parser
->token_len
;
468 if (len
> MAX_FIELD_LEN
- parser
->token_len
) len
= MAX_FIELD_LEN
- parser
->token_len
;
470 parser
->token_len
+= len
;
471 for ( ; len
> 0; len
--, dst
++, src
++) *dst
= *src
? *src
: ' ';
478 /* add a section with the current token as name */
479 static int add_section_from_token( struct parser
*parser
)
483 if (parser
->token_len
> MAX_SECTION_NAME_LEN
)
485 parser
->error
= ERROR_SECTION_NAME_TOO_LONG
;
488 if ((section_index
= find_section( parser
->file
, parser
->token
)) == -1)
490 /* need to create a new one */
491 const WCHAR
*name
= push_string( parser
->file
, parser
->token
);
492 if ((section_index
= add_section( parser
->file
, name
)) == -1)
494 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
498 parser
->token_len
= 0;
499 parser
->cur_section
= section_index
;
500 return section_index
;
504 /* add a field containing the current token to the current line */
505 static struct field
*add_field_from_token( struct parser
*parser
, int is_key
)
510 if (!parser
->line
) /* need to start a new line */
512 if (parser
->cur_section
== -1) /* got a line before the first section */
514 parser
->error
= ERROR_WRONG_INF_STYLE
;
517 if (!(parser
->line
= add_line( parser
->file
, parser
->cur_section
))) goto error
;
519 else assert(!is_key
);
521 text
= push_string( parser
->file
, parser
->token
);
522 if ((field
= add_field( parser
->file
, text
)))
524 if (!is_key
) parser
->line
->nb_fields
++;
527 /* replace first field by key field */
528 parser
->line
->key_field
= parser
->line
->first_field
;
529 parser
->line
->first_field
++;
531 parser
->token_len
= 0;
535 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
540 /* close the current line and prepare for parsing a new one */
541 static void close_current_line( struct parser
*parser
)
543 struct line
*cur_line
= parser
->line
;
547 /* if line has a single field and no key, the field is the key too */
548 if (cur_line
->nb_fields
== 1 && cur_line
->key_field
== -1)
549 cur_line
->key_field
= cur_line
->first_field
;
555 /* handler for parser LINE_START state */
556 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
)
560 for (p
= pos
; !is_eof( parser
, p
); p
++)
566 close_current_line( parser
);
569 push_state( parser
, LINE_START
);
570 set_state( parser
, COMMENT
);
573 parser
->start
= p
+ 1;
574 set_state( parser
, SECTION_NAME
);
580 set_state( parser
, KEY_NAME
);
586 close_current_line( parser
);
591 /* handler for parser SECTION_NAME state */
592 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
)
596 for (p
= pos
; !is_eol( parser
, p
); p
++)
600 push_token( parser
, p
);
601 if (add_section_from_token( parser
) == -1) return NULL
;
602 push_state( parser
, LINE_START
);
603 set_state( parser
, COMMENT
); /* ignore everything else on the line */
607 parser
->error
= ERROR_BAD_SECTION_NAME_LINE
; /* unfinished section name */
612 /* handler for parser KEY_NAME state */
613 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
)
615 const WCHAR
*p
, *token_end
= parser
->start
;
617 for (p
= pos
; !is_eol( parser
, p
); p
++)
619 if (*p
== ',') break;
624 push_token( parser
, token_end
);
625 if (!add_field_from_token( parser
, 1 )) return NULL
;
626 parser
->start
= p
+ 1;
627 push_state( parser
, VALUE_NAME
);
628 set_state( parser
, LEADING_SPACES
);
631 push_token( parser
, token_end
);
632 if (!add_field_from_token( parser
, 0 )) return NULL
;
633 push_state( parser
, LINE_START
);
634 set_state( parser
, COMMENT
);
637 push_token( parser
, token_end
);
638 parser
->start
= p
+ 1;
639 push_state( parser
, KEY_NAME
);
640 set_state( parser
, QUOTES
);
643 push_token( parser
, token_end
);
645 push_state( parser
, KEY_NAME
);
646 set_state( parser
, EOL_BACKSLASH
);
649 if (!isspaceW(*p
)) token_end
= p
+ 1;
652 push_token( parser
, p
);
653 push_state( parser
, KEY_NAME
);
654 set_state( parser
, TRAILING_SPACES
);
660 push_token( parser
, token_end
);
661 set_state( parser
, VALUE_NAME
);
666 /* handler for parser VALUE_NAME state */
667 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
)
669 const WCHAR
*p
, *token_end
= parser
->start
;
671 for (p
= pos
; !is_eol( parser
, p
); p
++)
676 push_token( parser
, token_end
);
677 if (!add_field_from_token( parser
, 0 )) return NULL
;
678 push_state( parser
, LINE_START
);
679 set_state( parser
, COMMENT
);
682 push_token( parser
, token_end
);
683 if (!add_field_from_token( parser
, 0 )) return NULL
;
684 parser
->start
= p
+ 1;
685 push_state( parser
, VALUE_NAME
);
686 set_state( parser
, LEADING_SPACES
);
689 push_token( parser
, token_end
);
690 parser
->start
= p
+ 1;
691 push_state( parser
, VALUE_NAME
);
692 set_state( parser
, QUOTES
);
695 push_token( parser
, token_end
);
697 push_state( parser
, VALUE_NAME
);
698 set_state( parser
, EOL_BACKSLASH
);
701 if (!isspaceW(*p
)) token_end
= p
+ 1;
704 push_token( parser
, p
);
705 push_state( parser
, VALUE_NAME
);
706 set_state( parser
, TRAILING_SPACES
);
712 push_token( parser
, token_end
);
713 if (!add_field_from_token( parser
, 0 )) return NULL
;
714 set_state( parser
, LINE_START
);
719 /* handler for parser EOL_BACKSLASH state */
720 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
)
724 for (p
= pos
; !is_eof( parser
, p
); p
++)
730 parser
->start
= p
+ 1;
731 set_state( parser
, LEADING_SPACES
);
736 push_state( parser
, EOL_BACKSLASH
);
737 set_state( parser
, COMMENT
);
740 if (isspaceW(*p
)) continue;
741 push_token( parser
, p
);
752 /* handler for parser QUOTES state */
753 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
)
755 const WCHAR
*p
, *token_end
= parser
->start
;
757 for (p
= pos
; !is_eol( parser
, p
); p
++)
761 if (p
+1 < parser
->end
&& p
[1] == '"') /* double quotes */
763 push_token( parser
, p
+ 1 );
764 parser
->start
= token_end
= p
+ 2;
767 else /* end of quotes */
769 push_token( parser
, p
);
770 parser
->start
= p
+ 1;
776 push_token( parser
, p
);
782 /* handler for parser LEADING_SPACES state */
783 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
787 for (p
= pos
; !is_eol( parser
, p
); p
++)
792 set_state( parser
, EOL_BACKSLASH
);
795 if (!isspaceW(*p
)) break;
803 /* handler for parser TRAILING_SPACES state */
804 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
808 for (p
= pos
; !is_eol( parser
, p
); p
++)
812 set_state( parser
, EOL_BACKSLASH
);
815 if (!isspaceW(*p
)) break;
822 /* handler for parser COMMENT state */
823 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
)
825 const WCHAR
*p
= pos
;
827 while (!is_eol( parser
, p
)) p
++;
833 /* parse a complete buffer */
834 static DWORD
parse_buffer( struct inf_file
*file
, const WCHAR
*buffer
, const WCHAR
*end
,
837 static const WCHAR Strings
[] = {'S','t','r','i','n','g','s',0};
839 struct parser parser
;
840 const WCHAR
*pos
= buffer
;
842 parser
.start
= buffer
;
846 parser
.state
= LINE_START
;
847 parser
.stack_pos
= 0;
848 parser
.cur_section
= -1;
851 parser
.token_len
= 0;
853 /* parser main loop */
854 while (pos
) pos
= (parser_funcs
[parser
.state
])( &parser
, pos
);
856 /* trim excess buffer space */
857 if (file
->alloc_sections
> file
->nb_sections
)
859 file
->sections
= HeapReAlloc( GetProcessHeap(), 0, file
->sections
,
860 file
->nb_sections
* sizeof(file
->sections
[0]) );
861 file
->alloc_sections
= file
->nb_sections
;
863 if (file
->alloc_fields
> file
->nb_fields
)
865 file
->fields
= HeapReAlloc( GetProcessHeap(), 0, file
->fields
,
866 file
->nb_fields
* sizeof(file
->fields
[0]) );
867 file
->alloc_fields
= file
->nb_fields
;
869 file
->strings
= HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY
, file
->strings
,
870 (file
->string_pos
- file
->strings
) * sizeof(WCHAR
) );
874 if (error_line
) *error_line
= parser
.line_pos
;
878 /* find the [strings] section */
879 file
->strings_section
= find_section( file
, Strings
);
884 /* append a child INF file to its parent list, in a thread-safe manner */
885 static void append_inf_file( struct inf_file
*parent
, struct inf_file
*child
)
887 struct inf_file
**ppnext
= &parent
->next
;
892 struct inf_file
*next
= InterlockedCompareExchangePointer( (void **)ppnext
, child
, NULL
);
894 ppnext
= &next
->next
;
899 /***********************************************************************
904 static struct inf_file
*parse_file( HANDLE handle
, const WCHAR
*class, UINT
*error_line
)
908 struct inf_file
*file
;
910 DWORD size
= GetFileSize( handle
, NULL
);
911 HANDLE mapping
= CreateFileMappingW( handle
, NULL
, PAGE_READONLY
, 0, size
, NULL
);
912 if (!mapping
) return NULL
;
913 buffer
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, size
);
915 if (!buffer
) return NULL
;
917 if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) );
919 if (!(file
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*file
) )))
921 err
= ERROR_NOT_ENOUGH_MEMORY
;
925 /* we won't need more strings space than the size of the file,
926 * so we can preallocate it here
928 if (!(file
->strings
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
930 err
= ERROR_NOT_ENOUGH_MEMORY
;
933 file
->string_pos
= file
->strings
;
934 file
->strings_section
= -1;
936 if (!RtlIsTextUnicode( buffer
, size
, NULL
))
938 WCHAR
*new_buff
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) );
941 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buffer
, size
, new_buff
,
942 size
* sizeof(WCHAR
) );
943 err
= parse_buffer( file
, new_buff
, new_buff
+ len
, error_line
);
944 HeapFree( GetProcessHeap(), 0, new_buff
);
947 else err
= parse_buffer( file
, buffer
, (WCHAR
*)((char *)buffer
+ size
), error_line
);
949 if (!err
) /* now check signature */
951 int version_index
= find_section( file
, Version
);
952 if (version_index
!= -1)
954 struct line
*line
= find_line( file
, version_index
, Signature
);
955 if (line
&& line
->nb_fields
> 0)
957 struct field
*field
= file
->fields
+ line
->first_field
;
958 if (!strcmpiW( field
->text
, Chicago
)) goto done
;
959 if (!strcmpiW( field
->text
, WindowsNT
)) goto done
;
960 if (!strcmpiW( field
->text
, Windows95
)) goto done
;
963 err
= ERROR_WRONG_INF_STYLE
;
967 UnmapViewOfFile( buffer
);
970 HeapFree( GetProcessHeap(), 0, file
);
978 /***********************************************************************
979 * PARSER_get_src_root
981 * Retrieve the source directory of an inf file.
983 const WCHAR
*PARSER_get_src_root( HINF hinf
)
985 struct inf_file
*file
= hinf
;
986 return file
->src_root
;
990 /***********************************************************************
991 * SetupOpenInfFileA (SETUPAPI.@)
993 HINF WINAPI
SetupOpenInfFileA( PCSTR name
, PCSTR
class, DWORD style
, UINT
*error
)
995 UNICODE_STRING nameW
, classW
;
996 HINF ret
= (HINF
)INVALID_HANDLE_VALUE
;
998 classW
.Buffer
= NULL
;
999 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW
, class ))
1001 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1004 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, name
))
1006 ret
= SetupOpenInfFileW( nameW
.Buffer
, classW
.Buffer
, style
, error
);
1007 RtlFreeUnicodeString( &nameW
);
1009 RtlFreeUnicodeString( &classW
);
1014 /***********************************************************************
1015 * SetupOpenInfFileW (SETUPAPI.@)
1017 HINF WINAPI
SetupOpenInfFileW( PCWSTR name
, PCWSTR
class, DWORD style
, UINT
*error
)
1019 struct inf_file
*file
= NULL
;
1024 if (strchrW( name
, '\\' ) || strchrW( name
, '/' ))
1026 if (!(len
= GetFullPathNameW( name
, 0, NULL
, NULL
))) return (HINF
)INVALID_HANDLE_VALUE
;
1027 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1029 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1030 return (HINF
)INVALID_HANDLE_VALUE
;
1032 GetFullPathNameW( name
, len
, path
, NULL
);
1033 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1035 else /* try Windows directory */
1037 static const WCHAR Inf
[] = {'\\','i','n','f','\\',0};
1038 static const WCHAR System32
[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
1040 len
= GetWindowsDirectoryW( NULL
, 0 ) + strlenW(name
) + 12;
1041 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1043 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1044 return (HINF
)INVALID_HANDLE_VALUE
;
1046 GetWindowsDirectoryW( path
, len
);
1047 p
= path
+ strlenW(path
);
1050 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1051 if (handle
== INVALID_HANDLE_VALUE
)
1053 strcpyW( p
, System32
);
1055 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1059 if (handle
!= INVALID_HANDLE_VALUE
)
1061 file
= parse_file( handle
, class, error
);
1062 CloseHandle( handle
);
1066 HeapFree( GetProcessHeap(), 0, path
);
1067 return (HINF
)INVALID_HANDLE_VALUE
;
1069 TRACE( "%s -> %p\n", debugstr_w(path
), file
);
1070 file
->src_root
= path
;
1071 if ((p
= strrchrW( path
, '\\' ))) p
[1] = 0; /* remove file name */
1077 /***********************************************************************
1078 * SetupOpenAppendInfFileA (SETUPAPI.@)
1080 BOOL WINAPI
SetupOpenAppendInfFileA( PCSTR name
, HINF parent_hinf
, UINT
*error
)
1084 if (!name
) return SetupOpenAppendInfFileW( NULL
, parent_hinf
, error
);
1085 child_hinf
= SetupOpenInfFileA( name
, NULL
, INF_STYLE_WIN4
, error
);
1086 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1087 append_inf_file( parent_hinf
, child_hinf
);
1088 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_a(name
), child_hinf
);
1093 /***********************************************************************
1094 * SetupOpenAppendInfFileW (SETUPAPI.@)
1096 BOOL WINAPI
SetupOpenAppendInfFileW( PCWSTR name
, HINF parent_hinf
, UINT
*error
)
1103 WCHAR filename
[MAX_PATH
];
1106 if (!SetupFindFirstLineW( parent_hinf
, Version
, LayoutFile
, &context
)) return FALSE
;
1107 while (SetupGetStringFieldW( &context
, idx
++, filename
,
1108 sizeof(filename
)/sizeof(WCHAR
), NULL
))
1110 child_hinf
= SetupOpenInfFileW( filename
, NULL
, INF_STYLE_WIN4
, error
);
1111 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1112 append_inf_file( parent_hinf
, child_hinf
);
1113 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(filename
), child_hinf
);
1117 child_hinf
= SetupOpenInfFileW( name
, NULL
, INF_STYLE_WIN4
, error
);
1118 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1119 append_inf_file( parent_hinf
, child_hinf
);
1120 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(name
), child_hinf
);
1125 /***********************************************************************
1126 * SetupCloseInfFile (SETUPAPI.@)
1128 void WINAPI
SetupCloseInfFile( HINF hinf
)
1130 struct inf_file
*file
= hinf
;
1133 for (i
= 0; i
< file
->nb_sections
; i
++) HeapFree( GetProcessHeap(), 0, file
->sections
[i
] );
1134 HeapFree( GetProcessHeap(), 0, file
->src_root
);
1135 HeapFree( GetProcessHeap(), 0, file
->sections
);
1136 HeapFree( GetProcessHeap(), 0, file
->fields
);
1137 HeapFree( GetProcessHeap(), 0, file
->strings
);
1138 HeapFree( GetProcessHeap(), 0, file
);
1142 /***********************************************************************
1143 * SetupGetLineCountA (SETUPAPI.@)
1145 LONG WINAPI
SetupGetLineCountA( HINF hinf
, PCSTR name
)
1147 UNICODE_STRING sectionW
;
1150 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, name
))
1151 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1154 ret
= SetupGetLineCountW( hinf
, sectionW
.Buffer
);
1155 RtlFreeUnicodeString( §ionW
);
1161 /***********************************************************************
1162 * SetupGetLineCountW (SETUPAPI.@)
1164 LONG WINAPI
SetupGetLineCountW( HINF hinf
, PCWSTR section
)
1166 struct inf_file
*file
= hinf
;
1170 for (file
= hinf
; file
; file
= file
->next
)
1172 if ((section_index
= find_section( file
, section
)) == -1) continue;
1173 if (ret
== -1) ret
= 0;
1174 ret
+= file
->sections
[section_index
]->nb_lines
;
1176 TRACE( "(%p,%s) returning %ld\n", hinf
, debugstr_w(section
), ret
);
1177 SetLastError( (ret
== -1) ? ERROR_SECTION_NOT_FOUND
: 0 );
1182 /***********************************************************************
1183 * SetupGetLineByIndexA (SETUPAPI.@)
1185 BOOL WINAPI
SetupGetLineByIndexA( HINF hinf
, PCSTR section
, DWORD index
, INFCONTEXT
*context
)
1187 UNICODE_STRING sectionW
;
1190 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1191 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1194 ret
= SetupGetLineByIndexW( hinf
, sectionW
.Buffer
, index
, context
);
1195 RtlFreeUnicodeString( §ionW
);
1201 /***********************************************************************
1202 * SetupGetLineByIndexW (SETUPAPI.@)
1204 BOOL WINAPI
SetupGetLineByIndexW( HINF hinf
, PCWSTR section
, DWORD index
, INFCONTEXT
*context
)
1206 struct inf_file
*file
= hinf
;
1209 SetLastError( ERROR_SECTION_NOT_FOUND
);
1210 for (file
= hinf
; file
; file
= file
->next
)
1212 if ((section_index
= find_section( file
, section
)) == -1) continue;
1213 SetLastError( ERROR_LINE_NOT_FOUND
);
1214 if (index
< file
->sections
[section_index
]->nb_lines
)
1216 context
->Inf
= hinf
;
1217 context
->CurrentInf
= file
;
1218 context
->Section
= section_index
;
1219 context
->Line
= index
;
1221 TRACE( "(%p,%s): returning %d/%ld\n",
1222 hinf
, debugstr_w(section
), section_index
, index
);
1225 index
-= file
->sections
[section_index
]->nb_lines
;
1227 TRACE( "(%p,%s) not found\n", hinf
, debugstr_w(section
) );
1232 /***********************************************************************
1233 * SetupFindFirstLineA (SETUPAPI.@)
1235 BOOL WINAPI
SetupFindFirstLineA( HINF hinf
, PCSTR section
, PCSTR key
, INFCONTEXT
*context
)
1237 UNICODE_STRING sectionW
, keyW
;
1240 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1242 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1246 if (!key
) ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, NULL
, context
);
1249 if (RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1251 ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, keyW
.Buffer
, context
);
1252 RtlFreeUnicodeString( &keyW
);
1254 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1256 RtlFreeUnicodeString( §ionW
);
1261 /***********************************************************************
1262 * SetupFindFirstLineW (SETUPAPI.@)
1264 BOOL WINAPI
SetupFindFirstLineW( HINF hinf
, PCWSTR section
, PCWSTR key
, INFCONTEXT
*context
)
1266 struct inf_file
*file
;
1269 SetLastError( ERROR_SECTION_NOT_FOUND
);
1270 for (file
= hinf
; file
; file
= file
->next
)
1272 if ((section_index
= find_section( file
, section
)) == -1) continue;
1277 ctx
.CurrentInf
= file
;
1278 ctx
.Section
= section_index
;
1280 return SetupFindNextMatchLineW( &ctx
, key
, context
);
1282 SetLastError( ERROR_LINE_NOT_FOUND
); /* found at least one section */
1283 if (file
->sections
[section_index
]->nb_lines
)
1285 context
->Inf
= hinf
;
1286 context
->CurrentInf
= file
;
1287 context
->Section
= section_index
;
1290 TRACE( "(%p,%s,%s): returning %d/0\n",
1291 hinf
, debugstr_w(section
), debugstr_w(key
), section_index
);
1295 TRACE( "(%p,%s,%s): not found\n", hinf
, debugstr_w(section
), debugstr_w(key
) );
1300 /***********************************************************************
1301 * SetupFindNextLine (SETUPAPI.@)
1303 BOOL WINAPI
SetupFindNextLine( const INFCONTEXT
*context_in
, INFCONTEXT
*context_out
)
1305 struct inf_file
*file
= context_in
->CurrentInf
;
1306 struct section
*section
;
1308 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1310 section
= file
->sections
[context_in
->Section
];
1311 if (context_in
->Line
+1 < section
->nb_lines
)
1313 if (context_out
!= context_in
) *context_out
= *context_in
;
1314 context_out
->Line
++;
1319 /* now search the appended files */
1321 for (file
= file
->next
; file
; file
= file
->next
)
1323 int section_index
= find_section( file
, section
->name
);
1324 if (section_index
== -1) continue;
1325 if (file
->sections
[section_index
]->nb_lines
)
1327 context_out
->Inf
= context_in
->Inf
;
1328 context_out
->CurrentInf
= file
;
1329 context_out
->Section
= section_index
;
1330 context_out
->Line
= 0;
1336 SetLastError( ERROR_LINE_NOT_FOUND
);
1341 /***********************************************************************
1342 * SetupFindNextMatchLineA (SETUPAPI.@)
1344 BOOL WINAPI
SetupFindNextMatchLineA( const INFCONTEXT
*context_in
, PCSTR key
,
1345 INFCONTEXT
*context_out
)
1347 UNICODE_STRING keyW
;
1350 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1352 if (!RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1353 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1356 ret
= SetupFindNextMatchLineW( context_in
, keyW
.Buffer
, context_out
);
1357 RtlFreeUnicodeString( &keyW
);
1363 /***********************************************************************
1364 * SetupFindNextMatchLineW (SETUPAPI.@)
1366 BOOL WINAPI
SetupFindNextMatchLineW( const INFCONTEXT
*context_in
, PCWSTR key
,
1367 INFCONTEXT
*context_out
)
1369 struct inf_file
*file
= context_in
->CurrentInf
;
1370 struct section
*section
;
1374 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1376 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1378 section
= file
->sections
[context_in
->Section
];
1380 for (i
= context_in
->Line
+1, line
= §ion
->lines
[i
]; i
< section
->nb_lines
; i
++, line
++)
1382 if (line
->key_field
== -1) continue;
1383 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1385 if (context_out
!= context_in
) *context_out
= *context_in
;
1386 context_out
->Line
= i
;
1388 TRACE( "(%p,%s,%s): returning %d\n",
1389 file
, debugstr_w(section
->name
), debugstr_w(key
), i
);
1394 /* now search the appended files */
1396 for (file
= file
->next
; file
; file
= file
->next
)
1398 int section_index
= find_section( file
, section
->name
);
1399 if (section_index
== -1) continue;
1400 section
= file
->sections
[section_index
];
1401 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
1403 if (line
->key_field
== -1) continue;
1404 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1406 context_out
->Inf
= context_in
->Inf
;
1407 context_out
->CurrentInf
= file
;
1408 context_out
->Section
= section_index
;
1409 context_out
->Line
= i
;
1411 TRACE( "(%p,%s,%s): returning %d/%d\n",
1412 file
, debugstr_w(section
->name
), debugstr_w(key
), section_index
, i
);
1417 TRACE( "(%p,%s,%s): not found\n",
1418 context_in
->CurrentInf
, debugstr_w(section
->name
), debugstr_w(key
) );
1420 SetLastError( ERROR_LINE_NOT_FOUND
);
1425 /***********************************************************************
1426 * SetupGetLineTextW (SETUPAPI.@)
1428 BOOL WINAPI
SetupGetLineTextW( const INFCONTEXT
*context
, HINF hinf
, PCWSTR section_name
,
1429 PCWSTR key_name
, PWSTR buffer
, DWORD size
, DWORD
*required
)
1431 struct inf_file
*file
;
1433 struct field
*field
;
1439 INFCONTEXT new_context
;
1440 if (!SetupFindFirstLineW( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1441 file
= new_context
.CurrentInf
;
1442 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1446 file
= context
->CurrentInf
;
1447 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1449 SetLastError( ERROR_LINE_NOT_FOUND
);
1454 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1455 total
+= PARSER_string_substW( file
, field
->text
, NULL
, 0 ) + 1;
1457 if (required
) *required
= total
;
1462 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1465 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1467 unsigned int len
= PARSER_string_substW( file
, field
->text
, buffer
, size
);
1468 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1476 /***********************************************************************
1477 * SetupGetLineTextA (SETUPAPI.@)
1479 BOOL WINAPI
SetupGetLineTextA( const INFCONTEXT
*context
, HINF hinf
, PCSTR section_name
,
1480 PCSTR key_name
, PSTR buffer
, DWORD size
, DWORD
*required
)
1482 struct inf_file
*file
;
1484 struct field
*field
;
1490 INFCONTEXT new_context
;
1491 if (!SetupFindFirstLineA( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1492 file
= new_context
.CurrentInf
;
1493 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1497 file
= context
->CurrentInf
;
1498 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1500 SetLastError( ERROR_LINE_NOT_FOUND
);
1505 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1506 total
+= PARSER_string_substA( file
, field
->text
, NULL
, 0 ) + 1;
1508 if (required
) *required
= total
;
1513 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1516 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1518 unsigned int len
= PARSER_string_substA( file
, field
->text
, buffer
, size
);
1519 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1527 /***********************************************************************
1528 * SetupGetFieldCount (SETUPAPI.@)
1530 DWORD WINAPI
SetupGetFieldCount( const INFCONTEXT
*context
)
1532 struct inf_file
*file
= context
->CurrentInf
;
1533 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1535 if (!line
) return 0;
1536 return line
->nb_fields
;
1540 /***********************************************************************
1541 * SetupGetStringFieldA (SETUPAPI.@)
1543 BOOL WINAPI
SetupGetStringFieldA( const INFCONTEXT
*context
, DWORD index
, PSTR buffer
,
1544 DWORD size
, DWORD
*required
)
1546 struct inf_file
*file
= context
->CurrentInf
;
1547 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1551 if (!field
) return FALSE
;
1552 len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 );
1553 if (required
) *required
= len
+ 1;
1558 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1561 PARSER_string_substA( file
, field
->text
, buffer
, size
);
1563 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1564 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1565 index
, debugstr_a(buffer
) );
1571 /***********************************************************************
1572 * SetupGetStringFieldW (SETUPAPI.@)
1574 BOOL WINAPI
SetupGetStringFieldW( const INFCONTEXT
*context
, DWORD index
, PWSTR buffer
,
1575 DWORD size
, DWORD
*required
)
1577 struct inf_file
*file
= context
->CurrentInf
;
1578 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1582 if (!field
) return FALSE
;
1583 len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 );
1584 if (required
) *required
= len
+ 1;
1589 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1592 PARSER_string_substW( file
, field
->text
, buffer
, size
);
1594 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1595 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1596 index
, debugstr_w(buffer
) );
1602 /***********************************************************************
1603 * SetupGetIntField (SETUPAPI.@)
1605 BOOL WINAPI
SetupGetIntField( const INFCONTEXT
*context
, DWORD index
, INT
*result
)
1608 char *end
, *buffer
= localbuff
;
1613 if (!SetupGetStringFieldA( context
, index
, localbuff
, sizeof(localbuff
), &required
))
1615 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
1616 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
))) return FALSE
;
1617 if (!SetupGetStringFieldA( context
, index
, buffer
, required
, NULL
)) goto done
;
1619 res
= strtol( buffer
, &end
, 0 );
1620 if (end
!= buffer
&& !*end
)
1625 else SetLastError( ERROR_INVALID_DATA
);
1628 if (buffer
!= localbuff
) HeapFree( GetProcessHeap(), 0, buffer
);
1633 /***********************************************************************
1634 * SetupGetBinaryField (SETUPAPI.@)
1636 BOOL WINAPI
SetupGetBinaryField( const INFCONTEXT
*context
, DWORD index
, BYTE
*buffer
,
1637 DWORD size
, DWORD
*required
)
1639 struct inf_file
*file
= context
->CurrentInf
;
1640 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1641 struct field
*field
;
1646 SetLastError( ERROR_LINE_NOT_FOUND
);
1649 if (!index
|| index
>= line
->nb_fields
)
1651 SetLastError( ERROR_INVALID_PARAMETER
);
1654 index
--; /* fields start at 0 */
1655 if (required
) *required
= line
->nb_fields
- index
;
1656 if (!buffer
) return TRUE
;
1657 if (size
< line
->nb_fields
- index
)
1659 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1662 field
= &file
->fields
[line
->first_field
+ index
];
1663 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1667 for (p
= field
->text
; *p
&& isxdigitW(*p
); p
++)
1669 if ((value
<<= 4) > 255)
1671 SetLastError( ERROR_INVALID_DATA
);
1674 if (*p
<= '9') value
|= (*p
- '0');
1675 else value
|= (tolowerW(*p
) - 'a' + 10);
1677 buffer
[i
- index
] = value
;
1679 if (TRACE_ON(setupapi
))
1681 TRACE( "%p/%p/%d/%d index %ld returning",
1682 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
, index
);
1683 for (i
= index
; i
< line
->nb_fields
; i
++) TRACE( " %02x", buffer
[i
- index
] );
1690 /***********************************************************************
1691 * SetupGetMultiSzFieldA (SETUPAPI.@)
1693 BOOL WINAPI
SetupGetMultiSzFieldA( const INFCONTEXT
*context
, DWORD index
, PSTR buffer
,
1694 DWORD size
, DWORD
*required
)
1696 struct inf_file
*file
= context
->CurrentInf
;
1697 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1698 struct field
*field
;
1705 SetLastError( ERROR_LINE_NOT_FOUND
);
1708 if (!index
|| index
>= line
->nb_fields
)
1710 SetLastError( ERROR_INVALID_PARAMETER
);
1713 index
--; /* fields start at 0 */
1714 field
= &file
->fields
[line
->first_field
+ index
];
1715 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1717 if (!(len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 ))) break;
1721 if (required
) *required
= total
;
1722 if (!buffer
) return TRUE
;
1725 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1728 field
= &file
->fields
[line
->first_field
+ index
];
1729 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1731 if (!(len
= PARSER_string_substA( file
, field
->text
, buffer
, size
))) break;
1734 *buffer
= 0; /* add final null */
1739 /***********************************************************************
1740 * SetupGetMultiSzFieldW (SETUPAPI.@)
1742 BOOL WINAPI
SetupGetMultiSzFieldW( const INFCONTEXT
*context
, DWORD index
, PWSTR buffer
,
1743 DWORD size
, DWORD
*required
)
1745 struct inf_file
*file
= context
->CurrentInf
;
1746 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1747 struct field
*field
;
1754 SetLastError( ERROR_LINE_NOT_FOUND
);
1757 if (!index
|| index
>= line
->nb_fields
)
1759 SetLastError( ERROR_INVALID_PARAMETER
);
1762 index
--; /* fields start at 0 */
1763 field
= &file
->fields
[line
->first_field
+ index
];
1764 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1766 if (!(len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 ))) break;
1770 if (required
) *required
= total
;
1771 if (!buffer
) return TRUE
;
1774 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1777 field
= &file
->fields
[line
->first_field
+ index
];
1778 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1780 if (!(len
= PARSER_string_substW( file
, field
->text
, buffer
, size
))) break;
1783 *buffer
= 0; /* add final null */