4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005 Hervé Poussineau (hpoussin@reactos.org)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "setupapi_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* Unicode constants */
27 static const WCHAR BackSlash
[] = {'\\',0};
28 static const WCHAR InfDirectory
[] = {'i','n','f','\\',0};
29 static const WCHAR InfFileSpecification
[] = {'*','.','i','n','f',0};
31 #define CONTROL_Z '\x1a'
32 #define MAX_SECTION_NAME_LEN 255
33 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
34 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
35 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
37 /* inf file structure definitions */
41 const WCHAR
*text
; /* field text */
46 int first_field
; /* index of first field in field array */
47 int nb_fields
; /* number of fields in line */
48 int key_field
; /* index of field for key or -1 if no key */
53 const WCHAR
*name
; /* section name */
54 unsigned int nb_lines
; /* number of used lines */
55 unsigned int alloc_lines
; /* total number of allocated lines in array below */
56 struct line lines
[16]; /* lines information (grown dynamically, 16 is initial size) */
61 struct inf_file
*next
; /* next appended file */
62 WCHAR
*strings
; /* buffer for string data (section names and field values) */
63 WCHAR
*string_pos
; /* position of next available string in buffer */
64 unsigned int nb_sections
; /* number of used sections */
65 unsigned int alloc_sections
; /* total number of allocated section pointers */
66 struct section
**sections
; /* section pointers array */
67 unsigned int nb_fields
;
68 unsigned int alloc_fields
;
70 int strings_section
; /* index of [Strings] section or -1 if none */
71 WCHAR
*src_root
; /* source root directory */
74 /* parser definitions */
78 LINE_START
, /* at beginning of a line */
79 SECTION_NAME
, /* parsing a section name */
80 KEY_NAME
, /* parsing a key name */
81 VALUE_NAME
, /* parsing a value name */
82 EOL_BACKSLASH
, /* backslash at end of line */
83 QUOTES
, /* inside quotes */
84 LEADING_SPACES
, /* leading spaces */
85 TRAILING_SPACES
, /* trailing spaces */
86 COMMENT
, /* inside a comment */
92 const WCHAR
*start
; /* start position of item being parsed */
93 const WCHAR
*end
; /* end of buffer */
94 struct inf_file
*file
; /* file being built */
95 enum parser_state state
; /* current parser state */
96 enum parser_state stack
[4]; /* state stack */
97 int stack_pos
; /* current pos in stack */
99 int cur_section
; /* index of section being parsed*/
100 struct line
*line
; /* current line */
101 unsigned int line_pos
; /* current line position in file */
102 unsigned int error
; /* error code */
103 unsigned int token_len
; /* current token len */
104 WCHAR token
[MAX_FIELD_LEN
+1]; /* current token */
107 typedef const WCHAR
* (*parser_state_func
)( struct parser
*parser
, const WCHAR
*pos
);
109 /* parser state machine functions */
110 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
);
111 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
);
112 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
);
113 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
);
114 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
);
115 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
);
116 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
117 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
);
118 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
);
120 static const parser_state_func parser_funcs
[NB_PARSER_STATES
] =
122 line_start_state
, /* LINE_START */
123 section_name_state
, /* SECTION_NAME */
124 key_name_state
, /* KEY_NAME */
125 value_name_state
, /* VALUE_NAME */
126 eol_backslash_state
, /* EOL_BACKSLASH */
127 quotes_state
, /* QUOTES */
128 leading_spaces_state
, /* LEADING_SPACES */
129 trailing_spaces_state
, /* TRAILING_SPACES */
130 comment_state
/* COMMENT */
134 /* Unicode string constants */
135 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
136 static const WCHAR Signature
[] = {'S','i','g','n','a','t','u','r','e',0};
137 static const WCHAR Chicago
[] = {'$','C','h','i','c','a','g','o','$',0};
138 static const WCHAR WindowsNT
[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
139 static const WCHAR Windows95
[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0};
140 static const WCHAR LayoutFile
[] = {'L','a','y','o','u','t','F','i','l','e',0};
142 /* extend an array, allocating more memory if necessary */
143 static void *grow_array( void *array
, unsigned int *count
, size_t elem
)
146 unsigned int new_count
= *count
+ *count
/ 2;
147 if (new_count
< 32) new_count
= 32;
150 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, array
, new_count
* elem
);
152 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* elem
);
157 HeapFree( GetProcessHeap(), 0, array
);
162 /* find a section by name */
163 static int find_section( struct inf_file
*file
, const WCHAR
*name
)
167 for (i
= 0; i
< file
->nb_sections
; i
++)
168 if (!strcmpiW( name
, file
->sections
[i
]->name
)) return i
;
173 /* find a line by name */
174 static struct line
*find_line( struct inf_file
*file
, int section_index
, const WCHAR
*name
)
176 struct section
*section
;
180 if (section_index
< 0 || section_index
>= file
->nb_sections
) return NULL
;
181 section
= file
->sections
[section_index
];
182 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
184 if (line
->key_field
== -1) continue;
185 if (!strcmpiW( name
, file
->fields
[line
->key_field
].text
)) return line
;
191 /* add a section to the file and return the section index */
192 static int add_section( struct inf_file
*file
, const WCHAR
*name
)
194 struct section
*section
;
196 if (file
->nb_sections
>= file
->alloc_sections
)
198 if (!(file
->sections
= grow_array( file
->sections
, &file
->alloc_sections
,
199 sizeof(file
->sections
[0]) ))) return -1;
201 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) ))) return -1;
202 section
->name
= name
;
203 section
->nb_lines
= 0;
204 section
->alloc_lines
= sizeof(section
->lines
)/sizeof(section
->lines
[0]);
205 file
->sections
[file
->nb_sections
] = section
;
206 return file
->nb_sections
++;
210 /* add a line to a given section */
211 static struct line
*add_line( struct inf_file
*file
, int section_index
)
213 struct section
*section
;
216 ASSERT( section_index
>= 0 && section_index
< file
->nb_sections
);
218 section
= file
->sections
[section_index
];
219 if (section
->nb_lines
== section
->alloc_lines
) /* need to grow the section */
221 int size
= sizeof(*section
) - sizeof(section
->lines
) + 2*section
->alloc_lines
*sizeof(*line
);
222 if (!(section
= HeapReAlloc( GetProcessHeap(), 0, section
, size
))) return NULL
;
223 section
->alloc_lines
*= 2;
224 file
->sections
[section_index
] = section
;
226 line
= §ion
->lines
[section
->nb_lines
++];
227 line
->first_field
= file
->nb_fields
;
229 line
->key_field
= -1;
234 /* retrieve a given line from section/line index */
235 inline static struct line
*get_line( struct inf_file
*file
, unsigned int section_index
,
236 unsigned int line_index
)
238 struct section
*section
;
240 if (section_index
>= file
->nb_sections
) return NULL
;
241 section
= file
->sections
[section_index
];
242 if (line_index
>= section
->nb_lines
) return NULL
;
243 return §ion
->lines
[line_index
];
247 /* retrieve a given field from section/line/field index */
248 static struct field
*get_field( struct inf_file
*file
, int section_index
, int line_index
,
251 struct line
*line
= get_line( file
, section_index
, line_index
);
253 if (!line
) return NULL
;
254 if (!field_index
) /* get the key */
256 if (line
->key_field
== -1) return NULL
;
257 return &file
->fields
[line
->key_field
];
260 if (field_index
>= line
->nb_fields
) return NULL
;
261 return &file
->fields
[line
->first_field
+ field_index
];
265 /* allocate a new field, growing the array if necessary */
266 static struct field
*add_field( struct inf_file
*file
, const WCHAR
*text
)
270 if (file
->nb_fields
>= file
->alloc_fields
)
272 if (!(file
->fields
= grow_array( file
->fields
, &file
->alloc_fields
,
273 sizeof(file
->fields
[0]) ))) return NULL
;
275 field
= &file
->fields
[file
->nb_fields
++];
281 /* retrieve the string substitution for a directory id */
282 static const WCHAR
*get_dirid_subst( int dirid
, unsigned int *len
)
284 extern const WCHAR
*DIRID_get_string( HINF hinf
, int dirid
);
285 const WCHAR
*ret
= DIRID_get_string( 0, dirid
);
286 if (ret
) *len
= strlenW(ret
);
291 /* retrieve the string substitution for a given string, or NULL if not found */
292 /* if found, len is set to the substitution length */
293 static const WCHAR
*get_string_subst( struct inf_file
*file
, const WCHAR
*str
, unsigned int *len
)
295 static const WCHAR percent
= '%';
297 struct section
*strings_section
;
302 WCHAR
*dirid_str
, *end
;
303 const WCHAR
*ret
= NULL
;
305 if (!*len
) /* empty string (%%) is replaced by single percent */
310 if (file
->strings_section
== -1) goto not_found
;
311 strings_section
= file
->sections
[file
->strings_section
];
312 for (i
= 0, line
= strings_section
->lines
; i
< strings_section
->nb_lines
; i
++, line
++)
314 if (line
->key_field
== -1) continue;
315 if (strncmpiW( str
, file
->fields
[line
->key_field
].text
, *len
)) continue;
316 if (!file
->fields
[line
->key_field
].text
[*len
]) break;
318 if (i
== strings_section
->nb_lines
|| !line
->nb_fields
) goto not_found
;
319 field
= &file
->fields
[line
->first_field
];
320 *len
= strlenW( field
->text
);
323 not_found
: /* check for integer id */
324 if ((dirid_str
= HeapAlloc( GetProcessHeap(), 0, (*len
+1) * sizeof(WCHAR
) )))
326 memcpy( dirid_str
, str
, *len
* sizeof(WCHAR
) );
328 dirid
= strtolW( dirid_str
, &end
, 10 );
329 if (!*end
) ret
= get_dirid_subst( dirid
, len
);
330 HeapFree( GetProcessHeap(), 0, dirid_str
);
337 /* do string substitutions on the specified text */
338 /* the buffer is assumed to be large enough */
339 /* returns necessary length not including terminating null */
340 unsigned int PARSER_string_substW( struct inf_file
*file
, const WCHAR
*text
, WCHAR
*buffer
,
343 const WCHAR
*start
, *subst
, *p
;
344 unsigned int len
, total
= 0;
347 if (!buffer
) size
= MAX_STRING_LEN
+ 1;
348 for (p
= start
= text
; *p
; p
++)
350 if (*p
!= '%') continue;
352 if (inside
) /* start of a %xx% string */
355 if (len
> size
- 1) len
= size
- 1;
356 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
361 else /* end of the %xx% string, find substitution */
364 subst
= get_string_subst( file
, start
+ 1, &len
);
370 if (len
> size
- 1) len
= size
- 1;
371 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
378 if (start
!= p
) /* unfinished string, copy it */
381 if (len
> size
- 1) len
= size
- 1;
382 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
385 if (buffer
&& size
) buffer
[total
] = 0;
390 /* do string substitutions on the specified text */
391 /* the buffer is assumed to be large enough */
392 /* returns necessary length not including terminating null */
393 unsigned int PARSER_string_substA( struct inf_file
*file
, const WCHAR
*text
, char *buffer
,
396 WCHAR buffW
[MAX_STRING_LEN
+1];
399 unsigned int len
= PARSER_string_substW( file
, text
, buffW
, sizeof(buffW
)/sizeof(WCHAR
) );
400 if (!buffer
) RtlUnicodeToMultiByteSize( &ret
, buffW
, len
* sizeof(WCHAR
) );
403 RtlUnicodeToMultiByteN( buffer
, size
-1, &ret
, buffW
, len
* sizeof(WCHAR
) );
410 /* push some string data into the strings buffer */
411 static WCHAR
*push_string( struct inf_file
*file
, const WCHAR
*string
)
413 WCHAR
*ret
= file
->string_pos
;
414 strcpyW( ret
, string
);
415 file
->string_pos
+= strlenW( ret
) + 1;
420 /* push the current state on the parser stack */
421 inline static void push_state( struct parser
*parser
, enum parser_state state
)
423 ASSERT( parser
->stack_pos
< sizeof(parser
->stack
)/sizeof(parser
->stack
[0]) );
424 parser
->stack
[parser
->stack_pos
++] = state
;
428 /* pop the current state */
429 inline static void pop_state( struct parser
*parser
)
431 ASSERT( parser
->stack_pos
);
432 parser
->state
= parser
->stack
[--parser
->stack_pos
];
436 /* set the parser state and return the previous one */
437 inline static enum parser_state
set_state( struct parser
*parser
, enum parser_state state
)
439 enum parser_state ret
= parser
->state
;
440 parser
->state
= state
;
445 /* check if the pointer points to an end of file */
446 inline static int is_eof( struct parser
*parser
, const WCHAR
*ptr
)
448 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
);
452 /* check if the pointer points to an end of line */
453 inline static int is_eol( struct parser
*parser
, const WCHAR
*ptr
)
455 return (ptr
>= parser
->end
|| *ptr
== CONTROL_Z
|| *ptr
== '\n');
459 /* push data from current token start up to pos into the current token */
460 static int push_token( struct parser
*parser
, const WCHAR
*pos
)
462 int len
= pos
- parser
->start
;
463 const WCHAR
*src
= parser
->start
;
464 WCHAR
*dst
= parser
->token
+ parser
->token_len
;
466 if (len
> MAX_FIELD_LEN
- parser
->token_len
) len
= MAX_FIELD_LEN
- parser
->token_len
;
468 parser
->token_len
+= len
;
469 for ( ; len
> 0; len
--, dst
++, src
++) *dst
= *src
? *src
: ' ';
476 /* add a section with the current token as name */
477 static int add_section_from_token( struct parser
*parser
)
481 if (parser
->token_len
> MAX_SECTION_NAME_LEN
)
483 parser
->error
= ERROR_SECTION_NAME_TOO_LONG
;
486 if ((section_index
= find_section( parser
->file
, parser
->token
)) == -1)
488 /* need to create a new one */
489 const WCHAR
*name
= push_string( parser
->file
, parser
->token
);
490 if ((section_index
= add_section( parser
->file
, name
)) == -1)
492 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
496 parser
->token_len
= 0;
497 parser
->cur_section
= section_index
;
498 return section_index
;
502 /* add a field containing the current token to the current line */
503 static struct field
*add_field_from_token( struct parser
*parser
, int is_key
)
508 if (!parser
->line
) /* need to start a new line */
510 if (parser
->cur_section
== -1) /* got a line before the first section */
512 parser
->error
= ERROR_EXPECTED_SECTION_NAME
;
515 if (!(parser
->line
= add_line( parser
->file
, parser
->cur_section
))) goto error
;
517 else ASSERT(!is_key
);
519 text
= push_string( parser
->file
, parser
->token
);
520 if ((field
= add_field( parser
->file
, text
)))
522 if (!is_key
) parser
->line
->nb_fields
++;
525 /* replace first field by key field */
526 parser
->line
->key_field
= parser
->line
->first_field
;
527 parser
->line
->first_field
++;
529 parser
->token_len
= 0;
533 parser
->error
= ERROR_NOT_ENOUGH_MEMORY
;
538 /* close the current line and prepare for parsing a new one */
539 static void close_current_line( struct parser
*parser
)
541 struct line
*cur_line
= parser
->line
;
545 /* if line has a single field and no key, the field is the key too */
546 if (cur_line
->nb_fields
== 1 && cur_line
->key_field
== -1)
547 cur_line
->key_field
= cur_line
->first_field
;
553 /* handler for parser LINE_START state */
554 static const WCHAR
*line_start_state( struct parser
*parser
, const WCHAR
*pos
)
558 for (p
= pos
; !is_eof( parser
, p
); p
++)
564 close_current_line( parser
);
567 push_state( parser
, LINE_START
);
568 set_state( parser
, COMMENT
);
571 parser
->start
= p
+ 1;
572 set_state( parser
, SECTION_NAME
);
578 set_state( parser
, KEY_NAME
);
584 close_current_line( parser
);
589 /* handler for parser SECTION_NAME state */
590 static const WCHAR
*section_name_state( struct parser
*parser
, const WCHAR
*pos
)
594 for (p
= pos
; !is_eol( parser
, p
); p
++)
598 push_token( parser
, p
);
599 if (add_section_from_token( parser
) == -1) return NULL
;
600 push_state( parser
, LINE_START
);
601 set_state( parser
, COMMENT
); /* ignore everything else on the line */
605 parser
->error
= ERROR_BAD_SECTION_NAME_LINE
; /* unfinished section name */
610 /* handler for parser KEY_NAME state */
611 static const WCHAR
*key_name_state( struct parser
*parser
, const WCHAR
*pos
)
613 const WCHAR
*p
, *token_end
= parser
->start
;
615 for (p
= pos
; !is_eol( parser
, p
); p
++)
617 if (*p
== ',') break;
622 push_token( parser
, token_end
);
623 if (!add_field_from_token( parser
, 1 )) return NULL
;
624 parser
->start
= p
+ 1;
625 push_state( parser
, VALUE_NAME
);
626 set_state( parser
, LEADING_SPACES
);
629 push_token( parser
, token_end
);
630 if (!add_field_from_token( parser
, 0 )) return NULL
;
631 push_state( parser
, LINE_START
);
632 set_state( parser
, COMMENT
);
635 push_token( parser
, p
);
636 parser
->start
= p
+ 1;
637 push_state( parser
, KEY_NAME
);
638 set_state( parser
, QUOTES
);
641 push_token( parser
, token_end
);
643 push_state( parser
, KEY_NAME
);
644 set_state( parser
, EOL_BACKSLASH
);
647 if (!isspaceW(*p
)) token_end
= p
+ 1;
650 push_token( parser
, p
);
651 push_state( parser
, KEY_NAME
);
652 set_state( parser
, TRAILING_SPACES
);
658 push_token( parser
, token_end
);
659 set_state( parser
, VALUE_NAME
);
664 /* handler for parser VALUE_NAME state */
665 static const WCHAR
*value_name_state( struct parser
*parser
, const WCHAR
*pos
)
667 const WCHAR
*p
, *token_end
= parser
->start
;
669 for (p
= pos
; !is_eol( parser
, p
); p
++)
674 push_token( parser
, token_end
);
675 if (!add_field_from_token( parser
, 0 )) return NULL
;
676 push_state( parser
, LINE_START
);
677 set_state( parser
, COMMENT
);
680 push_token( parser
, token_end
);
681 if (!add_field_from_token( parser
, 0 )) return NULL
;
682 parser
->start
= p
+ 1;
683 push_state( parser
, VALUE_NAME
);
684 set_state( parser
, LEADING_SPACES
);
687 push_token( parser
, p
);
688 parser
->start
= p
+ 1;
689 push_state( parser
, VALUE_NAME
);
690 set_state( parser
, QUOTES
);
693 push_token( parser
, token_end
);
695 push_state( parser
, VALUE_NAME
);
696 set_state( parser
, EOL_BACKSLASH
);
699 if (!isspaceW(*p
)) token_end
= p
+ 1;
702 push_token( parser
, p
);
703 push_state( parser
, VALUE_NAME
);
704 set_state( parser
, TRAILING_SPACES
);
710 push_token( parser
, token_end
);
711 if (!add_field_from_token( parser
, 0 )) return NULL
;
712 set_state( parser
, LINE_START
);
717 /* handler for parser EOL_BACKSLASH state */
718 static const WCHAR
*eol_backslash_state( struct parser
*parser
, const WCHAR
*pos
)
722 for (p
= pos
; !is_eof( parser
, p
); p
++)
728 parser
->start
= p
+ 1;
729 set_state( parser
, LEADING_SPACES
);
734 push_state( parser
, EOL_BACKSLASH
);
735 set_state( parser
, COMMENT
);
738 if (isspaceW(*p
)) continue;
739 push_token( parser
, p
);
750 /* handler for parser QUOTES state */
751 static const WCHAR
*quotes_state( struct parser
*parser
, const WCHAR
*pos
)
753 const WCHAR
*p
, *token_end
= parser
->start
;
755 for (p
= pos
; !is_eol( parser
, p
); p
++)
759 if (p
+1 < parser
->end
&& p
[1] == '"') /* double quotes */
761 push_token( parser
, p
+ 1 );
762 parser
->start
= token_end
= p
+ 2;
765 else /* end of quotes */
767 push_token( parser
, p
);
768 parser
->start
= p
+ 1;
774 push_token( parser
, p
);
780 /* handler for parser LEADING_SPACES state */
781 static const WCHAR
*leading_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
785 for (p
= pos
; !is_eol( parser
, p
); p
++)
790 set_state( parser
, EOL_BACKSLASH
);
793 if (!isspaceW(*p
)) break;
801 /* handler for parser TRAILING_SPACES state */
802 static const WCHAR
*trailing_spaces_state( struct parser
*parser
, const WCHAR
*pos
)
806 for (p
= pos
; !is_eol( parser
, p
); p
++)
810 set_state( parser
, EOL_BACKSLASH
);
813 if (!isspaceW(*p
)) break;
820 /* handler for parser COMMENT state */
821 static const WCHAR
*comment_state( struct parser
*parser
, const WCHAR
*pos
)
823 const WCHAR
*p
= pos
;
825 while (!is_eol( parser
, p
)) p
++;
831 /* parse a complete buffer */
832 static DWORD
parse_buffer( struct inf_file
*file
, const WCHAR
*buffer
, const WCHAR
*end
,
835 static const WCHAR Strings
[] = {'S','t','r','i','n','g','s',0};
837 struct parser parser
;
838 const WCHAR
*pos
= buffer
;
840 parser
.start
= buffer
;
844 parser
.state
= LINE_START
;
845 parser
.stack_pos
= 0;
846 parser
.cur_section
= -1;
849 parser
.token_len
= 0;
851 /* parser main loop */
852 while (pos
) pos
= (parser_funcs
[parser
.state
])( &parser
, pos
);
854 /* trim excess buffer space */
855 if (file
->alloc_sections
> file
->nb_sections
)
857 file
->sections
= HeapReAlloc( GetProcessHeap(), 0, file
->sections
,
858 file
->nb_sections
* sizeof(file
->sections
[0]) );
859 file
->alloc_sections
= file
->nb_sections
;
861 if (file
->alloc_fields
> file
->nb_fields
)
863 file
->fields
= HeapReAlloc( GetProcessHeap(), 0, file
->fields
,
864 file
->nb_fields
* sizeof(file
->fields
[0]) );
865 file
->alloc_fields
= file
->nb_fields
;
867 file
->strings
= HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY
, file
->strings
,
868 (file
->string_pos
- file
->strings
) * sizeof(WCHAR
) );
872 if (error_line
) *error_line
= parser
.line_pos
;
876 /* find the [strings] section */
877 file
->strings_section
= find_section( file
, Strings
);
882 /* append a child INF file to its parent list, in a thread-safe manner */
883 static void append_inf_file( struct inf_file
*parent
, struct inf_file
*child
)
885 struct inf_file
**ppnext
= &parent
->next
;
890 struct inf_file
*next
= InterlockedCompareExchangePointer( (void **)ppnext
, child
, NULL
);
892 ppnext
= &next
->next
;
897 /***********************************************************************
902 static struct inf_file
*parse_file( HANDLE handle
, UINT
*error_line
)
906 struct inf_file
*file
;
908 DWORD size
= GetFileSize( handle
, NULL
);
909 HANDLE mapping
= CreateFileMappingW( handle
, NULL
, PAGE_READONLY
, 0, size
, NULL
);
910 if (!mapping
) return NULL
;
911 buffer
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, size
);
913 if (!buffer
) return NULL
;
915 if (!(file
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*file
) )))
917 err
= ERROR_NOT_ENOUGH_MEMORY
;
921 /* we won't need more strings space than the size of the file,
922 * so we can preallocate it here
924 if (!(file
->strings
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
926 err
= ERROR_NOT_ENOUGH_MEMORY
;
929 file
->string_pos
= file
->strings
;
930 file
->strings_section
= -1;
932 if (!RtlIsTextUnicode( buffer
, size
, NULL
))
934 WCHAR
*new_buff
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) );
937 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buffer
, size
, new_buff
, size
);
938 err
= parse_buffer( file
, new_buff
, new_buff
+ len
, error_line
);
939 HeapFree( GetProcessHeap(), 0, new_buff
);
944 WCHAR
*new_buff
= (WCHAR
*)buffer
;
945 /* Some UNICODE files may start with the UNICODE marker */
946 if (*new_buff
== 0xfeff)
948 err
= parse_buffer( file
, new_buff
, (WCHAR
*)((char *)new_buff
+ size
), error_line
);
951 if (!err
) /* now check signature */
953 int version_index
= find_section( file
, Version
);
954 if (version_index
!= -1)
956 struct line
*line
= find_line( file
, version_index
, Signature
);
957 if (line
&& line
->nb_fields
> 0)
959 struct field
*field
= file
->fields
+ line
->first_field
;
960 if (!strcmpiW( field
->text
, Chicago
)) goto done
;
961 if (!strcmpiW( field
->text
, WindowsNT
)) goto done
;
962 if (!strcmpiW( field
->text
, Windows95
)) goto done
;
965 if (error_line
) *error_line
= 0;
966 err
= ERROR_WRONG_INF_STYLE
;
970 UnmapViewOfFile( buffer
);
973 HeapFree( GetProcessHeap(), 0, file
);
981 /***********************************************************************
982 * PARSER_get_src_root
984 * Retrieve the source directory of an inf file.
986 const WCHAR
*PARSER_get_src_root( HINF hinf
)
988 struct inf_file
*file
= hinf
;
989 return file
->src_root
;
993 /***********************************************************************
994 * PARSER_get_dest_dir
996 * retrieve a destination dir of the form "dirid,relative_path" in the given entry.
997 * returned buffer must be freed by caller.
999 WCHAR
*PARSER_get_dest_dir( INFCONTEXT
*context
)
1006 if (!SetupGetIntField( context
, 1, &dirid
)) return NULL
;
1007 if (!(dir
= DIRID_get_string( context
->Inf
, dirid
))) return NULL
;
1008 len1
= strlenW(dir
) + 1;
1009 if (!SetupGetStringFieldW( context
, 2, NULL
, 0, &len2
)) len2
= 0;
1010 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, (len1
+len2
) * sizeof(WCHAR
) ))) return NULL
;
1011 strcpyW( ret
, dir
);
1012 ptr
= ret
+ strlenW(ret
);
1013 if (len2
&& ptr
> ret
&& ptr
[-1] != '\\') *ptr
++ = '\\';
1014 if (!SetupGetStringFieldW( context
, 2, ptr
, len2
, NULL
)) *ptr
= 0;
1019 /***********************************************************************
1020 * SetupOpenInfFileA (SETUPAPI.@)
1022 HINF WINAPI
SetupOpenInfFileA( PCSTR name
, PCSTR
class, DWORD style
, UINT
*error
)
1024 UNICODE_STRING nameW
, classW
;
1025 HINF ret
= (HINF
)INVALID_HANDLE_VALUE
;
1027 classW
.Buffer
= NULL
;
1028 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW
, class ))
1030 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1033 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, name
))
1035 ret
= SetupOpenInfFileW( nameW
.Buffer
, classW
.Buffer
, style
, error
);
1036 RtlFreeUnicodeString( &nameW
);
1038 RtlFreeUnicodeString( &classW
);
1046 OUT LPGUID ClassGuid
,
1047 OUT PWSTR ClassName
,
1048 IN DWORD ClassNameSize
,
1049 OUT PDWORD RequiredSize OPTIONAL
)
1052 WCHAR guidW
[MAX_GUID_STRING_LEN
+ 1];
1055 /* Read class Guid */
1056 if (!SetupGetLineTextW(NULL
, hInf
, L
"Version", L
"ClassGUID", guidW
, sizeof(guidW
), NULL
))
1058 guidW
[37] = '\0'; /* Replace the } by a NULL character */
1059 if (UuidFromStringW(&guidW
[1], ClassGuid
) != RPC_S_OK
)
1062 /* Read class name */
1063 ret
= SetupGetLineTextW(NULL
, hInf
, L
"Version", L
"Class", ClassName
, ClassNameSize
, &requiredSize
);
1064 if (ret
&& ClassName
== NULL
&& ClassNameSize
== 0)
1067 *RequiredSize
= requiredSize
;
1068 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1074 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
1077 *RequiredSize
= requiredSize
;
1080 else if (!SetupDiClassNameFromGuidW(ClassGuid
, ClassName
, ClassNameSize
, &requiredSize
))
1082 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
1085 *RequiredSize
= requiredSize
;
1088 /* Return a NULL class name */
1091 if (ClassNameSize
< 1)
1093 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1096 memcpy(ClassGuid
, &GUID_NULL
, sizeof(GUID
));
1097 *ClassName
= UNICODE_NULL
;
1104 TRACE("Returning %d\n", ret
);
1109 /***********************************************************************
1110 * SetupOpenInfFileW (SETUPAPI.@)
1112 HINF WINAPI
SetupOpenInfFileW( PCWSTR name
, PCWSTR
class, DWORD style
, UINT
*error
)
1114 struct inf_file
*file
= NULL
;
1119 TRACE("%S %S %lx %p\n", name
, class, style
, error
);
1121 if (strchrW( name
, '\\' ) || strchrW( name
, '/' ))
1123 if (!(len
= GetFullPathNameW( name
, 0, NULL
, NULL
))) return (HINF
)INVALID_HANDLE_VALUE
;
1124 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1126 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1127 return (HINF
)INVALID_HANDLE_VALUE
;
1129 GetFullPathNameW( name
, len
, path
, NULL
);
1130 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1132 else /* try Windows directory */
1134 static const WCHAR Inf
[] = {'\\','i','n','f','\\',0};
1135 static const WCHAR System32
[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
1137 len
= GetWindowsDirectoryW( NULL
, 0 ) + strlenW(name
) + 12;
1138 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1140 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1141 return (HINF
)INVALID_HANDLE_VALUE
;
1143 GetWindowsDirectoryW( path
, len
);
1144 p
= path
+ strlenW(path
);
1147 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1148 if (handle
== INVALID_HANDLE_VALUE
)
1150 strcpyW( p
, System32
);
1152 handle
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1156 if (handle
!= INVALID_HANDLE_VALUE
)
1158 file
= parse_file( handle
, error
);
1159 CloseHandle( handle
);
1163 HeapFree( GetProcessHeap(), 0, path
);
1164 return (HINF
)INVALID_HANDLE_VALUE
;
1166 TRACE( "%s -> %p\n", debugstr_w(path
), file
);
1167 file
->src_root
= path
;
1168 if ((p
= strrchrW( path
, '\\' ))) p
[1] = 0; /* remove file name */
1173 LPWSTR ClassName
= HeapAlloc(GetProcessHeap(), 0, (strlenW(class) + 1) * sizeof(WCHAR
));
1176 /* Not enough memory */
1177 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1178 SetupCloseInfFile((HINF
)file
);
1181 else if (!GetInfClassW((HINF
)file
, &ClassGuid
, ClassName
, strlenW(class) + 1, NULL
))
1183 /* Unable to get class name in .inf file */
1184 HeapFree(GetProcessHeap(), 0, ClassName
);
1185 SetLastError(ERROR_CLASS_MISMATCH
);
1186 SetupCloseInfFile((HINF
)file
);
1189 else if (strcmpW(class, ClassName
) != 0)
1191 /* Provided name name is not the expected one */
1192 HeapFree(GetProcessHeap(), 0, ClassName
);
1193 SetLastError(ERROR_CLASS_MISMATCH
);
1194 SetupCloseInfFile((HINF
)file
);
1197 HeapFree(GetProcessHeap(), 0, ClassName
);
1205 /***********************************************************************
1206 * SetupOpenAppendInfFileA (SETUPAPI.@)
1208 BOOL WINAPI
SetupOpenAppendInfFileA( PCSTR name
, HINF parent_hinf
, UINT
*error
)
1212 if (!name
) return SetupOpenAppendInfFileW( NULL
, parent_hinf
, error
);
1213 child_hinf
= SetupOpenInfFileA( name
, NULL
, INF_STYLE_WIN4
, error
);
1214 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1215 append_inf_file( parent_hinf
, child_hinf
);
1216 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_a(name
), child_hinf
);
1221 /***********************************************************************
1222 * SetupOpenAppendInfFileW (SETUPAPI.@)
1224 BOOL WINAPI
SetupOpenAppendInfFileW( PCWSTR name
, HINF parent_hinf
, UINT
*error
)
1231 WCHAR filename
[MAX_PATH
];
1234 if (!SetupFindFirstLineW( parent_hinf
, Version
, LayoutFile
, &context
)) return FALSE
;
1235 while (SetupGetStringFieldW( &context
, idx
++, filename
,
1236 sizeof(filename
)/sizeof(WCHAR
), NULL
))
1238 child_hinf
= SetupOpenInfFileW( filename
, NULL
, INF_STYLE_WIN4
, error
);
1239 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1240 append_inf_file( parent_hinf
, child_hinf
);
1241 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(filename
), child_hinf
);
1245 child_hinf
= SetupOpenInfFileW( name
, NULL
, INF_STYLE_WIN4
, error
);
1246 if (child_hinf
== (HINF
)INVALID_HANDLE_VALUE
) return FALSE
;
1247 append_inf_file( parent_hinf
, child_hinf
);
1248 TRACE( "%p: appended %s (%p)\n", parent_hinf
, debugstr_w(name
), child_hinf
);
1253 /***********************************************************************
1254 * SetupOpenMasterInf (SETUPAPI.@)
1256 HINF WINAPI
SetupOpenMasterInf( VOID
)
1258 static const WCHAR Layout
[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0};
1259 WCHAR Buffer
[MAX_PATH
];
1261 GetWindowsDirectoryW( Buffer
, MAX_PATH
);
1262 strcatW( Buffer
, Layout
);
1263 return SetupOpenInfFileW( Buffer
, NULL
, INF_STYLE_WIN4
, NULL
);
1268 /***********************************************************************
1269 * SetupCloseInfFile (SETUPAPI.@)
1271 void WINAPI
SetupCloseInfFile( HINF hinf
)
1273 struct inf_file
*file
= hinf
;
1276 for (i
= 0; i
< file
->nb_sections
; i
++) HeapFree( GetProcessHeap(), 0, file
->sections
[i
] );
1277 HeapFree( GetProcessHeap(), 0, file
->src_root
);
1278 HeapFree( GetProcessHeap(), 0, file
->sections
);
1279 HeapFree( GetProcessHeap(), 0, file
->fields
);
1280 HeapFree( GetProcessHeap(), 0, file
->strings
);
1281 HeapFree( GetProcessHeap(), 0, file
);
1285 /***********************************************************************
1286 * SetupGetLineCountA (SETUPAPI.@)
1288 LONG WINAPI
SetupGetLineCountA( HINF hinf
, PCSTR name
)
1290 UNICODE_STRING sectionW
;
1293 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, name
))
1294 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1297 ret
= SetupGetLineCountW( hinf
, sectionW
.Buffer
);
1298 RtlFreeUnicodeString( §ionW
);
1304 /***********************************************************************
1305 * SetupGetLineCountW (SETUPAPI.@)
1307 LONG WINAPI
SetupGetLineCountW( HINF hinf
, PCWSTR section
)
1309 struct inf_file
*file
= hinf
;
1313 for (file
= hinf
; file
; file
= file
->next
)
1315 if ((section_index
= find_section( file
, section
)) == -1) continue;
1316 if (ret
== -1) ret
= 0;
1317 ret
+= file
->sections
[section_index
]->nb_lines
;
1319 TRACE( "(%p,%s) returning %ld\n", hinf
, debugstr_w(section
), ret
);
1320 SetLastError( (ret
== -1) ? ERROR_SECTION_NOT_FOUND
: 0 );
1325 /***********************************************************************
1326 * SetupGetLineByIndexA (SETUPAPI.@)
1328 BOOL WINAPI
SetupGetLineByIndexA( HINF hinf
, PCSTR section
, DWORD index
, INFCONTEXT
*context
)
1330 UNICODE_STRING sectionW
;
1333 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1334 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1337 ret
= SetupGetLineByIndexW( hinf
, sectionW
.Buffer
, index
, context
);
1338 RtlFreeUnicodeString( §ionW
);
1344 /***********************************************************************
1345 * SetupGetLineByIndexW (SETUPAPI.@)
1347 BOOL WINAPI
SetupGetLineByIndexW( HINF hinf
, PCWSTR section
, DWORD index
, INFCONTEXT
*context
)
1349 struct inf_file
*file
= hinf
;
1352 SetLastError( ERROR_SECTION_NOT_FOUND
);
1353 for (file
= hinf
; file
; file
= file
->next
)
1355 if ((section_index
= find_section( file
, section
)) == -1) continue;
1356 SetLastError( ERROR_LINE_NOT_FOUND
);
1357 if (index
< file
->sections
[section_index
]->nb_lines
)
1359 context
->Inf
= hinf
;
1360 context
->CurrentInf
= file
;
1361 context
->Section
= section_index
;
1362 context
->Line
= index
;
1364 TRACE( "(%p,%s): returning %d/%ld\n",
1365 hinf
, debugstr_w(section
), section_index
, index
);
1368 index
-= file
->sections
[section_index
]->nb_lines
;
1370 TRACE( "(%p,%s) not found\n", hinf
, debugstr_w(section
) );
1375 /***********************************************************************
1376 * SetupFindFirstLineA (SETUPAPI.@)
1378 BOOL WINAPI
SetupFindFirstLineA( HINF hinf
, PCSTR section
, PCSTR key
, INFCONTEXT
*context
)
1380 UNICODE_STRING sectionW
, keyW
;
1383 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1385 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1389 if (!key
) ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, NULL
, context
);
1392 if (RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1394 ret
= SetupFindFirstLineW( hinf
, sectionW
.Buffer
, keyW
.Buffer
, context
);
1395 RtlFreeUnicodeString( &keyW
);
1397 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1399 RtlFreeUnicodeString( §ionW
);
1404 /***********************************************************************
1405 * SetupFindFirstLineW (SETUPAPI.@)
1407 BOOL WINAPI
SetupFindFirstLineW( HINF hinf
, PCWSTR section
, PCWSTR key
, INFCONTEXT
*context
)
1409 struct inf_file
*file
;
1412 SetLastError( ERROR_SECTION_NOT_FOUND
);
1413 for (file
= hinf
; file
; file
= file
->next
)
1415 if ((section_index
= find_section( file
, section
)) == -1) continue;
1420 ctx
.CurrentInf
= file
;
1421 ctx
.Section
= section_index
;
1423 return SetupFindNextMatchLineW( &ctx
, key
, context
);
1425 SetLastError( ERROR_LINE_NOT_FOUND
); /* found at least one section */
1426 if (file
->sections
[section_index
]->nb_lines
)
1428 context
->Inf
= hinf
;
1429 context
->CurrentInf
= file
;
1430 context
->Section
= section_index
;
1433 TRACE( "(%p,%s,%s): returning %d/0\n",
1434 hinf
, debugstr_w(section
), debugstr_w(key
), section_index
);
1438 TRACE( "(%p,%s,%s): not found\n", hinf
, debugstr_w(section
), debugstr_w(key
) );
1443 /***********************************************************************
1444 * SetupFindNextLine (SETUPAPI.@)
1446 BOOL WINAPI
SetupFindNextLine( PINFCONTEXT context_in
, PINFCONTEXT context_out
)
1448 struct inf_file
*file
= context_in
->CurrentInf
;
1449 struct section
*section
;
1451 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1453 section
= file
->sections
[context_in
->Section
];
1454 if (context_in
->Line
+1 < section
->nb_lines
)
1456 if (context_out
!= context_in
) *context_out
= *context_in
;
1457 context_out
->Line
++;
1462 /* now search the appended files */
1464 for (file
= file
->next
; file
; file
= file
->next
)
1466 int section_index
= find_section( file
, section
->name
);
1467 if (section_index
== -1) continue;
1468 if (file
->sections
[section_index
]->nb_lines
)
1470 context_out
->Inf
= context_in
->Inf
;
1471 context_out
->CurrentInf
= file
;
1472 context_out
->Section
= section_index
;
1473 context_out
->Line
= 0;
1479 SetLastError( ERROR_LINE_NOT_FOUND
);
1484 /***********************************************************************
1485 * SetupFindNextMatchLineA (SETUPAPI.@)
1487 BOOL WINAPI
SetupFindNextMatchLineA( PINFCONTEXT context_in
, PCSTR key
,
1488 PINFCONTEXT context_out
)
1490 UNICODE_STRING keyW
;
1493 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1495 if (!RtlCreateUnicodeStringFromAsciiz( &keyW
, key
))
1496 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1499 ret
= SetupFindNextMatchLineW( context_in
, keyW
.Buffer
, context_out
);
1500 RtlFreeUnicodeString( &keyW
);
1506 /***********************************************************************
1507 * SetupFindNextMatchLineW (SETUPAPI.@)
1509 BOOL WINAPI
SetupFindNextMatchLineW( PINFCONTEXT context_in
, PCWSTR key
,
1510 PINFCONTEXT context_out
)
1512 struct inf_file
*file
= context_in
->CurrentInf
;
1513 struct section
*section
;
1517 if (!key
) return SetupFindNextLine( context_in
, context_out
);
1519 if (context_in
->Section
>= file
->nb_sections
) goto error
;
1521 section
= file
->sections
[context_in
->Section
];
1523 for (i
= context_in
->Line
+1, line
= §ion
->lines
[i
]; i
< section
->nb_lines
; i
++, line
++)
1525 if (line
->key_field
== -1) continue;
1526 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1528 if (context_out
!= context_in
) *context_out
= *context_in
;
1529 context_out
->Line
= i
;
1531 TRACE( "(%p,%s,%s): returning %d\n",
1532 file
, debugstr_w(section
->name
), debugstr_w(key
), i
);
1537 /* now search the appended files */
1539 for (file
= file
->next
; file
; file
= file
->next
)
1541 int section_index
= find_section( file
, section
->name
);
1542 if (section_index
== -1) continue;
1543 section
= file
->sections
[section_index
];
1544 for (i
= 0, line
= section
->lines
; i
< section
->nb_lines
; i
++, line
++)
1546 if (line
->key_field
== -1) continue;
1547 if (!strcmpiW( key
, file
->fields
[line
->key_field
].text
))
1549 context_out
->Inf
= context_in
->Inf
;
1550 context_out
->CurrentInf
= file
;
1551 context_out
->Section
= section_index
;
1552 context_out
->Line
= i
;
1554 TRACE( "(%p,%s,%s): returning %d/%d\n",
1555 file
, debugstr_w(section
->name
), debugstr_w(key
), section_index
, i
);
1560 TRACE( "(%p,%s,%s): not found\n",
1561 context_in
->CurrentInf
, debugstr_w(section
->name
), debugstr_w(key
) );
1563 SetLastError( ERROR_LINE_NOT_FOUND
);
1568 /***********************************************************************
1569 * SetupGetLineTextW (SETUPAPI.@)
1571 BOOL WINAPI
SetupGetLineTextW( PINFCONTEXT context
, HINF hinf
, PCWSTR section_name
,
1572 PCWSTR key_name
, PWSTR buffer
, DWORD size
, PDWORD required
)
1574 struct inf_file
*file
;
1576 struct field
*field
;
1582 INFCONTEXT new_context
;
1583 if (!SetupFindFirstLineW( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1584 file
= new_context
.CurrentInf
;
1585 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1589 file
= context
->CurrentInf
;
1590 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1592 SetLastError( ERROR_LINE_NOT_FOUND
);
1597 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1598 total
+= PARSER_string_substW( file
, field
->text
, NULL
, 0 ) + 1;
1600 if (required
) *required
= total
;
1605 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1608 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1610 unsigned int len
= PARSER_string_substW( file
, field
->text
, buffer
, size
);
1611 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1619 /***********************************************************************
1620 * SetupGetLineTextA (SETUPAPI.@)
1622 BOOL WINAPI
SetupGetLineTextA( PINFCONTEXT context
, HINF hinf
, PCSTR section_name
,
1623 PCSTR key_name
, PSTR buffer
, DWORD size
, PDWORD required
)
1625 struct inf_file
*file
;
1627 struct field
*field
;
1633 INFCONTEXT new_context
;
1634 if (!SetupFindFirstLineA( hinf
, section_name
, key_name
, &new_context
)) return FALSE
;
1635 file
= new_context
.CurrentInf
;
1636 line
= get_line( file
, new_context
.Section
, new_context
.Line
);
1640 file
= context
->CurrentInf
;
1641 if (!(line
= get_line( file
, context
->Section
, context
->Line
)))
1643 SetLastError( ERROR_LINE_NOT_FOUND
);
1648 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1649 total
+= PARSER_string_substA( file
, field
->text
, NULL
, 0 ) + 1;
1651 if (required
) *required
= total
;
1656 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1659 for (i
= 0, field
= &file
->fields
[line
->first_field
]; i
< line
->nb_fields
; i
++, field
++)
1661 unsigned int len
= PARSER_string_substA( file
, field
->text
, buffer
, size
);
1662 if (i
+1 < line
->nb_fields
) buffer
[len
] = ',';
1670 /***********************************************************************
1671 * SetupGetFieldCount (SETUPAPI.@)
1673 DWORD WINAPI
SetupGetFieldCount( PINFCONTEXT context
)
1675 struct inf_file
*file
= context
->CurrentInf
;
1676 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1678 if (!line
) return 0;
1679 return line
->nb_fields
;
1683 /***********************************************************************
1684 * SetupGetStringFieldA (SETUPAPI.@)
1686 BOOL WINAPI
SetupGetStringFieldA( PINFCONTEXT context
, DWORD index
, PSTR buffer
,
1687 DWORD size
, PDWORD required
)
1689 struct inf_file
*file
= context
->CurrentInf
;
1690 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1694 if (!field
) { SetLastError(ERROR_INVALID_PARAMETER
); return FALSE
; }
1695 len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 );
1696 if (required
) *required
= len
+ 1;
1701 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1704 PARSER_string_substA( file
, field
->text
, buffer
, size
);
1706 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1707 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1708 index
, debugstr_a(buffer
) );
1714 /***********************************************************************
1715 * SetupGetStringFieldW (SETUPAPI.@)
1717 BOOL WINAPI
SetupGetStringFieldW( PINFCONTEXT context
, DWORD index
, PWSTR buffer
,
1718 DWORD size
, PDWORD required
)
1720 struct inf_file
*file
= context
->CurrentInf
;
1721 struct field
*field
= get_field( file
, context
->Section
, context
->Line
, index
);
1725 if (!field
) { SetLastError(ERROR_INVALID_PARAMETER
); return FALSE
; }
1726 len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 );
1727 if (required
) *required
= len
+ 1;
1732 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1735 PARSER_string_substW( file
, field
->text
, buffer
, size
);
1737 TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
1738 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
,
1739 index
, debugstr_w(buffer
) );
1745 /***********************************************************************
1746 * SetupGetIntField (SETUPAPI.@)
1748 BOOL WINAPI
SetupGetIntField( PINFCONTEXT context
, DWORD index
, PINT result
)
1751 char *end
, *buffer
= localbuff
;
1756 if (!SetupGetStringFieldA( context
, index
, localbuff
, sizeof(localbuff
), &required
))
1758 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
1759 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
))) return FALSE
;
1760 if (!SetupGetStringFieldA( context
, index
, buffer
, required
, NULL
)) goto done
;
1762 res
= strtol( buffer
, &end
, 0 );
1763 if (end
!= buffer
&& !*end
)
1768 else SetLastError( ERROR_INVALID_DATA
);
1771 if (buffer
!= localbuff
) HeapFree( GetProcessHeap(), 0, buffer
);
1776 /***********************************************************************
1777 * SetupGetBinaryField (SETUPAPI.@)
1779 BOOL WINAPI
SetupGetBinaryField( PINFCONTEXT context
, DWORD index
, BYTE
*buffer
,
1780 DWORD size
, LPDWORD required
)
1782 struct inf_file
*file
= context
->CurrentInf
;
1783 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1784 struct field
*field
;
1789 SetLastError( ERROR_LINE_NOT_FOUND
);
1792 if (!index
|| index
> line
->nb_fields
)
1794 SetLastError( ERROR_INVALID_PARAMETER
);
1797 index
--; /* fields start at 0 */
1798 if (required
) *required
= line
->nb_fields
- index
;
1799 if (!buffer
) return TRUE
;
1800 if (size
< line
->nb_fields
- index
)
1802 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1805 field
= &file
->fields
[line
->first_field
+ index
];
1806 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1810 for (p
= field
->text
; *p
&& isxdigitW(*p
); p
++)
1812 if ((value
<<= 4) > 255)
1814 SetLastError( ERROR_INVALID_DATA
);
1817 if (*p
<= '9') value
|= (*p
- '0');
1818 else value
|= (tolowerW(*p
) - 'a' + 10);
1820 buffer
[i
- index
] = value
;
1822 if (TRACE_ON(setupapi
))
1824 TRACE( "%p/%p/%d/%d index %ld returning",
1825 context
->Inf
, context
->CurrentInf
, context
->Section
, context
->Line
, index
);
1826 for (i
= index
; i
< line
->nb_fields
; i
++) TRACE( " %02x", buffer
[i
- index
] );
1833 /***********************************************************************
1834 * SetupGetMultiSzFieldA (SETUPAPI.@)
1836 BOOL WINAPI
SetupGetMultiSzFieldA( PINFCONTEXT context
, DWORD index
, PSTR buffer
,
1837 DWORD size
, LPDWORD required
)
1839 struct inf_file
*file
= context
->CurrentInf
;
1840 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1841 struct field
*field
;
1848 SetLastError( ERROR_LINE_NOT_FOUND
);
1851 if (!index
|| index
> line
->nb_fields
)
1853 SetLastError( ERROR_INVALID_PARAMETER
);
1856 index
--; /* fields start at 0 */
1857 field
= &file
->fields
[line
->first_field
+ index
];
1858 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1860 if (!(len
= PARSER_string_substA( file
, field
->text
, NULL
, 0 ))) break;
1864 if (required
) *required
= total
;
1865 if (!buffer
) return TRUE
;
1868 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1871 field
= &file
->fields
[line
->first_field
+ index
];
1872 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1874 if (!(len
= PARSER_string_substA( file
, field
->text
, buffer
, size
))) break;
1877 *buffer
= 0; /* add final null */
1882 /***********************************************************************
1883 * SetupGetMultiSzFieldW (SETUPAPI.@)
1885 BOOL WINAPI
SetupGetMultiSzFieldW( PINFCONTEXT context
, DWORD index
, PWSTR buffer
,
1886 DWORD size
, LPDWORD required
)
1888 struct inf_file
*file
= context
->CurrentInf
;
1889 struct line
*line
= get_line( file
, context
->Section
, context
->Line
);
1890 struct field
*field
;
1897 SetLastError( ERROR_LINE_NOT_FOUND
);
1900 if (!index
|| index
> line
->nb_fields
)
1902 SetLastError( ERROR_INVALID_PARAMETER
);
1905 index
--; /* fields start at 0 */
1906 field
= &file
->fields
[line
->first_field
+ index
];
1907 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1909 if (!(len
= PARSER_string_substW( file
, field
->text
, NULL
, 0 ))) break;
1913 if (required
) *required
= total
;
1914 if (!buffer
) return TRUE
;
1917 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1920 field
= &file
->fields
[line
->first_field
+ index
];
1921 for (i
= index
; i
< line
->nb_fields
; i
++, field
++)
1923 if (!(len
= PARSER_string_substW( file
, field
->text
, buffer
, size
))) break;
1926 *buffer
= 0; /* add final null */
1930 /***********************************************************************
1931 * SetupGetInfInformationW (SETUPAPI.@)
1934 SetupGetInfInformationW(
1936 IN DWORD SearchControl
,
1937 IN PSP_INF_INFORMATION ReturnBuffer
,
1938 IN DWORD ReturnBufferSize
,
1939 IN PDWORD RequiredSize
)
1945 TRACE("%p %lx %p %ld %p\n", InfSpec
, SearchControl
, ReturnBuffer
,
1946 ReturnBufferSize
, RequiredSize
);
1948 if (SearchControl
!= INFINFO_INF_SPEC_IS_HINF
1949 && SearchControl
!= INFINFO_INF_NAME_IS_ABSOLUTE
1950 && SearchControl
!= INFINFO_DEFAULT_SEARCH
1951 && SearchControl
!= INFINFO_REVERSE_DEFAULT_SEARCH
1952 && SearchControl
!= INFINFO_INF_PATH_LIST_SEARCH
)
1954 SetLastError(ERROR_INVALID_PARAMETER
);
1958 if (SearchControl
== INFINFO_INF_SPEC_IS_HINF
)
1959 hInf
= (HINF
)InfSpec
;
1962 /* open .inf file and put its handle to hInf */
1963 FIXME("SearchControl 0x%lx not implemented\n", SearchControl
);
1964 SetLastError(ERROR_GEN_FAILURE
);
1968 /* FIXME: add size of [Version] section */
1969 requiredSize
= sizeof(SP_INF_INFORMATION
);
1971 if (requiredSize
<= ReturnBufferSize
)
1973 ReturnBuffer
->InfStyle
= INF_STYLE_WIN4
; /* FIXME */
1974 ReturnBuffer
->InfCount
= 1; /* FIXME */
1975 /* FIXME: memcpy(ReturnBuffer->VersionData, ...); */
1979 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1982 *RequiredSize
= requiredSize
;
1984 if (SearchControl
!= INFINFO_INF_SPEC_IS_HINF
)
1985 SetupCloseInfFile(hInf
);
1989 /***********************************************************************
1990 * SetupGetInfFileListW (SETUPAPI.@)
1993 SetupGetInfFileListW(
1994 IN PCWSTR DirectoryPath OPTIONAL
,
1996 IN OUT PWSTR ReturnBuffer OPTIONAL
,
1997 IN DWORD ReturnBufferSize OPTIONAL
,
1998 OUT PDWORD RequiredSize OPTIONAL
)
2001 LPWSTR pFileSpecification
, pFileName
;
2002 LPWSTR pBuffer
= ReturnBuffer
;
2003 WIN32_FIND_DATAW wfdFileInfo
;
2004 PVOID Buffer
= NULL
;
2006 DWORD requiredSizeInfo
;
2007 DWORD requiredSize
= 0;
2010 TRACE("%S %lx %p %ld %p\n", DirectoryPath
, InfStyle
,
2011 ReturnBuffer
, ReturnBufferSize
, RequiredSize
);
2013 if (InfStyle
& ~(INF_STYLE_OLDNT
| INF_STYLE_WIN4
))
2015 TRACE("Unknown flags: 0x%08lx\n", InfStyle
& ~(INF_STYLE_OLDNT
| INF_STYLE_WIN4
));
2016 SetLastError(ERROR_INVALID_PARAMETER
);
2022 len
= wcslen(DirectoryPath
);
2023 pFileSpecification
= HeapAlloc(
2024 GetProcessHeap(), 0,
2025 (len
+ MAX_PATH
+ 2) * sizeof(WCHAR
));
2026 if (!pFileSpecification
)
2028 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2031 wcscpy(pFileSpecification
, DirectoryPath
);
2032 if (DirectoryPath
[len
] == '\\')
2034 pFileName
= &pFileSpecification
[len
];
2038 wcscat(pFileSpecification
, BackSlash
);
2039 pFileName
= &pFileSpecification
[len
+ 1];
2044 WCHAR windir
[MAX_PATH
];
2045 if (GetSystemWindowsDirectoryW(windir
, MAX_PATH
) == 0)
2047 len
= wcslen(windir
);
2048 pFileSpecification
= HeapAlloc(
2049 GetProcessHeap(), 0,
2050 (len
+ MAX_PATH
+ 6) * sizeof(WCHAR
));
2051 if (!pFileSpecification
)
2053 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2056 wcscpy(pFileSpecification
, windir
);
2057 if (windir
[len
] != '\\')
2058 wcscat(pFileSpecification
, BackSlash
);
2059 wcscat(pFileSpecification
, InfDirectory
);
2060 pFileName
= &pFileSpecification
[wcslen(pFileSpecification
)];
2062 wcscpy(pFileName
, InfFileSpecification
);
2063 hSearch
= FindFirstFileW(pFileSpecification
, &wfdFileInfo
);
2064 if (hSearch
== INVALID_HANDLE_VALUE
)
2066 HeapFree(GetProcessHeap(), 0, pFileSpecification
);
2075 wcscpy(pFileName
, wfdFileInfo
.cFileName
);
2076 hInf
= SetupOpenInfFileW(
2078 NULL
, /* Inf class */
2080 NULL
/* Error line */);
2081 if (hInf
== INVALID_HANDLE_VALUE
)
2083 if (GetLastError() == ERROR_CLASS_MISMATCH
)
2085 /* InfStyle was not correct. Skip this file */
2088 TRACE("Invalid .inf file %S\n", pFileSpecification
);
2092 ret
= SetupGetInfInformationW(
2094 INFINFO_INF_SPEC_IS_HINF
,
2097 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
2102 Buffer
= HeapAlloc(GetProcessHeap(), 0, requiredSizeInfo
);
2105 SetupCloseInfFile(hInf
);
2107 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2111 ret
= SetupGetInfInformationW(
2113 INFINFO_INF_SPEC_IS_HINF
,
2114 Buffer
, requiredSizeInfo
,
2120 len
= wcslen(wfdFileInfo
.cFileName
) + 1;
2121 requiredSize
+= (DWORD
)(len
* sizeof(WCHAR
));
2122 if (requiredSize
<= ReturnBufferSize
)
2124 wcscpy(pBuffer
, wfdFileInfo
.cFileName
);
2125 pBuffer
= &pBuffer
[len
];
2127 HeapFree(GetProcessHeap(), 0, Buffer
);
2128 SetupCloseInfFile(hInf
);
2130 } while (FindNextFileW(hSearch
, &wfdFileInfo
));
2135 requiredSize
+= sizeof(WCHAR
); /* Final NULL char */
2136 if (requiredSize
<= ReturnBufferSize
)
2140 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2144 *RequiredSize
= requiredSize
;
2147 HeapFree(GetProcessHeap(), 0, pFileSpecification
);
2151 /***********************************************************************
2152 * SetupGetInfFileListA (SETUPAPI.@)
2155 SetupGetInfFileListA(
2156 IN PCSTR DirectoryPath OPTIONAL
,
2158 IN OUT PSTR ReturnBuffer OPTIONAL
,
2159 IN DWORD ReturnBufferSize OPTIONAL
,
2160 OUT PDWORD RequiredSize OPTIONAL
)
2162 PWSTR DirectoryPathW
= NULL
;
2163 PWSTR ReturnBufferW
= NULL
;
2166 TRACE("%s %lx %p %ld %p\n", debugstr_a(DirectoryPath
), InfStyle
,
2167 ReturnBuffer
, ReturnBufferSize
, RequiredSize
);
2169 if (DirectoryPath
!= NULL
)
2171 DirectoryPathW
= MultiByteToUnicode(DirectoryPath
, CP_ACP
);
2172 if (DirectoryPathW
== NULL
) goto Cleanup
;
2175 if (ReturnBuffer
!= NULL
&& ReturnBufferSize
!= 0)
2177 ReturnBufferW
= MyMalloc(ReturnBufferSize
* sizeof(WCHAR
));
2178 if (ReturnBufferW
== NULL
) goto Cleanup
;
2181 ret
= SetupGetInfFileListW(DirectoryPathW
, InfStyle
, ReturnBufferW
, ReturnBufferSize
, RequiredSize
);
2183 if (ret
&& ReturnBufferW
!= NULL
)
2185 ret
= WideCharToMultiByte(CP_ACP
, 0, ReturnBufferW
, -1, ReturnBuffer
, ReturnBufferSize
, NULL
, NULL
) != 0;
2189 if (DirectoryPathW
!= NULL
)
2190 MyFree(DirectoryPathW
);
2191 if (ReturnBufferW
!= NULL
)
2192 MyFree(ReturnBufferW
);
2197 /***********************************************************************
2198 * SetupDiGetINFClassW (SETUPAPI.@)
2201 SetupDiGetINFClassW(
2203 OUT LPGUID ClassGuid
,
2204 OUT PWSTR ClassName
,
2205 IN DWORD ClassNameSize
,
2206 OUT PDWORD RequiredSize OPTIONAL
)
2208 HINF hInf
= INVALID_HANDLE_VALUE
;
2211 TRACE("%S %p %p %ld %p\n", InfName
, ClassGuid
,
2212 ClassName
, ClassNameSize
, RequiredSize
);
2214 /* Open .inf file */
2215 hInf
= SetupOpenInfFileW(InfName
, NULL
, INF_STYLE_WIN4
, NULL
);
2216 if (hInf
== INVALID_HANDLE_VALUE
)
2219 ret
= GetInfClassW(hInf
, ClassGuid
, ClassName
, ClassNameSize
, RequiredSize
);
2222 if (hInf
!= INVALID_HANDLE_VALUE
)
2223 SetupCloseInfFile(hInf
);
2225 TRACE("Returning %d\n", ret
);
2229 /***********************************************************************
2230 * SetupDiGetINFClassA (SETUPAPI.@)
2232 BOOL WINAPI
SetupDiGetINFClassA(
2234 OUT LPGUID ClassGuid
,
2236 IN DWORD ClassNameSize
,
2237 OUT PDWORD RequiredSize OPTIONAL
)
2239 PWSTR InfNameW
= NULL
;
2240 PWSTR ClassNameW
= NULL
;
2243 TRACE("%s %p %p %ld %p\n", debugstr_a(InfName
), ClassGuid
,
2244 ClassName
, ClassNameSize
, RequiredSize
);
2246 if (InfName
!= NULL
)
2248 InfNameW
= MultiByteToUnicode(InfName
, CP_ACP
);
2249 if (InfNameW
== NULL
) goto Cleanup
;
2252 if (ClassName
!= NULL
&& ClassNameSize
!= 0)
2254 ClassNameW
= MyMalloc(ClassNameSize
* sizeof(WCHAR
));
2255 if (ClassNameW
== NULL
) goto Cleanup
;
2258 ret
= SetupDiGetINFClassW(InfNameW
, ClassGuid
, ClassNameW
, ClassNameSize
, RequiredSize
);
2260 if (ret
&& ClassNameW
!= NULL
)
2262 ret
= WideCharToMultiByte(CP_ACP
, 0, ClassNameW
, -1, ClassName
, ClassNameSize
, NULL
, NULL
) != 0;
2266 if (InfNameW
!= NULL
)
2268 if (ClassNameW
!= NULL
)