ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

parser.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 = &section->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 &section->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( &sectionW, name ))
01439         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01440     else
01441     {
01442         ret = SetupGetLineCountW( hinf, sectionW.Buffer );
01443         RtlFreeUnicodeString( &sectionW );
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( &sectionW, section ))
01479         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01480     else
01481     {
01482         ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context );
01483         RtlFreeUnicodeString( &sectionW );
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( &sectionW, 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( &sectionW );
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 = &section->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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.