Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenparser.c
Go to the documentation of this file.
00001 /* 00002 * INF file parsing 00003 * 00004 * Copyright 2002 Alexandre Julliard for CodeWeavers 00005 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org) 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include "setupapi_private.h" 00023 00024 WINE_DEFAULT_DEBUG_CHANNEL(setupapi); 00025 00026 /* Unicode constants */ 00027 static const WCHAR BackSlash[] = {'\\',0}; 00028 static const WCHAR Class[] = {'C','l','a','s','s',0}; 00029 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; 00030 static const WCHAR InfDirectory[] = {'i','n','f','\\',0}; 00031 static const WCHAR InfFileSpecification[] = {'*','.','i','n','f',0}; 00032 00033 #define CONTROL_Z '\x1a' 00034 #define MAX_SECTION_NAME_LEN 255 00035 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ 00036 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ 00037 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) 00038 00039 /* inf file structure definitions */ 00040 00041 struct field 00042 { 00043 const WCHAR *text; /* field text */ 00044 }; 00045 00046 struct line 00047 { 00048 int first_field; /* index of first field in field array */ 00049 int nb_fields; /* number of fields in line */ 00050 int key_field; /* index of field for key or -1 if no key */ 00051 }; 00052 00053 struct section 00054 { 00055 const WCHAR *name; /* section name */ 00056 unsigned int nb_lines; /* number of used lines */ 00057 unsigned int alloc_lines; /* total number of allocated lines in array below */ 00058 struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */ 00059 }; 00060 00061 struct inf_file 00062 { 00063 struct inf_file *next; /* next appended file */ 00064 WCHAR *strings; /* buffer for string data (section names and field values) */ 00065 WCHAR *string_pos; /* position of next available string in buffer */ 00066 unsigned int nb_sections; /* number of used sections */ 00067 unsigned int alloc_sections; /* total number of allocated section pointers */ 00068 struct section **sections; /* section pointers array */ 00069 unsigned int nb_fields; 00070 unsigned int alloc_fields; 00071 struct field *fields; 00072 int strings_section; /* index of [Strings] section or -1 if none */ 00073 WCHAR *filename; /* filename of the INF */ 00074 }; 00075 00076 /* parser definitions */ 00077 00078 enum parser_state 00079 { 00080 LINE_START, /* at beginning of a line */ 00081 SECTION_NAME, /* parsing a section name */ 00082 KEY_NAME, /* parsing a key name */ 00083 VALUE_NAME, /* parsing a value name */ 00084 EOL_BACKSLASH, /* backslash at end of line */ 00085 QUOTES, /* inside quotes */ 00086 LEADING_SPACES, /* leading spaces */ 00087 TRAILING_SPACES, /* trailing spaces */ 00088 COMMENT, /* inside a comment */ 00089 NB_PARSER_STATES 00090 }; 00091 00092 struct parser 00093 { 00094 const WCHAR *start; /* start position of item being parsed */ 00095 const WCHAR *end; /* end of buffer */ 00096 struct inf_file *file; /* file being built */ 00097 enum parser_state state; /* current parser state */ 00098 enum parser_state stack[4]; /* state stack */ 00099 int stack_pos; /* current pos in stack */ 00100 00101 int cur_section; /* index of section being parsed*/ 00102 struct line *line; /* current line */ 00103 unsigned int line_pos; /* current line position in file */ 00104 unsigned int error; /* error code */ 00105 unsigned int token_len; /* current token len */ 00106 WCHAR token[MAX_FIELD_LEN+1]; /* current token */ 00107 }; 00108 00109 typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos ); 00110 00111 /* parser state machine functions */ 00112 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ); 00113 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ); 00114 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ); 00115 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ); 00116 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ); 00117 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ); 00118 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ); 00119 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ); 00120 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ); 00121 00122 static const parser_state_func parser_funcs[NB_PARSER_STATES] = 00123 { 00124 line_start_state, /* LINE_START */ 00125 section_name_state, /* SECTION_NAME */ 00126 key_name_state, /* KEY_NAME */ 00127 value_name_state, /* VALUE_NAME */ 00128 eol_backslash_state, /* EOL_BACKSLASH */ 00129 quotes_state, /* QUOTES */ 00130 leading_spaces_state, /* LEADING_SPACES */ 00131 trailing_spaces_state, /* TRAILING_SPACES */ 00132 comment_state /* COMMENT */ 00133 }; 00134 00135 00136 /* Unicode string constants */ 00137 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; 00138 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0}; 00139 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0}; 00140 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0}; 00141 static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0}; 00142 static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0}; 00143 00144 /* extend an array, allocating more memory if necessary */ 00145 static void *grow_array( void *array, unsigned int *count, size_t elem ) 00146 { 00147 void *new_array; 00148 unsigned int new_count = *count + *count / 2; 00149 if (new_count < 32) new_count = 32; 00150 00151 if (array) 00152 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, array, new_count * elem ); 00153 else 00154 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * elem ); 00155 00156 if (new_array) 00157 *count = new_count; 00158 else 00159 HeapFree( GetProcessHeap(), 0, array ); 00160 return new_array; 00161 } 00162 00163 00164 /* get the directory of the inf file (as counted string, not null-terminated) */ 00165 static const WCHAR *get_inf_dir( const struct inf_file *file, unsigned int *len ) 00166 { 00167 const WCHAR *p = strrchrW( file->filename, '\\' ); 00168 *len = p ? (p + 1 - file->filename) : 0; 00169 return file->filename; 00170 } 00171 00172 00173 /* find a section by name */ 00174 static int find_section( const struct inf_file *file, const WCHAR *name ) 00175 { 00176 unsigned int i; 00177 00178 for (i = 0; i < file->nb_sections; i++) 00179 if (!strcmpiW( name, file->sections[i]->name )) return i; 00180 return -1; 00181 } 00182 00183 00184 /* find a line by name */ 00185 static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name ) 00186 { 00187 struct section *section; 00188 struct line *line; 00189 int i; 00190 00191 if (section_index < 0 || section_index >= file->nb_sections) return NULL; 00192 section = file->sections[section_index]; 00193 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) 00194 { 00195 if (line->key_field == -1) continue; 00196 if (!strcmpiW( name, file->fields[line->key_field].text )) return line; 00197 } 00198 return NULL; 00199 } 00200 00201 00202 /* add a section to the file and return the section index */ 00203 static int add_section( struct inf_file *file, const WCHAR *name ) 00204 { 00205 struct section *section; 00206 00207 if (file->nb_sections >= file->alloc_sections) 00208 { 00209 if (!(file->sections = grow_array( file->sections, &file->alloc_sections, 00210 sizeof(file->sections[0]) ))) return -1; 00211 } 00212 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ))) return -1; 00213 section->name = name; 00214 section->nb_lines = 0; 00215 section->alloc_lines = sizeof(section->lines)/sizeof(section->lines[0]); 00216 file->sections[file->nb_sections] = section; 00217 return file->nb_sections++; 00218 } 00219 00220 00221 /* add a line to a given section */ 00222 static struct line *add_line( struct inf_file *file, int section_index ) 00223 { 00224 struct section *section; 00225 struct line *line; 00226 00227 ASSERT( section_index >= 0 && section_index < file->nb_sections ); 00228 00229 section = file->sections[section_index]; 00230 if (section->nb_lines == section->alloc_lines) /* need to grow the section */ 00231 { 00232 int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line); 00233 if (!(section = HeapReAlloc( GetProcessHeap(), 0, section, size ))) return NULL; 00234 section->alloc_lines *= 2; 00235 file->sections[section_index] = section; 00236 } 00237 line = §ion->lines[section->nb_lines++]; 00238 line->first_field = file->nb_fields; 00239 line->nb_fields = 0; 00240 line->key_field = -1; 00241 return line; 00242 } 00243 00244 00245 /* retrieve a given line from section/line index */ 00246 static inline struct line *get_line( struct inf_file *file, unsigned int section_index, 00247 unsigned int line_index ) 00248 { 00249 struct section *section; 00250 00251 if (section_index >= file->nb_sections) return NULL; 00252 section = file->sections[section_index]; 00253 if (line_index >= section->nb_lines) return NULL; 00254 return §ion->lines[line_index]; 00255 } 00256 00257 00258 /* retrieve a given field from section/line/field index */ 00259 static struct field *get_field( struct inf_file *file, int section_index, int line_index, 00260 int field_index ) 00261 { 00262 struct line *line = get_line( file, section_index, line_index ); 00263 00264 if (!line) return NULL; 00265 if (!field_index) /* get the key */ 00266 { 00267 if (line->key_field == -1) return NULL; 00268 return &file->fields[line->key_field]; 00269 } 00270 field_index--; 00271 if (field_index >= line->nb_fields) return NULL; 00272 return &file->fields[line->first_field + field_index]; 00273 } 00274 00275 00276 /* allocate a new field, growing the array if necessary */ 00277 static struct field *add_field( struct inf_file *file, const WCHAR *text ) 00278 { 00279 struct field *field; 00280 00281 if (file->nb_fields >= file->alloc_fields) 00282 { 00283 if (!(file->fields = grow_array( file->fields, &file->alloc_fields, 00284 sizeof(file->fields[0]) ))) return NULL; 00285 } 00286 field = &file->fields[file->nb_fields++]; 00287 field->text = text; 00288 return field; 00289 } 00290 00291 00292 /* retrieve the string substitution for a directory id */ 00293 static const WCHAR *get_dirid_subst( const struct inf_file *file, int dirid, unsigned int *len ) 00294 { 00295 const WCHAR *ret; 00296 00297 if (dirid == DIRID_SRCPATH) return get_inf_dir( file, len ); 00298 ret = DIRID_get_string( dirid ); 00299 if (ret) *len = strlenW(ret); 00300 return ret; 00301 } 00302 00303 00304 /* retrieve the string substitution for a given string, or NULL if not found */ 00305 /* if found, len is set to the substitution length */ 00306 static const WCHAR *get_string_subst( const struct inf_file *file, const WCHAR *str, unsigned int *len, 00307 BOOL no_trailing_slash ) 00308 { 00309 static const WCHAR percent = '%'; 00310 00311 struct section *strings_section; 00312 struct line *line; 00313 struct field *field; 00314 unsigned int i,j; 00315 int dirid; 00316 WCHAR *dirid_str, *end; 00317 const WCHAR *ret = NULL; 00318 WCHAR StringLangId[13] = {'S','t','r','i','n','g','s','.',0}; 00319 TCHAR Lang[5]; 00320 00321 if (!*len) /* empty string (%%) is replaced by single percent */ 00322 { 00323 *len = 1; 00324 return &percent; 00325 } 00326 if (file->strings_section == -1) goto not_found; 00327 strings_section = file->sections[file->strings_section]; 00328 for (j = 0, line = strings_section->lines; j < strings_section->nb_lines; j++, line++) 00329 { 00330 if (line->key_field == -1) continue; 00331 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; 00332 if (!file->fields[line->key_field].text[*len]) break; 00333 } 00334 if (j == strings_section->nb_lines || !line->nb_fields) goto not_found; 00335 field = &file->fields[line->first_field]; 00336 GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, Lang, sizeof(Lang)/sizeof(TCHAR)); // get the current system locale for translated strings 00337 strcatW(StringLangId, Lang); // append the Language identifier from GetLocaleInfo 00338 // now you have e.g. Strings.0407 for german translations 00339 for (i = 0; i < file->nb_sections; i++) // search in all sections 00340 { 00341 if (!strcmpiW(file->sections[i]->name,StringLangId)) // if the section is a Strings.* section 00342 { 00343 strings_section = file->sections[i]; // select this section for further use 00344 for (j = 0, line = strings_section->lines; j < strings_section->nb_lines; j++, line++) // process all lines in this section 00345 { 00346 if (line->key_field == -1) continue; // if no key then skip 00347 if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; // if wrong key name, then skip 00348 if (!file->fields[line->key_field].text[*len]) // if value exist 00349 { 00350 field = &file->fields[line->first_field]; // then extract value and 00351 break; // no more search necessary 00352 } 00353 } 00354 } 00355 } 00356 *len = strlenW( field->text ); // set length 00357 ret = field->text; // return the english or translated string 00358 return ret; 00359 00360 00361 not_found: /* check for integer id */ 00362 if ((dirid_str = HeapAlloc( GetProcessHeap(), 0, (*len+1) * sizeof(WCHAR) ))) 00363 { 00364 memcpy( dirid_str, str, *len * sizeof(WCHAR) ); 00365 dirid_str[*len] = 0; 00366 dirid = strtolW( dirid_str, &end, 10 ); 00367 if (!*end) ret = get_dirid_subst( file, dirid, len ); 00368 if (no_trailing_slash && ret && *len && ret[*len - 1] == '\\') *len -= 1; 00369 HeapFree( GetProcessHeap(), 0, dirid_str ); 00370 return ret; 00371 } 00372 return NULL; 00373 } 00374 00375 00376 /* do string substitutions on the specified text */ 00377 /* the buffer is assumed to be large enough */ 00378 /* returns necessary length not including terminating null */ 00379 unsigned int PARSER_string_substW( const struct inf_file *file, const WCHAR *text, WCHAR *buffer, 00380 unsigned int size ) 00381 { 00382 const WCHAR *start, *subst, *p; 00383 unsigned int len, total = 0; 00384 int inside = 0; 00385 00386 if (!buffer) size = MAX_STRING_LEN + 1; 00387 for (p = start = text; *p; p++) 00388 { 00389 if (*p != '%') continue; 00390 inside = !inside; 00391 if (inside) /* start of a %xx% string */ 00392 { 00393 len = p - start; 00394 if (len > size - 1) len = size - 1; 00395 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 00396 total += len; 00397 size -= len; 00398 start = p; 00399 } 00400 else /* end of the %xx% string, find substitution */ 00401 { 00402 len = p - start - 1; 00403 subst = get_string_subst( file, start + 1, &len, p[1] == '\\' ); 00404 if (!subst) 00405 { 00406 subst = start; 00407 len = p - start + 1; 00408 } 00409 if (len > size - 1) len = size - 1; 00410 if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) ); 00411 total += len; 00412 size -= len; 00413 start = p + 1; 00414 } 00415 } 00416 00417 if (start != p) /* unfinished string, copy it */ 00418 { 00419 len = p - start; 00420 if (len > size - 1) len = size - 1; 00421 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 00422 total += len; 00423 } 00424 if (buffer && size) buffer[total] = 0; 00425 return total; 00426 } 00427 00428 00429 /* do string substitutions on the specified text */ 00430 /* the buffer is assumed to be large enough */ 00431 /* returns necessary length not including terminating null */ 00432 unsigned int PARSER_string_substA( const struct inf_file *file, const WCHAR *text, char *buffer, 00433 unsigned int size ) 00434 { 00435 WCHAR buffW[MAX_STRING_LEN+1]; 00436 DWORD ret; 00437 00438 unsigned int len = PARSER_string_substW( file, text, buffW, sizeof(buffW)/sizeof(WCHAR) ); 00439 if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) ); 00440 else 00441 { 00442 RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) ); 00443 buffer[ret] = 0; 00444 } 00445 return ret; 00446 } 00447 00448 00449 /* push some string data into the strings buffer */ 00450 static WCHAR *push_string( struct inf_file *file, const WCHAR *string ) 00451 { 00452 WCHAR *ret = file->string_pos; 00453 strcpyW( ret, string ); 00454 file->string_pos += strlenW( ret ) + 1; 00455 return ret; 00456 } 00457 00458 00459 /* push the current state on the parser stack */ 00460 static inline void push_state( struct parser *parser, enum parser_state state ) 00461 { 00462 ASSERT( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) ); 00463 parser->stack[parser->stack_pos++] = state; 00464 } 00465 00466 00467 /* pop the current state */ 00468 static inline void pop_state( struct parser *parser ) 00469 { 00470 ASSERT( parser->stack_pos ); 00471 parser->state = parser->stack[--parser->stack_pos]; 00472 } 00473 00474 00475 /* set the parser state and return the previous one */ 00476 static inline enum parser_state set_state( struct parser *parser, enum parser_state state ) 00477 { 00478 enum parser_state ret = parser->state; 00479 parser->state = state; 00480 return ret; 00481 } 00482 00483 00484 /* check if the pointer points to an end of file */ 00485 static inline int is_eof( const struct parser *parser, const WCHAR *ptr ) 00486 { 00487 return (ptr >= parser->end || *ptr == CONTROL_Z); 00488 } 00489 00490 00491 /* check if the pointer points to an end of line */ 00492 static inline int is_eol( const struct parser *parser, const WCHAR *ptr ) 00493 { 00494 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n'); 00495 } 00496 00497 00498 /* push data from current token start up to pos into the current token */ 00499 static int push_token( struct parser *parser, const WCHAR *pos ) 00500 { 00501 int len = pos - parser->start; 00502 const WCHAR *src = parser->start; 00503 WCHAR *dst = parser->token + parser->token_len; 00504 00505 if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len; 00506 00507 parser->token_len += len; 00508 for ( ; len > 0; len--, dst++, src++) *dst = *src ? *src : ' '; 00509 *dst = 0; 00510 parser->start = pos; 00511 return 0; 00512 } 00513 00514 00515 /* add a section with the current token as name */ 00516 static int add_section_from_token( struct parser *parser ) 00517 { 00518 int section_index; 00519 00520 if (parser->token_len > MAX_SECTION_NAME_LEN) 00521 { 00522 parser->error = ERROR_SECTION_NAME_TOO_LONG; 00523 return -1; 00524 } 00525 if ((section_index = find_section( parser->file, parser->token )) == -1) 00526 { 00527 /* need to create a new one */ 00528 const WCHAR *name = push_string( parser->file, parser->token ); 00529 if ((section_index = add_section( parser->file, name )) == -1) 00530 { 00531 parser->error = ERROR_NOT_ENOUGH_MEMORY; 00532 return -1; 00533 } 00534 } 00535 parser->token_len = 0; 00536 parser->cur_section = section_index; 00537 return section_index; 00538 } 00539 00540 00541 /* add a field containing the current token to the current line */ 00542 static struct field *add_field_from_token( struct parser *parser, int is_key ) 00543 { 00544 struct field *field; 00545 WCHAR *text; 00546 00547 if (!parser->line) /* need to start a new line */ 00548 { 00549 if (parser->cur_section == -1) /* got a line before the first section */ 00550 { 00551 parser->error = ERROR_EXPECTED_SECTION_NAME; 00552 return NULL; 00553 } 00554 if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error; 00555 } 00556 else ASSERT(!is_key); 00557 00558 text = push_string( parser->file, parser->token ); 00559 if ((field = add_field( parser->file, text ))) 00560 { 00561 if (!is_key) parser->line->nb_fields++; 00562 else 00563 { 00564 /* replace first field by key field */ 00565 parser->line->key_field = parser->line->first_field; 00566 parser->line->first_field++; 00567 } 00568 parser->token_len = 0; 00569 return field; 00570 } 00571 error: 00572 parser->error = ERROR_NOT_ENOUGH_MEMORY; 00573 return NULL; 00574 } 00575 00576 00577 /* close the current line and prepare for parsing a new one */ 00578 static void close_current_line( struct parser *parser ) 00579 { 00580 struct line *cur_line = parser->line; 00581 00582 if (cur_line) 00583 { 00584 /* if line has a single field and no key, the field is the key too */ 00585 if (cur_line->nb_fields == 1 && cur_line->key_field == -1) 00586 cur_line->key_field = cur_line->first_field; 00587 } 00588 parser->line = NULL; 00589 } 00590 00591 00592 /* handler for parser LINE_START state */ 00593 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ) 00594 { 00595 const WCHAR *p; 00596 00597 for (p = pos; !is_eof( parser, p ); p++) 00598 { 00599 switch(*p) 00600 { 00601 case '\n': 00602 parser->line_pos++; 00603 close_current_line( parser ); 00604 break; 00605 case ';': 00606 push_state( parser, LINE_START ); 00607 set_state( parser, COMMENT ); 00608 return p + 1; 00609 case '[': 00610 parser->start = p + 1; 00611 set_state( parser, SECTION_NAME ); 00612 return p + 1; 00613 default: 00614 if (!isspaceW(*p)) 00615 { 00616 parser->start = p; 00617 set_state( parser, KEY_NAME ); 00618 return p; 00619 } 00620 break; 00621 } 00622 } 00623 close_current_line( parser ); 00624 return NULL; 00625 } 00626 00627 00628 /* handler for parser SECTION_NAME state */ 00629 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ) 00630 { 00631 const WCHAR *p; 00632 00633 for (p = pos; !is_eol( parser, p ); p++) 00634 { 00635 if (*p == ']') 00636 { 00637 push_token( parser, p ); 00638 if (add_section_from_token( parser ) == -1) return NULL; 00639 push_state( parser, LINE_START ); 00640 set_state( parser, COMMENT ); /* ignore everything else on the line */ 00641 return p + 1; 00642 } 00643 } 00644 parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */ 00645 return NULL; 00646 } 00647 00648 00649 /* handler for parser KEY_NAME state */ 00650 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ) 00651 { 00652 const WCHAR *p, *token_end = parser->start; 00653 00654 for (p = pos; !is_eol( parser, p ); p++) 00655 { 00656 if (*p == ',') break; 00657 switch(*p) 00658 { 00659 00660 case '=': 00661 push_token( parser, token_end ); 00662 if (!add_field_from_token( parser, 1 )) return NULL; 00663 parser->start = p + 1; 00664 push_state( parser, VALUE_NAME ); 00665 set_state( parser, LEADING_SPACES ); 00666 return p + 1; 00667 case ';': 00668 push_token( parser, token_end ); 00669 if (!add_field_from_token( parser, 0 )) return NULL; 00670 push_state( parser, LINE_START ); 00671 set_state( parser, COMMENT ); 00672 return p + 1; 00673 case '"': 00674 push_token( parser, p ); 00675 parser->start = p + 1; 00676 push_state( parser, KEY_NAME ); 00677 set_state( parser, QUOTES ); 00678 return p + 1; 00679 case '\\': 00680 push_token( parser, token_end ); 00681 parser->start = p; 00682 push_state( parser, KEY_NAME ); 00683 set_state( parser, EOL_BACKSLASH ); 00684 return p; 00685 default: 00686 if (!isspaceW(*p)) token_end = p + 1; 00687 else 00688 { 00689 push_token( parser, p ); 00690 push_state( parser, KEY_NAME ); 00691 set_state( parser, TRAILING_SPACES ); 00692 return p; 00693 } 00694 break; 00695 } 00696 } 00697 push_token( parser, token_end ); 00698 set_state( parser, VALUE_NAME ); 00699 return p; 00700 } 00701 00702 00703 /* handler for parser VALUE_NAME state */ 00704 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ) 00705 { 00706 const WCHAR *p, *token_end = parser->start; 00707 00708 for (p = pos; !is_eol( parser, p ); p++) 00709 { 00710 switch(*p) 00711 { 00712 case ';': 00713 push_token( parser, token_end ); 00714 if (!add_field_from_token( parser, 0 )) return NULL; 00715 push_state( parser, LINE_START ); 00716 set_state( parser, COMMENT ); 00717 return p + 1; 00718 case ',': 00719 push_token( parser, token_end ); 00720 if (!add_field_from_token( parser, 0 )) return NULL; 00721 parser->start = p + 1; 00722 push_state( parser, VALUE_NAME ); 00723 set_state( parser, LEADING_SPACES ); 00724 return p + 1; 00725 case '"': 00726 push_token( parser, p ); 00727 parser->start = p + 1; 00728 push_state( parser, VALUE_NAME ); 00729 set_state( parser, QUOTES ); 00730 return p + 1; 00731 case '\\': 00732 push_token( parser, token_end ); 00733 parser->start = p; 00734 push_state( parser, VALUE_NAME ); 00735 set_state( parser, EOL_BACKSLASH ); 00736 return p; 00737 default: 00738 if (!isspaceW(*p)) token_end = p + 1; 00739 else 00740 { 00741 push_token( parser, p ); 00742 push_state( parser, VALUE_NAME ); 00743 set_state( parser, TRAILING_SPACES ); 00744 return p; 00745 } 00746 break; 00747 } 00748 } 00749 push_token( parser, token_end ); 00750 if (!add_field_from_token( parser, 0 )) return NULL; 00751 set_state( parser, LINE_START ); 00752 return p; 00753 } 00754 00755 00756 /* handler for parser EOL_BACKSLASH state */ 00757 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ) 00758 { 00759 const WCHAR *p; 00760 00761 for (p = pos; !is_eof( parser, p ); p++) 00762 { 00763 switch(*p) 00764 { 00765 case '\n': 00766 parser->line_pos++; 00767 parser->start = p + 1; 00768 set_state( parser, LEADING_SPACES ); 00769 return p + 1; 00770 case '\\': 00771 continue; 00772 case ';': 00773 push_state( parser, EOL_BACKSLASH ); 00774 set_state( parser, COMMENT ); 00775 return p + 1; 00776 default: 00777 if (isspaceW(*p)) continue; 00778 push_token( parser, p ); 00779 pop_state( parser ); 00780 return p; 00781 } 00782 } 00783 parser->start = p; 00784 pop_state( parser ); 00785 return p; 00786 } 00787 00788 00789 /* handler for parser QUOTES state */ 00790 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ) 00791 { 00792 const WCHAR *p, *token_end = parser->start; 00793 00794 for (p = pos; !is_eol( parser, p ); p++) 00795 { 00796 if (*p == '"') 00797 { 00798 if (p+1 < parser->end && p[1] == '"') /* double quotes */ 00799 { 00800 push_token( parser, p + 1 ); 00801 parser->start = token_end = p + 2; 00802 p++; 00803 } 00804 else /* end of quotes */ 00805 { 00806 push_token( parser, p ); 00807 parser->start = p + 1; 00808 pop_state( parser ); 00809 return p + 1; 00810 } 00811 } 00812 } 00813 push_token( parser, p ); 00814 pop_state( parser ); 00815 return p; 00816 } 00817 00818 00819 /* handler for parser LEADING_SPACES state */ 00820 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ) 00821 { 00822 const WCHAR *p; 00823 00824 for (p = pos; !is_eol( parser, p ); p++) 00825 { 00826 if (*p == '\\') 00827 { 00828 parser->start = p; 00829 set_state( parser, EOL_BACKSLASH ); 00830 return p; 00831 } 00832 if (!isspaceW(*p)) break; 00833 } 00834 parser->start = p; 00835 pop_state( parser ); 00836 return p; 00837 } 00838 00839 00840 /* handler for parser TRAILING_SPACES state */ 00841 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ) 00842 { 00843 const WCHAR *p; 00844 00845 for (p = pos; !is_eol( parser, p ); p++) 00846 { 00847 if (*p == '\\') 00848 { 00849 set_state( parser, EOL_BACKSLASH ); 00850 return p; 00851 } 00852 if (!isspaceW(*p)) break; 00853 } 00854 pop_state( parser ); 00855 return p; 00856 } 00857 00858 00859 /* handler for parser COMMENT state */ 00860 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ) 00861 { 00862 const WCHAR *p = pos; 00863 00864 while (!is_eol( parser, p )) p++; 00865 pop_state( parser ); 00866 return p; 00867 } 00868 00869 00870 /* parse a complete buffer */ 00871 static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end, 00872 UINT *error_line ) 00873 { 00874 static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0}; 00875 00876 struct parser parser; 00877 const WCHAR *pos = buffer; 00878 00879 parser.start = buffer; 00880 parser.end = end; 00881 parser.file = file; 00882 parser.line = NULL; 00883 parser.state = LINE_START; 00884 parser.stack_pos = 0; 00885 parser.cur_section = -1; 00886 parser.line_pos = 1; 00887 parser.error = 0; 00888 parser.token_len = 0; 00889 00890 /* parser main loop */ 00891 while (pos) pos = (parser_funcs[parser.state])( &parser, pos ); 00892 00893 /* trim excess buffer space */ 00894 if (file->alloc_sections > file->nb_sections) 00895 { 00896 file->sections = HeapReAlloc( GetProcessHeap(), 0, file->sections, 00897 file->nb_sections * sizeof(file->sections[0]) ); 00898 file->alloc_sections = file->nb_sections; 00899 } 00900 if (file->alloc_fields > file->nb_fields) 00901 { 00902 file->fields = HeapReAlloc( GetProcessHeap(), 0, file->fields, 00903 file->nb_fields * sizeof(file->fields[0]) ); 00904 file->alloc_fields = file->nb_fields; 00905 } 00906 file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings, 00907 (file->string_pos - file->strings) * sizeof(WCHAR) ); 00908 00909 if (parser.error) 00910 { 00911 if (error_line) *error_line = parser.line_pos; 00912 return parser.error; 00913 } 00914 00915 /* find the [strings] section */ 00916 file->strings_section = find_section( file, Strings ); 00917 return 0; 00918 } 00919 00920 00921 /* append a child INF file to its parent list, in a thread-safe manner */ 00922 static void append_inf_file( struct inf_file *parent, struct inf_file *child ) 00923 { 00924 struct inf_file **ppnext = &parent->next; 00925 child->next = NULL; 00926 00927 for (;;) 00928 { 00929 struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL ); 00930 if (!next) return; 00931 ppnext = &next->next; 00932 } 00933 } 00934 00935 00936 /*********************************************************************** 00937 * parse_file 00938 * 00939 * parse an INF file. 00940 */ 00941 static struct inf_file *parse_file( HANDLE handle, UINT *error_line, DWORD style ) 00942 { 00943 void *buffer; 00944 DWORD err = 0; 00945 struct inf_file *file; 00946 00947 DWORD size = GetFileSize( handle, NULL ); 00948 HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL ); 00949 if (!mapping) return NULL; 00950 buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size ); 00951 NtClose( mapping ); 00952 if (!buffer) return NULL; 00953 00954 if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) ))) 00955 { 00956 err = ERROR_NOT_ENOUGH_MEMORY; 00957 goto done; 00958 } 00959 00960 /* we won't need more strings space than the size of the file, 00961 * so we can preallocate it here 00962 */ 00963 if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) 00964 { 00965 err = ERROR_NOT_ENOUGH_MEMORY; 00966 goto done; 00967 } 00968 file->string_pos = file->strings; 00969 file->strings_section = -1; 00970 00971 if (!RtlIsTextUnicode( buffer, size, NULL )) 00972 { 00973 static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; 00974 WCHAR *new_buff; 00975 UINT codepage = CP_ACP; 00976 UINT offset = 0; 00977 00978 if (size > sizeof(utf8_bom) && !memcmp( buffer, utf8_bom, sizeof(utf8_bom) )) 00979 { 00980 codepage = CP_UTF8; 00981 offset = sizeof(utf8_bom); 00982 } 00983 00984 if ((new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) 00985 { 00986 DWORD len = MultiByteToWideChar( codepage, 0, (char *)buffer + offset, 00987 size - offset, new_buff, size ); 00988 err = parse_buffer( file, new_buff, new_buff + len, error_line ); 00989 HeapFree( GetProcessHeap(), 0, new_buff ); 00990 } 00991 } 00992 else 00993 { 00994 WCHAR *new_buff = (WCHAR *)buffer; 00995 /* UCS-16 files should start with the Unicode BOM; we should skip it */ 00996 if (*new_buff == 0xfeff) 00997 new_buff++; 00998 err = parse_buffer( file, new_buff, (WCHAR *)((char *)buffer + size), error_line ); 00999 } 01000 01001 if (!err) /* now check signature */ 01002 { 01003 int version_index = find_section( file, Version ); 01004 if (version_index != -1) 01005 { 01006 struct line *line = find_line( file, version_index, Signature ); 01007 if (line && line->nb_fields > 0) 01008 { 01009 struct field *field = file->fields + line->first_field; 01010 if (!strcmpiW( field->text, Chicago )) goto done; 01011 if (!strcmpiW( field->text, WindowsNT )) goto done; 01012 if (!strcmpiW( field->text, Windows95 )) goto done; 01013 } 01014 } 01015 if (error_line) *error_line = 0; 01016 if (style & INF_STYLE_WIN4) err = ERROR_WRONG_INF_STYLE; 01017 } 01018 01019 done: 01020 UnmapViewOfFile( buffer ); 01021 if (err) 01022 { 01023 HeapFree( GetProcessHeap(), 0, file ); 01024 SetLastError( err ); 01025 file = NULL; 01026 } 01027 return file; 01028 } 01029 01030 01031 /*********************************************************************** 01032 * PARSER_get_inf_filename 01033 * 01034 * Retrieve the filename of an inf file. 01035 */ 01036 const WCHAR *PARSER_get_inf_filename( HINF hinf ) 01037 { 01038 struct inf_file *file = hinf; 01039 return file->filename; 01040 } 01041 01042 01043 /*********************************************************************** 01044 * PARSER_get_src_root 01045 * 01046 * Retrieve the source directory of an inf file. 01047 */ 01048 WCHAR *PARSER_get_src_root( HINF hinf ) 01049 { 01050 unsigned int len; 01051 const WCHAR *dir = get_inf_dir( hinf, &len ); 01052 WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ); 01053 if (ret) 01054 { 01055 memcpy( ret, dir, len * sizeof(WCHAR) ); 01056 ret[len] = 0; 01057 } 01058 return ret; 01059 } 01060 01061 01062 /*********************************************************************** 01063 * PARSER_get_dest_dir 01064 * 01065 * retrieve a destination dir of the form "dirid,relative_path" in the given entry. 01066 * returned buffer must be freed by caller. 01067 */ 01068 WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) 01069 { 01070 const WCHAR *dir; 01071 WCHAR *ptr, *ret; 01072 INT dirid; 01073 unsigned int len1; 01074 DWORD len2; 01075 01076 if (!SetupGetIntField( context, 1, &dirid )) return NULL; 01077 if (!(dir = get_dirid_subst( context->Inf, dirid, &len1 ))) return NULL; 01078 if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0; 01079 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2+1) * sizeof(WCHAR) ))) return NULL; 01080 memcpy( ret, dir, len1 * sizeof(WCHAR) ); 01081 ptr = ret + len1; 01082 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\'; 01083 if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0; 01084 return ret; 01085 } 01086 01087 01088 /*********************************************************************** 01089 * SetupOpenInfFileA (SETUPAPI.@) 01090 */ 01091 HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error ) 01092 { 01093 UNICODE_STRING nameW, classW; 01094 HINF ret = INVALID_HANDLE_VALUE; 01095 01096 classW.Buffer = NULL; 01097 if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class )) 01098 { 01099 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01100 return ret; 01101 } 01102 if (RtlCreateUnicodeStringFromAsciiz( &nameW, name )) 01103 { 01104 ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error ); 01105 RtlFreeUnicodeString( &nameW ); 01106 } 01107 RtlFreeUnicodeString( &classW ); 01108 return ret; 01109 } 01110 01111 01112 static BOOL 01113 PARSER_GetInfClassW( 01114 IN HINF hInf, 01115 OUT LPGUID ClassGuid, 01116 OUT PWSTR ClassName, 01117 IN DWORD ClassNameSize, 01118 OUT PDWORD RequiredSize OPTIONAL) 01119 { 01120 DWORD requiredSize; 01121 WCHAR guidW[MAX_GUID_STRING_LEN + 1]; 01122 BOOL ret = FALSE; 01123 01124 /* Read class Guid */ 01125 if (!SetupGetLineTextW(NULL, hInf, Version, ClassGUID, guidW, sizeof(guidW), NULL)) 01126 goto cleanup; 01127 guidW[37] = '\0'; /* Replace the } by a NULL character */ 01128 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK) 01129 goto cleanup; 01130 01131 /* Read class name */ 01132 ret = SetupGetLineTextW(NULL, hInf, Version, Class, ClassName, ClassNameSize, &requiredSize); 01133 if (ret && ClassName == NULL && ClassNameSize == 0) 01134 { 01135 if (RequiredSize) 01136 *RequiredSize = requiredSize; 01137 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01138 ret = FALSE; 01139 goto cleanup; 01140 } 01141 if (!ret) 01142 { 01143 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 01144 { 01145 if (RequiredSize) 01146 *RequiredSize = requiredSize; 01147 goto cleanup; 01148 } 01149 else if (!SetupDiClassNameFromGuidW(ClassGuid, ClassName, ClassNameSize, &requiredSize)) 01150 { 01151 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 01152 { 01153 if (RequiredSize) 01154 *RequiredSize = requiredSize; 01155 goto cleanup; 01156 } 01157 /* Return a NULL class name */ 01158 if (RequiredSize) 01159 *RequiredSize = 1; 01160 if (ClassNameSize < 1) 01161 { 01162 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01163 goto cleanup; 01164 } 01165 memcpy(ClassGuid, &GUID_NULL, sizeof(GUID)); 01166 *ClassName = UNICODE_NULL; 01167 } 01168 } 01169 01170 ret = TRUE; 01171 01172 cleanup: 01173 TRACE("Returning %d\n", ret); 01174 return ret; 01175 } 01176 01177 01178 /*********************************************************************** 01179 * SetupOpenInfFileW (SETUPAPI.@) 01180 */ 01181 HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error ) 01182 { 01183 struct inf_file *file = NULL; 01184 HANDLE handle; 01185 WCHAR *path, *p; 01186 UINT len; 01187 01188 TRACE("%s %s %lx %p\n", debugstr_w(name), debugstr_w(class), style, error); 01189 01190 if (style & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)) 01191 { 01192 SetLastError(ERROR_INVALID_PARAMETER); 01193 return (HINF)INVALID_HANDLE_VALUE; 01194 } 01195 01196 if (strchrW( name, '\\' ) || strchrW( name, '/' )) 01197 { 01198 if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return INVALID_HANDLE_VALUE; 01199 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 01200 { 01201 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01202 return INVALID_HANDLE_VALUE; 01203 } 01204 GetFullPathNameW( name, len, path, NULL ); 01205 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 01206 } 01207 else /* try Windows directory */ 01208 { 01209 static const WCHAR Inf[] = {'\\','i','n','f','\\',0}; 01210 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0}; 01211 01212 len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12; 01213 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 01214 { 01215 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01216 return INVALID_HANDLE_VALUE; 01217 } 01218 GetWindowsDirectoryW( path, len ); 01219 p = path + strlenW(path); 01220 strcpyW( p, Inf ); 01221 strcatW( p, name ); 01222 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 01223 if (handle == INVALID_HANDLE_VALUE) 01224 { 01225 strcpyW( p, System32 ); 01226 strcatW( p, name ); 01227 handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); 01228 } 01229 } 01230 01231 if (handle != INVALID_HANDLE_VALUE) 01232 { 01233 file = parse_file( handle, error, style ); 01234 CloseHandle( handle ); 01235 } 01236 if (!file) 01237 { 01238 HeapFree( GetProcessHeap(), 0, path ); 01239 return INVALID_HANDLE_VALUE; 01240 } 01241 TRACE( "%s -> %p\n", debugstr_w(path), file ); 01242 file->filename = path; 01243 01244 if (class) 01245 { 01246 GUID ClassGuid; 01247 LPWSTR ClassName = HeapAlloc(GetProcessHeap(), 0, (strlenW(class) + 1) * sizeof(WCHAR)); 01248 if (!ClassName) 01249 { 01250 /* Not enough memory */ 01251 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01252 SetupCloseInfFile((HINF)file); 01253 return INVALID_HANDLE_VALUE; 01254 } 01255 else if (!PARSER_GetInfClassW((HINF)file, &ClassGuid, ClassName, strlenW(class) + 1, NULL)) 01256 { 01257 /* Unable to get class name in .inf file */ 01258 HeapFree(GetProcessHeap(), 0, ClassName); 01259 SetLastError(ERROR_CLASS_MISMATCH); 01260 SetupCloseInfFile((HINF)file); 01261 return INVALID_HANDLE_VALUE; 01262 } 01263 else if (strcmpW(class, ClassName) != 0) 01264 { 01265 /* Provided name name is not the expected one */ 01266 HeapFree(GetProcessHeap(), 0, ClassName); 01267 SetLastError(ERROR_CLASS_MISMATCH); 01268 SetupCloseInfFile((HINF)file); 01269 return INVALID_HANDLE_VALUE; 01270 } 01271 HeapFree(GetProcessHeap(), 0, ClassName); 01272 } 01273 01274 SetLastError( 0 ); 01275 return (HINF)file; 01276 } 01277 01278 01279 /*********************************************************************** 01280 * SetupOpenAppendInfFileA (SETUPAPI.@) 01281 */ 01282 BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error ) 01283 { 01284 HINF child_hinf; 01285 01286 if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error ); 01287 child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error ); 01288 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 01289 append_inf_file( parent_hinf, child_hinf ); 01290 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf ); 01291 return TRUE; 01292 } 01293 01294 01295 /*********************************************************************** 01296 * SetupOpenAppendInfFileW (SETUPAPI.@) 01297 */ 01298 BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error ) 01299 { 01300 HINF child_hinf; 01301 01302 if (!name) 01303 { 01304 INFCONTEXT context; 01305 WCHAR filename[MAX_PATH]; 01306 int idx = 1; 01307 01308 if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE; 01309 while (SetupGetStringFieldW( &context, idx++, filename, 01310 sizeof(filename)/sizeof(WCHAR), NULL )) 01311 { 01312 child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error ); 01313 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 01314 append_inf_file( parent_hinf, child_hinf ); 01315 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf ); 01316 } 01317 return TRUE; 01318 } 01319 child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error ); 01320 if (child_hinf == INVALID_HANDLE_VALUE) return FALSE; 01321 append_inf_file( parent_hinf, child_hinf ); 01322 TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf ); 01323 return TRUE; 01324 } 01325 01326 01327 /*********************************************************************** 01328 * SetupOpenMasterInf (SETUPAPI.@) 01329 */ 01330 HINF WINAPI SetupOpenMasterInf( VOID ) 01331 { 01332 static const WCHAR Layout[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0}; 01333 WCHAR Buffer[MAX_PATH]; 01334 01335 GetWindowsDirectoryW( Buffer, MAX_PATH ); 01336 strcatW( Buffer, Layout ); 01337 return SetupOpenInfFileW( Buffer, NULL, INF_STYLE_WIN4, NULL); 01338 } 01339 01340 01341 01342 /*********************************************************************** 01343 * SetupCloseInfFile (SETUPAPI.@) 01344 */ 01345 void WINAPI SetupCloseInfFile( HINF hinf ) 01346 { 01347 struct inf_file *file = hinf; 01348 unsigned int i; 01349 01350 if (!hinf || (hinf == INVALID_HANDLE_VALUE)) return; 01351 01352 for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] ); 01353 HeapFree( GetProcessHeap(), 0, file->filename ); 01354 HeapFree( GetProcessHeap(), 0, file->sections ); 01355 HeapFree( GetProcessHeap(), 0, file->fields ); 01356 HeapFree( GetProcessHeap(), 0, file->strings ); 01357 HeapFree( GetProcessHeap(), 0, file ); 01358 } 01359 01360 01361 /*********************************************************************** 01362 * SetupEnumInfSectionsA (SETUPAPI.@) 01363 */ 01364 BOOL WINAPI SetupEnumInfSectionsA( HINF hinf, UINT index, PSTR buffer, DWORD size, DWORD *need ) 01365 { 01366 struct inf_file *file = hinf; 01367 01368 for (file = hinf; file; file = file->next) 01369 { 01370 if (index < file->nb_sections) 01371 { 01372 DWORD len = WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1, 01373 NULL, 0, NULL, NULL ); 01374 if (need) *need = len; 01375 if (!buffer) 01376 { 01377 if (!size) return TRUE; 01378 SetLastError( ERROR_INVALID_USER_BUFFER ); 01379 return FALSE; 01380 } 01381 if (len > size) 01382 { 01383 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01384 return FALSE; 01385 } 01386 WideCharToMultiByte( CP_ACP, 0, file->sections[index]->name, -1, buffer, size, NULL, NULL ); 01387 return TRUE; 01388 } 01389 index -= file->nb_sections; 01390 } 01391 SetLastError( ERROR_NO_MORE_ITEMS ); 01392 return FALSE; 01393 } 01394 01395 01396 /*********************************************************************** 01397 * SetupEnumInfSectionsW (SETUPAPI.@) 01398 */ 01399 BOOL WINAPI SetupEnumInfSectionsW( HINF hinf, UINT index, PWSTR buffer, DWORD size, DWORD *need ) 01400 { 01401 struct inf_file *file = hinf; 01402 01403 for (file = hinf; file; file = file->next) 01404 { 01405 if (index < file->nb_sections) 01406 { 01407 DWORD len = strlenW( file->sections[index]->name ) + 1; 01408 if (need) *need = len; 01409 if (!buffer) 01410 { 01411 if (!size) return TRUE; 01412 SetLastError( ERROR_INVALID_USER_BUFFER ); 01413 return FALSE; 01414 } 01415 if (len > size) 01416 { 01417 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01418 return FALSE; 01419 } 01420 memcpy( buffer, file->sections[index]->name, len * sizeof(WCHAR) ); 01421 return TRUE; 01422 } 01423 index -= file->nb_sections; 01424 } 01425 SetLastError( ERROR_NO_MORE_ITEMS ); 01426 return FALSE; 01427 } 01428 01429 01430 /*********************************************************************** 01431 * SetupGetLineCountA (SETUPAPI.@) 01432 */ 01433 LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name ) 01434 { 01435 UNICODE_STRING sectionW; 01436 LONG ret = -1; 01437 01438 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, name )) 01439 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01440 else 01441 { 01442 ret = SetupGetLineCountW( hinf, sectionW.Buffer ); 01443 RtlFreeUnicodeString( §ionW ); 01444 } 01445 return ret; 01446 } 01447 01448 01449 /*********************************************************************** 01450 * SetupGetLineCountW (SETUPAPI.@) 01451 */ 01452 LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section ) 01453 { 01454 struct inf_file *file = hinf; 01455 int section_index; 01456 LONG ret = -1; 01457 01458 for (file = hinf; file; file = file->next) 01459 { 01460 if ((section_index = find_section( file, section )) == -1) continue; 01461 if (ret == -1) ret = 0; 01462 ret += file->sections[section_index]->nb_lines; 01463 } 01464 TRACE( "(%p,%s) returning %d\n", hinf, debugstr_w(section), ret ); 01465 SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 ); 01466 return ret; 01467 } 01468 01469 01470 /*********************************************************************** 01471 * SetupGetLineByIndexA (SETUPAPI.@) 01472 */ 01473 BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context ) 01474 { 01475 UNICODE_STRING sectionW; 01476 BOOL ret = FALSE; 01477 01478 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 01479 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01480 else 01481 { 01482 ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context ); 01483 RtlFreeUnicodeString( §ionW ); 01484 } 01485 return ret; 01486 } 01487 01488 01489 /*********************************************************************** 01490 * SetupGetLineByIndexW (SETUPAPI.@) 01491 */ 01492 BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context ) 01493 { 01494 struct inf_file *file = hinf; 01495 int section_index; 01496 01497 for (file = hinf; file; file = file->next) 01498 { 01499 if ((section_index = find_section( file, section )) == -1) continue; 01500 if (index < file->sections[section_index]->nb_lines) 01501 { 01502 context->Inf = hinf; 01503 context->CurrentInf = file; 01504 context->Section = section_index; 01505 context->Line = index; 01506 SetLastError( 0 ); 01507 TRACE( "(%p,%s): returning %d/%d\n", 01508 hinf, debugstr_w(section), section_index, index ); 01509 return TRUE; 01510 } 01511 index -= file->sections[section_index]->nb_lines; 01512 } 01513 TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) ); 01514 SetLastError( ERROR_LINE_NOT_FOUND ); 01515 return FALSE; 01516 } 01517 01518 01519 /*********************************************************************** 01520 * SetupFindFirstLineA (SETUPAPI.@) 01521 */ 01522 BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context ) 01523 { 01524 UNICODE_STRING sectionW, keyW; 01525 BOOL ret = FALSE; 01526 01527 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 01528 { 01529 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01530 return FALSE; 01531 } 01532 01533 if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context ); 01534 else 01535 { 01536 if (RtlCreateUnicodeStringFromAsciiz( &keyW, key )) 01537 { 01538 ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context ); 01539 RtlFreeUnicodeString( &keyW ); 01540 } 01541 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01542 } 01543 RtlFreeUnicodeString( §ionW ); 01544 return ret; 01545 } 01546 01547 01548 /*********************************************************************** 01549 * SetupFindFirstLineW (SETUPAPI.@) 01550 */ 01551 BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context ) 01552 { 01553 struct inf_file *file; 01554 int section_index; 01555 01556 for (file = hinf; file; file = file->next) 01557 { 01558 if ((section_index = find_section( file, section )) == -1) continue; 01559 if (key) 01560 { 01561 INFCONTEXT ctx; 01562 ctx.Inf = hinf; 01563 ctx.CurrentInf = file; 01564 ctx.Section = section_index; 01565 ctx.Line = -1; 01566 return SetupFindNextMatchLineW( &ctx, key, context ); 01567 } 01568 if (file->sections[section_index]->nb_lines) 01569 { 01570 context->Inf = hinf; 01571 context->CurrentInf = file; 01572 context->Section = section_index; 01573 context->Line = 0; 01574 SetLastError( 0 ); 01575 TRACE( "(%p,%s,%s): returning %d/0\n", 01576 hinf, debugstr_w(section), debugstr_w(key), section_index ); 01577 return TRUE; 01578 } 01579 } 01580 TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) ); 01581 SetLastError( ERROR_LINE_NOT_FOUND ); 01582 return FALSE; 01583 } 01584 01585 01586 /*********************************************************************** 01587 * SetupFindNextLine (SETUPAPI.@) 01588 */ 01589 BOOL WINAPI SetupFindNextLine( PINFCONTEXT context_in, PINFCONTEXT context_out ) 01590 { 01591 struct inf_file *file = context_in->CurrentInf; 01592 struct section *section; 01593 01594 if (context_in->Section >= file->nb_sections) goto error; 01595 01596 section = file->sections[context_in->Section]; 01597 if (context_in->Line+1 < section->nb_lines) 01598 { 01599 if (context_out != context_in) *context_out = *context_in; 01600 context_out->Line++; 01601 SetLastError( 0 ); 01602 return TRUE; 01603 } 01604 01605 /* now search the appended files */ 01606 01607 for (file = file->next; file; file = file->next) 01608 { 01609 int section_index = find_section( file, section->name ); 01610 if (section_index == -1) continue; 01611 if (file->sections[section_index]->nb_lines) 01612 { 01613 context_out->Inf = context_in->Inf; 01614 context_out->CurrentInf = file; 01615 context_out->Section = section_index; 01616 context_out->Line = 0; 01617 SetLastError( 0 ); 01618 return TRUE; 01619 } 01620 } 01621 error: 01622 SetLastError( ERROR_LINE_NOT_FOUND ); 01623 return FALSE; 01624 } 01625 01626 01627 /*********************************************************************** 01628 * SetupFindNextMatchLineA (SETUPAPI.@) 01629 */ 01630 BOOL WINAPI SetupFindNextMatchLineA( PINFCONTEXT context_in, PCSTR key, 01631 PINFCONTEXT context_out ) 01632 { 01633 UNICODE_STRING keyW; 01634 BOOL ret = FALSE; 01635 01636 if (!key) return SetupFindNextLine( context_in, context_out ); 01637 01638 if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key )) 01639 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 01640 else 01641 { 01642 ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out ); 01643 RtlFreeUnicodeString( &keyW ); 01644 } 01645 return ret; 01646 } 01647 01648 01649 /*********************************************************************** 01650 * SetupFindNextMatchLineW (SETUPAPI.@) 01651 */ 01652 BOOL WINAPI SetupFindNextMatchLineW( PINFCONTEXT context_in, PCWSTR key, 01653 PINFCONTEXT context_out ) 01654 { 01655 struct inf_file *file = context_in->CurrentInf; 01656 struct section *section; 01657 struct line *line; 01658 unsigned int i; 01659 01660 if (!key) return SetupFindNextLine( context_in, context_out ); 01661 01662 if (context_in->Section >= file->nb_sections) goto error; 01663 01664 section = file->sections[context_in->Section]; 01665 01666 for (i = context_in->Line+1, line = §ion->lines[i]; i < section->nb_lines; i++, line++) 01667 { 01668 if (line->key_field == -1) continue; 01669 if (!strcmpiW( key, file->fields[line->key_field].text )) 01670 { 01671 if (context_out != context_in) *context_out = *context_in; 01672 context_out->Line = i; 01673 SetLastError( 0 ); 01674 TRACE( "(%p,%s,%s): returning %d\n", 01675 file, debugstr_w(section->name), debugstr_w(key), i ); 01676 return TRUE; 01677 } 01678 } 01679 01680 /* now search the appended files */ 01681 01682 for (file = file->next; file; file = file->next) 01683 { 01684 int section_index = find_section( file, section->name ); 01685 if (section_index == -1) continue; 01686 section = file->sections[section_index]; 01687 for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) 01688 { 01689 if (line->key_field == -1) continue; 01690 if (!strcmpiW( key, file->fields[line->key_field].text )) 01691 { 01692 context_out->Inf = context_in->Inf; 01693 context_out->CurrentInf = file; 01694 context_out->Section = section_index; 01695 context_out->Line = i; 01696 SetLastError( 0 ); 01697 TRACE( "(%p,%s,%s): returning %d/%d\n", 01698 file, debugstr_w(section->name), debugstr_w(key), section_index, i ); 01699 return TRUE; 01700 } 01701 } 01702 } 01703 TRACE( "(%p,%s,%s): not found\n", 01704 context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) ); 01705 error: 01706 SetLastError( ERROR_LINE_NOT_FOUND ); 01707 return FALSE; 01708 } 01709 01710 01711 /*********************************************************************** 01712 * SetupGetLineTextW (SETUPAPI.@) 01713 */ 01714 BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_name, 01715 PCWSTR key_name, PWSTR buffer, DWORD size, PDWORD required ) 01716 { 01717 struct inf_file *file; 01718 struct line *line; 01719 struct field *field; 01720 int i; 01721 DWORD total = 0; 01722 01723 if (!context) 01724 { 01725 INFCONTEXT new_context; 01726 if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE; 01727 file = new_context.CurrentInf; 01728 line = get_line( file, new_context.Section, new_context.Line ); 01729 } 01730 else 01731 { 01732 file = context->CurrentInf; 01733 if (!(line = get_line( file, context->Section, context->Line ))) 01734 { 01735 SetLastError( ERROR_LINE_NOT_FOUND ); 01736 return FALSE; 01737 } 01738 } 01739 01740 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 01741 total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1; 01742 01743 if (required) *required = total; 01744 if (buffer) 01745 { 01746 if (total > size) 01747 { 01748 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01749 return FALSE; 01750 } 01751 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 01752 { 01753 unsigned int len = PARSER_string_substW( file, field->text, buffer, size ); 01754 if (i+1 < line->nb_fields) buffer[len] = ','; 01755 buffer += len + 1; 01756 } 01757 } 01758 return TRUE; 01759 } 01760 01761 01762 /*********************************************************************** 01763 * SetupGetLineTextA (SETUPAPI.@) 01764 */ 01765 BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_name, 01766 PCSTR key_name, PSTR buffer, DWORD size, PDWORD required ) 01767 { 01768 struct inf_file *file; 01769 struct line *line; 01770 struct field *field; 01771 int i; 01772 DWORD total = 0; 01773 01774 if (!context) 01775 { 01776 INFCONTEXT new_context; 01777 if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE; 01778 file = new_context.CurrentInf; 01779 line = get_line( file, new_context.Section, new_context.Line ); 01780 } 01781 else 01782 { 01783 file = context->CurrentInf; 01784 if (!(line = get_line( file, context->Section, context->Line ))) 01785 { 01786 SetLastError( ERROR_LINE_NOT_FOUND ); 01787 return FALSE; 01788 } 01789 } 01790 01791 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 01792 total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1; 01793 01794 if (required) *required = total; 01795 if (buffer) 01796 { 01797 if (total > size) 01798 { 01799 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01800 return FALSE; 01801 } 01802 for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) 01803 { 01804 unsigned int len = PARSER_string_substA( file, field->text, buffer, size ); 01805 if (i+1 < line->nb_fields) buffer[len] = ','; 01806 buffer += len + 1; 01807 } 01808 } 01809 return TRUE; 01810 } 01811 01812 01813 /*********************************************************************** 01814 * SetupGetFieldCount (SETUPAPI.@) 01815 */ 01816 DWORD WINAPI SetupGetFieldCount( PINFCONTEXT context ) 01817 { 01818 struct inf_file *file = context->CurrentInf; 01819 struct line *line = get_line( file, context->Section, context->Line ); 01820 01821 if (!line) return 0; 01822 return line->nb_fields; 01823 } 01824 01825 01826 /*********************************************************************** 01827 * SetupGetStringFieldA (SETUPAPI.@) 01828 */ 01829 BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, 01830 DWORD size, PDWORD required ) 01831 { 01832 struct inf_file *file = context->CurrentInf; 01833 struct field *field = get_field( file, context->Section, context->Line, index ); 01834 unsigned int len; 01835 01836 SetLastError(0); 01837 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } 01838 len = PARSER_string_substA( file, field->text, NULL, 0 ); 01839 if (required) *required = len + 1; 01840 if (buffer) 01841 { 01842 if (size <= len) 01843 { 01844 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01845 return FALSE; 01846 } 01847 PARSER_string_substA( file, field->text, buffer, size ); 01848 01849 TRACE( "context %p/%p/%d/%d index %d returning %s\n", 01850 context->Inf, context->CurrentInf, context->Section, context->Line, 01851 index, debugstr_a(buffer) ); 01852 } 01853 return TRUE; 01854 } 01855 01856 01857 /*********************************************************************** 01858 * SetupGetStringFieldW (SETUPAPI.@) 01859 */ 01860 BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, 01861 DWORD size, PDWORD required ) 01862 { 01863 struct inf_file *file = context->CurrentInf; 01864 struct field *field = get_field( file, context->Section, context->Line, index ); 01865 unsigned int len; 01866 01867 SetLastError(0); 01868 if (!field) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } 01869 len = PARSER_string_substW( file, field->text, NULL, 0 ); 01870 if (required) *required = len + 1; 01871 if (buffer) 01872 { 01873 if (size <= len) 01874 { 01875 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01876 return FALSE; 01877 } 01878 PARSER_string_substW( file, field->text, buffer, size ); 01879 01880 TRACE( "context %p/%p/%d/%d index %d returning %s\n", 01881 context->Inf, context->CurrentInf, context->Section, context->Line, 01882 index, debugstr_w(buffer) ); 01883 } 01884 return TRUE; 01885 } 01886 01887 01888 /*********************************************************************** 01889 * SetupGetIntField (SETUPAPI.@) 01890 */ 01891 BOOL WINAPI SetupGetIntField( PINFCONTEXT context, DWORD index, PINT result ) 01892 { 01893 char localbuff[20]; 01894 char *end, *buffer = localbuff; 01895 DWORD required; 01896 INT res; 01897 BOOL ret; 01898 01899 if (!(ret = SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required ))) 01900 { 01901 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE; 01902 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE; 01903 if (!(ret = SetupGetStringFieldA( context, index, buffer, required, NULL ))) goto done; 01904 } 01905 /* The call to SetupGetStringFieldA succeeded. If buffer is empty we have an optional field */ 01906 if (!*buffer) *result = 0; 01907 else 01908 { 01909 res = strtol( buffer, &end, 0 ); 01910 if (end != buffer && !*end) *result = res; 01911 else 01912 { 01913 SetLastError( ERROR_INVALID_DATA ); 01914 ret = FALSE; 01915 } 01916 } 01917 01918 done: 01919 if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer ); 01920 return ret; 01921 } 01922 01923 01924 /*********************************************************************** 01925 * SetupGetBinaryField (SETUPAPI.@) 01926 */ 01927 BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer, 01928 DWORD size, LPDWORD required ) 01929 { 01930 struct inf_file *file = context->CurrentInf; 01931 struct line *line = get_line( file, context->Section, context->Line ); 01932 struct field *field; 01933 int i; 01934 01935 if (!line) 01936 { 01937 SetLastError( ERROR_LINE_NOT_FOUND ); 01938 return FALSE; 01939 } 01940 if (!index || index > line->nb_fields) 01941 { 01942 SetLastError( ERROR_INVALID_PARAMETER ); 01943 return FALSE; 01944 } 01945 index--; /* fields start at 0 */ 01946 if (required) *required = line->nb_fields - index; 01947 if (!buffer) return TRUE; 01948 if (size < line->nb_fields - index) 01949 { 01950 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 01951 return FALSE; 01952 } 01953 field = &file->fields[line->first_field + index]; 01954 for (i = index; i < line->nb_fields; i++, field++) 01955 { 01956 const WCHAR *p; 01957 DWORD value = 0; 01958 for (p = field->text; *p && isxdigitW(*p); p++) 01959 { 01960 if ((value <<= 4) > 255) 01961 { 01962 SetLastError( ERROR_INVALID_DATA ); 01963 return FALSE; 01964 } 01965 if (*p <= '9') value |= (*p - '0'); 01966 else value |= (tolowerW(*p) - 'a' + 10); 01967 } 01968 buffer[i - index] = value; 01969 } 01970 if (TRACE_ON(setupapi)) 01971 { 01972 TRACE( "%p/%p/%d/%d index %d returning:\n", 01973 context->Inf, context->CurrentInf, context->Section, context->Line, index ); 01974 for (i = index; i < line->nb_fields; i++) TRACE( " %02x\n", buffer[i - index] ); 01975 } 01976 return TRUE; 01977 } 01978 01979 01980 /*********************************************************************** 01981 * SetupGetMultiSzFieldA (SETUPAPI.@) 01982 */ 01983 BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, 01984 DWORD size, LPDWORD required ) 01985 { 01986 struct inf_file *file = context->CurrentInf; 01987 struct line *line = get_line( file, context->Section, context->Line ); 01988 struct field *field; 01989 unsigned int len; 01990 int i; 01991 DWORD total = 1; 01992 01993 if (!line) 01994 { 01995 SetLastError( ERROR_LINE_NOT_FOUND ); 01996 return FALSE; 01997 } 01998 if (!index || index > line->nb_fields) 01999 { 02000 SetLastError( ERROR_INVALID_PARAMETER ); 02001 return FALSE; 02002 } 02003 index--; /* fields start at 0 */ 02004 field = &file->fields[line->first_field + index]; 02005 for (i = index; i < line->nb_fields; i++, field++) 02006 { 02007 if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break; 02008 total += len + 1; 02009 } 02010 02011 if (required) *required = total; 02012 if (!buffer) return TRUE; 02013 if (total > size) 02014 { 02015 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 02016 return FALSE; 02017 } 02018 field = &file->fields[line->first_field + index]; 02019 for (i = index; i < line->nb_fields; i++, field++) 02020 { 02021 if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break; 02022 buffer += len + 1; 02023 } 02024 *buffer = 0; /* add final null */ 02025 return TRUE; 02026 } 02027 02028 02029 /*********************************************************************** 02030 * SetupGetMultiSzFieldW (SETUPAPI.@) 02031 */ 02032 BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, 02033 DWORD size, LPDWORD required ) 02034 { 02035 struct inf_file *file = context->CurrentInf; 02036 struct line *line = get_line( file, context->Section, context->Line ); 02037 struct field *field; 02038 unsigned int len; 02039 int i; 02040 DWORD total = 1; 02041 02042 if (!line) 02043 { 02044 SetLastError( ERROR_LINE_NOT_FOUND ); 02045 return FALSE; 02046 } 02047 if (!index || index > line->nb_fields) 02048 { 02049 SetLastError( ERROR_INVALID_PARAMETER ); 02050 return FALSE; 02051 } 02052 index--; /* fields start at 0 */ 02053 field = &file->fields[line->first_field + index]; 02054 for (i = index; i < line->nb_fields; i++, field++) 02055 { 02056 if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break; 02057 total += len + 1; 02058 } 02059 02060 if (required) *required = total; 02061 if (!buffer) return TRUE; 02062 if (total > size) 02063 { 02064 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 02065 return FALSE; 02066 } 02067 field = &file->fields[line->first_field + index]; 02068 for (i = index; i < line->nb_fields; i++, field++) 02069 { 02070 if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break; 02071 buffer += len + 1; 02072 } 02073 *buffer = 0; /* add final null */ 02074 return TRUE; 02075 } 02076 02077 /*********************************************************************** 02078 * pSetupGetField (SETUPAPI.@) 02079 */ 02080 LPCWSTR WINAPI pSetupGetField( PINFCONTEXT context, DWORD index ) 02081 { 02082 struct inf_file *file = context->CurrentInf; 02083 struct field *field = get_field( file, context->Section, context->Line, index ); 02084 02085 if (!field) 02086 { 02087 SetLastError( ERROR_INVALID_PARAMETER ); 02088 return NULL; 02089 } 02090 return field->text; 02091 } 02092 02093 /*********************************************************************** 02094 * SetupGetInfFileListW (SETUPAPI.@) 02095 */ 02096 BOOL WINAPI 02097 SetupGetInfFileListW( 02098 IN PCWSTR DirectoryPath OPTIONAL, 02099 IN DWORD InfStyle, 02100 IN OUT PWSTR ReturnBuffer OPTIONAL, 02101 IN DWORD ReturnBufferSize OPTIONAL, 02102 OUT PDWORD RequiredSize OPTIONAL) 02103 { 02104 HANDLE hSearch; 02105 LPWSTR pFullFileName = NULL; 02106 LPWSTR pFileName; /* Pointer into pFullFileName buffer */ 02107 LPWSTR pBuffer = ReturnBuffer; 02108 WIN32_FIND_DATAW wfdFileInfo; 02109 size_t len; 02110 DWORD requiredSize = 0; 02111 BOOL ret = FALSE; 02112 02113 TRACE("%s %lx %p %ld %p\n", debugstr_w(DirectoryPath), InfStyle, 02114 ReturnBuffer, ReturnBufferSize, RequiredSize); 02115 02116 if (InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)) 02117 { 02118 TRACE("Unknown flags: 0x%08lx\n", InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4)); 02119 SetLastError(ERROR_INVALID_PARAMETER); 02120 goto cleanup; 02121 } 02122 else if (ReturnBufferSize == 0 && ReturnBuffer != NULL) 02123 { 02124 SetLastError(ERROR_INVALID_PARAMETER); 02125 goto cleanup; 02126 } 02127 else if (ReturnBufferSize > 0 && ReturnBuffer == NULL) 02128 { 02129 SetLastError(ERROR_INVALID_PARAMETER); 02130 goto cleanup; 02131 } 02132 02133 /* Allocate memory for file filter */ 02134 if (DirectoryPath != NULL) 02135 /* "DirectoryPath\" form */ 02136 len = strlenW(DirectoryPath) + 1 + 1; 02137 else 02138 /* "%SYSTEMROOT%\Inf\" form */ 02139 len = MAX_PATH + 1 + strlenW(InfDirectory) + 1; 02140 len += MAX_PATH; /* To contain file name or "*.inf" string */ 02141 pFullFileName = MyMalloc(len * sizeof(WCHAR)); 02142 if (pFullFileName == NULL) 02143 { 02144 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 02145 goto cleanup; 02146 } 02147 02148 /* Fill file filter buffer */ 02149 if (DirectoryPath) 02150 { 02151 strcpyW(pFullFileName, DirectoryPath); 02152 if (*pFullFileName && pFullFileName[strlenW(pFullFileName) - 1] != '\\') 02153 strcatW(pFullFileName, BackSlash); 02154 } 02155 else 02156 { 02157 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH); 02158 if (len == 0 || len > MAX_PATH) 02159 goto cleanup; 02160 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\') 02161 strcatW(pFullFileName, BackSlash); 02162 strcatW(pFullFileName, InfDirectory); 02163 } 02164 pFileName = &pFullFileName[strlenW(pFullFileName)]; 02165 02166 /* Search for the first file */ 02167 strcpyW(pFileName, InfFileSpecification); 02168 hSearch = FindFirstFileW(pFullFileName, &wfdFileInfo); 02169 if (hSearch == INVALID_HANDLE_VALUE) 02170 { 02171 TRACE("No file returned by %s\n", debugstr_w(pFullFileName)); 02172 goto cleanup; 02173 } 02174 02175 do 02176 { 02177 HINF hInf; 02178 02179 strcpyW(pFileName, wfdFileInfo.cFileName); 02180 hInf = SetupOpenInfFileW( 02181 pFullFileName, 02182 NULL, /* Inf class */ 02183 InfStyle, 02184 NULL /* Error line */); 02185 if (hInf == INVALID_HANDLE_VALUE) 02186 { 02187 if (GetLastError() == ERROR_CLASS_MISMATCH) 02188 { 02189 /* InfStyle was not correct. Skip this file */ 02190 continue; 02191 } 02192 TRACE("Invalid .inf file %s\n", debugstr_w(pFullFileName)); 02193 continue; 02194 } 02195 02196 len = strlenW(wfdFileInfo.cFileName) + 1; 02197 requiredSize += (DWORD)(len * sizeof(WCHAR)); 02198 if (requiredSize <= ReturnBufferSize) 02199 { 02200 strcpyW(pBuffer, wfdFileInfo.cFileName); 02201 pBuffer = &pBuffer[len]; 02202 } 02203 SetupCloseInfFile(hInf); 02204 } while (FindNextFileW(hSearch, &wfdFileInfo)); 02205 FindClose(hSearch); 02206 02207 requiredSize += sizeof(WCHAR); /* Final NULL char */ 02208 if (requiredSize <= ReturnBufferSize) 02209 { 02210 *pBuffer = '\0'; 02211 ret = TRUE; 02212 } 02213 else 02214 { 02215 SetLastError(ERROR_INSUFFICIENT_BUFFER); 02216 ret = FALSE; 02217 } 02218 if (RequiredSize) 02219 *RequiredSize = requiredSize; 02220 02221 cleanup: 02222 MyFree(pFullFileName); 02223 return ret; 02224 } 02225 02226 /*********************************************************************** 02227 * SetupGetInfFileListA (SETUPAPI.@) 02228 */ 02229 BOOL WINAPI 02230 SetupGetInfFileListA( 02231 IN PCSTR DirectoryPath OPTIONAL, 02232 IN DWORD InfStyle, 02233 IN OUT PSTR ReturnBuffer OPTIONAL, 02234 IN DWORD ReturnBufferSize OPTIONAL, 02235 OUT PDWORD RequiredSize OPTIONAL) 02236 { 02237 PWSTR DirectoryPathW = NULL; 02238 PWSTR ReturnBufferW = NULL; 02239 BOOL ret = FALSE; 02240 02241 TRACE("%s %lx %p %ld %p\n", debugstr_a(DirectoryPath), InfStyle, 02242 ReturnBuffer, ReturnBufferSize, RequiredSize); 02243 02244 if (DirectoryPath != NULL) 02245 { 02246 DirectoryPathW = pSetupMultiByteToUnicode(DirectoryPath, CP_ACP); 02247 if (DirectoryPathW == NULL) goto Cleanup; 02248 } 02249 02250 if (ReturnBuffer != NULL && ReturnBufferSize != 0) 02251 { 02252 ReturnBufferW = MyMalloc(ReturnBufferSize * sizeof(WCHAR)); 02253 if (ReturnBufferW == NULL) goto Cleanup; 02254 } 02255 02256 ret = SetupGetInfFileListW(DirectoryPathW, InfStyle, ReturnBufferW, ReturnBufferSize, RequiredSize); 02257 02258 if (ret && ReturnBufferW != NULL) 02259 { 02260 ret = WideCharToMultiByte(CP_ACP, 0, ReturnBufferW, -1, ReturnBuffer, ReturnBufferSize, NULL, NULL) != 0; 02261 } 02262 02263 Cleanup: 02264 MyFree(DirectoryPathW); 02265 MyFree(ReturnBufferW); 02266 02267 return ret; 02268 } 02269 02270 /*********************************************************************** 02271 * SetupDiGetINFClassW (SETUPAPI.@) 02272 */ 02273 BOOL WINAPI 02274 SetupDiGetINFClassW( 02275 IN PCWSTR InfName, 02276 OUT LPGUID ClassGuid, 02277 OUT PWSTR ClassName, 02278 IN DWORD ClassNameSize, 02279 OUT PDWORD RequiredSize OPTIONAL) 02280 { 02281 HINF hInf = INVALID_HANDLE_VALUE; 02282 BOOL ret = FALSE; 02283 02284 TRACE("%s %p %p %ld %p\n", debugstr_w(InfName), ClassGuid, 02285 ClassName, ClassNameSize, RequiredSize); 02286 02287 /* Open .inf file */ 02288 hInf = SetupOpenInfFileW(InfName, NULL, INF_STYLE_WIN4, NULL); 02289 if (hInf == INVALID_HANDLE_VALUE) 02290 goto cleanup; 02291 02292 ret = PARSER_GetInfClassW(hInf, ClassGuid, ClassName, ClassNameSize, RequiredSize); 02293 02294 cleanup: 02295 if (hInf != INVALID_HANDLE_VALUE) 02296 SetupCloseInfFile(hInf); 02297 02298 TRACE("Returning %d\n", ret); 02299 return ret; 02300 } 02301 02302 /*********************************************************************** 02303 * SetupDiGetINFClassA (SETUPAPI.@) 02304 */ 02305 BOOL WINAPI SetupDiGetINFClassA( 02306 IN PCSTR InfName, 02307 OUT LPGUID ClassGuid, 02308 OUT PSTR ClassName, 02309 IN DWORD ClassNameSize, 02310 OUT PDWORD RequiredSize OPTIONAL) 02311 { 02312 PWSTR InfNameW = NULL; 02313 PWSTR ClassNameW = NULL; 02314 BOOL ret = FALSE; 02315 02316 TRACE("%s %p %p %ld %p\n", debugstr_a(InfName), ClassGuid, 02317 ClassName, ClassNameSize, RequiredSize); 02318 02319 if (InfName != NULL) 02320 { 02321 InfNameW = pSetupMultiByteToUnicode(InfName, CP_ACP); 02322 if (InfNameW == NULL) goto Cleanup; 02323 } 02324 02325 if (ClassName != NULL && ClassNameSize != 0) 02326 { 02327 ClassNameW = MyMalloc(ClassNameSize * sizeof(WCHAR)); 02328 if (ClassNameW == NULL) goto Cleanup; 02329 } 02330 02331 ret = SetupDiGetINFClassW(InfNameW, ClassGuid, ClassNameW, ClassNameSize, RequiredSize); 02332 02333 if (ret && ClassNameW != NULL) 02334 { 02335 ret = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName, ClassNameSize, NULL, NULL) != 0; 02336 } 02337 02338 Cleanup: 02339 MyFree(InfNameW); 02340 MyFree(ClassNameW); 02341 02342 return ret; 02343 } 02344 02345 BOOL EnumerateSectionsStartingWith( 02346 IN HINF hInf, 02347 IN LPCWSTR pStr, 02348 IN FIND_CALLBACK Callback, 02349 IN PVOID Context) 02350 { 02351 struct inf_file *file = (struct inf_file *)hInf; 02352 size_t len = strlenW(pStr); 02353 unsigned int i; 02354 02355 for (i = 0; i < file->nb_sections; i++) 02356 if (strncmpiW(pStr, file->sections[i]->name, len) == 0) 02357 { 02358 if (!Callback(file->sections[i]->name, Context)) 02359 return FALSE; 02360 } 02361 return TRUE; 02362 } Generated on Sun May 27 2012 04:17:20 for ReactOS by
1.7.6.1
|