ReactOS  0.4.14-dev-98-gb0d4763
parser.c
Go to the documentation of this file.
1 /*
2  * INF file parsing tests
3  *
4  * Copyright 2002, 2005 Alexandre Julliard for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "setupapi.h"
29 
30 #include "wine/test.h"
31 
32 /* function pointers */
34 static LPCSTR (WINAPI *pSetupGetFieldA)(PINFCONTEXT,DWORD);
35 static LPCWSTR (WINAPI *pSetupGetFieldW)(PINFCONTEXT,DWORD);
36 static BOOL (WINAPI *pSetupEnumInfSectionsA)( HINF hinf, UINT index, PSTR buffer, DWORD size, UINT *need );
37 
38 static void init_function_pointers(void)
39 {
40  hSetupAPI = GetModuleHandleA("setupapi.dll");
41 
42  /* Nice, pSetupGetField is either A or W depending on the Windows version! The actual test
43  * takes care of this difference */
44  pSetupGetFieldA = (void *)GetProcAddress(hSetupAPI, "pSetupGetField");
45  pSetupGetFieldW = (void *)GetProcAddress(hSetupAPI, "pSetupGetField");
46  pSetupEnumInfSectionsA = (void *)GetProcAddress(hSetupAPI, "SetupEnumInfSectionsA" );
47 }
48 
49 static const char tmpfilename[] = ".\\tmp.inf";
50 
51 /* some large strings */
52 #define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
53  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
54  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
55  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
56 #define A256 "a" A255
57 #define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
58  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
59  "aaaaaaaaaaaaaaaa" A256
60 #define A1200 A400 A400 A400
61 #define A511 A255 A256
62 #define A4096 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
63 #define A4097 "a" A4096
64 
65 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
66 
67 #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \
68  "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \
69  "big=" A400 "\n" \
70  "mydrive=\"C:\\\"\n" \
71  "verybig=" A1200 "\n"
72 
73 /* create a new file with specified contents and open it */
74 static HINF test_file_contents( const char *data, UINT *err_line )
75 {
76  DWORD res;
79  if (handle == INVALID_HANDLE_VALUE) return 0;
80  if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" );
83 }
84 
86 {
87  static char buffer[MAX_INF_STRING_LENGTH+32];
88  if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
89  return NULL;
90 }
91 
92 static const char *get_line_text( INFCONTEXT *context )
93 {
94  static char buffer[MAX_INF_STRING_LENGTH+32];
95  if (SetupGetLineTextA( context, 0, 0, 0, buffer, sizeof(buffer), NULL )) return buffer;
96  return NULL;
97 }
98 
99 
100 /* Test various valid/invalid file formats */
101 
102 static const struct
103 {
104  const char *data;
108 } invalid_files[] =
109 {
110  /* file contents expected error (or 0) errline todo */
111  { "\r\n", ERROR_WRONG_INF_STYLE, 0, FALSE },
112  { "abcd\r\n", ERROR_WRONG_INF_STYLE, 0, TRUE },
113  { "[Version]\r\n", ERROR_WRONG_INF_STYLE, 0, FALSE },
114  { "[Version]\nSignature=", ERROR_WRONG_INF_STYLE, 0, FALSE },
115  { "[Version]\nSignature=foo", ERROR_WRONG_INF_STYLE, 0, FALSE },
116  { "[version]\nsignature=$chicago$", 0, 0, FALSE },
117  { "[VERSION]\nSIGNATURE=$CHICAGO$", 0, 0, FALSE },
118  { "[Version]\nSignature=$chicago$,abcd", 0, 0, FALSE },
119  { "[Version]\nabc=def\nSignature=$chicago$", 0, 0, FALSE },
120  { "[Version]\nabc=def\n[Version]\nSignature=$chicago$", 0, 0, FALSE },
121  { STD_HEADER, 0, 0, FALSE },
122  { STD_HEADER "[]\r\n", 0, 0, FALSE },
123  { STD_HEADER "]\r\n", 0, 0, FALSE },
124  { STD_HEADER "[" A255 "]\r\n", 0, 0, FALSE },
125  { STD_HEADER "[ab\r\n", ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
126  { STD_HEADER "\n\n[ab\x1a]\n", ERROR_BAD_SECTION_NAME_LINE, 5, FALSE },
127  { STD_HEADER "[" A256 "]\r\n", ERROR_SECTION_NAME_TOO_LONG, 3, FALSE },
128  { "[abc]\n" STD_HEADER, 0, 0, FALSE },
129  { "abc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
130  { ";\n;\nabc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, FALSE },
131  { ";\n;\nab\nab\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, FALSE },
132  { ";aa\n;bb\n" STD_HEADER, 0, 0, FALSE },
133  { STD_HEADER " [TestSection\x00]\n", ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
134  { STD_HEADER " [Test\x00Section]\n", ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
135  { STD_HEADER " [TestSection\x00]\n", ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
136  { STD_HEADER " [Test\x00Section]\n", ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
137  { "garbage1\ngarbage2\n[abc]\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
138  { "garbage1\ngarbage2\n[Strings]\n" STD_HEADER, 0, 0, FALSE },
139  { ";comment\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
140  { ";comment\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER, 0, 0, FALSE },
141  { " \t\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
142  { " \t\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER, 0, 0, FALSE },
143  { "garbage1\ngarbage2\n" STD_HEADER "[abc]\n", ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
144  { "garbage1\ngarbage2\n" STD_HEADER "[Strings]\n", 0, 0, FALSE },
145  { ";comment\ngarbage1\ngarbage2\n" STD_HEADER "[abc]\n", ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
146  { ";comment\ngarbage1\ngarbage2\n" STD_HEADER "[Strings]\n", 0, 0, FALSE },
147  { " \t\ngarbage1\ngarbage2\n" STD_HEADER "[abc]\n", ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
148  { " \t\ngarbage1\ngarbage2\n" STD_HEADER "[Strings]\n", 0, 0, FALSE },
149 };
150 
151 static void test_invalid_files(void)
152 {
153  unsigned int i;
154  UINT err_line;
155  HINF hinf;
156  DWORD err;
157 
158  for (i = 0; i < ARRAY_SIZE(invalid_files); i++)
159  {
160  SetLastError( 0xdeadbeef );
161  err_line = 0xdeadbeef;
163  err = GetLastError();
164  trace( "hinf=%p err=0x%x line=%d\n", hinf, err, err_line );
165  if (invalid_files[i].error) /* should fail */
166  {
167  ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i );
169  {
170  ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
171  i, err, invalid_files[i].error );
172  ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
174  }
175  }
176  else /* should succeed */
177  {
178  ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i );
179  ok( err == 0, "file %u: Error code set to %u\n", i, err );
180  }
181  SetupCloseInfFile( hinf );
182  }
183 }
184 
185 
186 /* Test various section names */
187 
188 static const struct
189 {
190  const char *data;
191  const char *section;
192  DWORD error;
193 } section_names[] =
194 {
195  /* file contents section name error code */
196  { STD_HEADER "[TestSection]", "TestSection", 0 },
197  { STD_HEADER "[TestSection]\n", "TestSection", 0 },
198  { STD_HEADER "[TESTSECTION]\r\n", "TestSection", 0 },
199  { STD_HEADER "[TestSection]\n[abc]", "testsection", 0 },
200  { STD_HEADER ";[TestSection]\n", "TestSection", ERROR_SECTION_NOT_FOUND },
201  { STD_HEADER "[TestSection]\n", "Bad name", ERROR_SECTION_NOT_FOUND },
202  /* spaces */
203  { STD_HEADER "[TestSection] \r\n", "TestSection", 0 },
204  { STD_HEADER " [TestSection]\r\n", "TestSection", 0 },
205  { STD_HEADER " [TestSection] dummy\r\n", "TestSection", 0 },
206  { STD_HEADER " [TestSection] [foo]\r\n", "TestSection", 0 },
207  { STD_HEADER " [ Test Section ] dummy\r\n", " Test Section ", 0 },
208  { STD_HEADER "[TestSection] \032\ndummy", "TestSection", 0 },
209  { STD_HEADER "[TestSection] \n\032dummy", "TestSection", 0 },
210  /* special chars in section name */
211  { STD_HEADER "[Test[Section]\r\n", "Test[Section", 0 },
212  { STD_HEADER "[Test[S]ection]\r\n", "Test[S", 0 },
213  { STD_HEADER "[Test[[[Section]\r\n", "Test[[[Section", 0 },
214  { STD_HEADER "[]\r\n", "", 0 },
215  { STD_HEADER "[[[]\n", "[[", 0 },
216  { STD_HEADER "[Test\"Section]\r\n", "Test\"Section", 0 },
217  { STD_HEADER "[Test\\Section]\r\n", "Test\\Section", 0 },
218  { STD_HEADER "[Test\\ Section]\r\n", "Test\\ Section", 0 },
219  { STD_HEADER "[Test;Section]\r\n", "Test;Section", 0 },
220  /* various control chars */
221  { STD_HEADER " [Test\r\b\tSection] \n", "Test\r\b\tSection", 0 },
222  /* nulls */
223 };
224 
225 static void test_section_names(void)
226 {
227  unsigned int i;
228  UINT err_line;
229  HINF hinf;
230  DWORD err;
231  LONG ret;
232 
233  for (i = 0; i < ARRAY_SIZE(section_names); i++)
234  {
235  SetLastError( 0xdeadbeef );
237  ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
238  if (hinf == INVALID_HANDLE_VALUE) continue;
239 
241  err = GetLastError();
242  trace( "hinf=%p ret=%d err=0x%x\n", hinf, ret, err );
243  if (ret != -1)
244  {
245  ok( !section_names[i].error, "line %u: section name %s found\n",
246  i, section_names[i].section );
247  ok( !err, "line %u: bad error code %u\n", i, err );
248  }
249  else
250  {
251  ok( section_names[i].error, "line %u: section name %s not found\n",
252  i, section_names[i].section );
253  ok( err == section_names[i].error, "line %u: bad error %u/%u\n",
254  i, err, section_names[i].error );
255  }
256  SetupCloseInfFile( hinf );
257  }
258 }
259 
260 static void test_enum_sections(void)
261 {
262  static const char *contents = STD_HEADER "[s1]\nfoo=bar\n[s2]\nbar=foo\n[s3]\n[strings]\na=b\n";
263 
264  BOOL ret;
265  DWORD len;
266  HINF hinf;
267  UINT err, index;
268  char buffer[256];
269 
270  if (!pSetupEnumInfSectionsA)
271  {
272  win_skip( "SetupEnumInfSectionsA not available\n" );
273  return;
274  }
275 
276  hinf = test_file_contents( contents, &err );
277  ok( hinf != NULL, "Expected valid INF file\n" );
278 
279  for (index = 0; ; index++)
280  {
281  SetLastError( 0xdeadbeef );
282  ret = pSetupEnumInfSectionsA( hinf, index, NULL, 0, &len );
283  err = GetLastError();
284  if (!ret && GetLastError() == ERROR_NO_MORE_ITEMS) break;
285  ok( ret, "SetupEnumInfSectionsA failed\n" );
286  ok( len == 3 || len == 8, "wrong len %u\n", len );
287 
288  SetLastError( 0xdeadbeef );
289  ret = pSetupEnumInfSectionsA( hinf, index, NULL, sizeof(buffer), &len );
290  err = GetLastError();
291  ok( !ret, "SetupEnumInfSectionsA succeeded\n" );
292  ok( err == ERROR_INVALID_USER_BUFFER, "wrong error %u\n", err );
293  ok( len == 3 || len == 8, "wrong len %u\n", len );
294 
295  SetLastError( 0xdeadbeef );
296  ret = pSetupEnumInfSectionsA( hinf, index, buffer, sizeof(buffer), &len );
297  ok( ret, "SetupEnumInfSectionsA failed err %u\n", GetLastError() );
298  ok( len == 3 || len == 8, "wrong len %u\n", len );
299  ok( !lstrcmpiA( buffer, "version" ) || !lstrcmpiA( buffer, "s1" ) ||
300  !lstrcmpiA( buffer, "s2" ) || !lstrcmpiA( buffer, "s3" ) || !lstrcmpiA( buffer, "strings" ),
301  "bad section '%s'\n", buffer );
302  }
303  SetupCloseInfFile( hinf );
304 }
305 
306 
307 /* Test various key and value names */
308 
309 static const struct
310 {
311  const char *data;
312  const char *key;
313  const char *fields[10];
314 } key_names[] =
315 {
316 /* file contents expected key expected fields */
317  { "ab=cd", "ab", { "cd" } },
318  { "ab=cd,ef,gh,ij", "ab", { "cd", "ef", "gh", "ij" } },
319  { "ab", "ab", { "ab" } },
320  { "ab,cd", NULL, { "ab", "cd" } },
321  { "ab,cd=ef", NULL, { "ab", "cd=ef" } },
322  { "=abcd,ef", "", { "abcd", "ef" } },
323  /* backslashes */
324  { "ba\\\ncd=ef", "bacd", { "ef" } },
325  { "ab \\ \ncd=ef", "abcd", { "ef" } },
326  { "ab\\\ncd,ef", NULL, { "abcd", "ef" } },
327  { "ab \\ ;cc\ncd=ef", "abcd", { "ef" } },
328  { "ab \\ \\ \ncd=ef", "abcd", { "ef" } },
329  { "ba \\ dc=xx", "ba \\ dc", { "xx" } },
330  { "ba \\\\ \nc=d", "bac", { "d" } },
331  { "a=b\\\\c", "a", { "b\\\\c" } },
332  { "ab=cd \\ ", "ab", { "cd" } },
333  { "ba=c \\ \n \\ \n a", "ba", { "ca" } },
334  { "ba=c \\ \n \\ a", "ba", { "c\\ a" } },
335  { " \\ a= \\ b", "\\ a", { "\\ b" } },
336  /* quotes */
337  { "Ab\"Cd\"=Ef", "AbCd", { "Ef" } },
338  { "Ab\"Cd=Ef\"", "AbCd=Ef", { "AbCd=Ef" } },
339  { "ab\"\"\"cd,ef=gh\"", "ab\"cd,ef=gh", { "ab\"cd,ef=gh" } },
340  { "ab\"\"cd=ef", "abcd", { "ef" } },
341  { "ab\"\"cd=ef,gh", "abcd", { "ef", "gh" } },
342  { "ab=cd\"\"ef", "ab", { "cdef" } },
343  { "ab=cd\",\"ef", "ab", { "cd,ef" } },
344  { "ab=cd\",ef", "ab", { "cd,ef" } },
345  { "ab=cd\",ef\\\nab", "ab", { "cd,ef\\" } },
346 
347  /* single quotes (unhandled)*/
348  { "HKLM,A,B,'C',D", NULL, { "HKLM", "A","B","'C'","D" } },
349  /* spaces */
350  { " a b = c , d \n", "a b", { "c", "d" } },
351  { " a b = c ,\" d\" \n", "a b", { "c", " d" } },
352  { " a b\r = c\r\n", "a b", { "c" } },
353  /* empty fields */
354  { "a=b,,,c,,,d", "a", { "b", "", "", "c", "", "", "d" } },
355  { "a=b,\"\",c,\" \",d", "a", { "b", "", "c", " ", "d" } },
356  { "=,,b", "", { "", "", "b" } },
357  { ",=,,b", NULL, { "", "=", "", "b" } },
358  { "a=\n", "a", { "" } },
359  { "=", "", { "" } },
360  /* eof */
361  { "ab=c\032d", "ab", { "c" } },
362  { "ab\032=cd", "ab", { "ab" } },
363  /* nulls */
364  { "abcd=ef\x0gh", "abcd", { "ef" } },
365  /* multiple sections with same name */
366  { "[Test2]\nab\n[Test]\nee=ff\n", "ee", { "ff" } },
367  /* string substitution */
368  { "%foo%=%bar%\n" STR_SECTION, "aaa", { "bbb" } },
369  { "%foo%xx=%bar%yy\n" STR_SECTION, "aaaxx", { "bbbyy" } },
370  { "%% %foo%=%bar%\n" STR_SECTION, "% aaa", { "bbb" } },
371  { "%f\"o\"o%=ccc\n" STR_SECTION, "aaa", { "ccc" } },
372  { "abc=%bar;bla%\n" STR_SECTION, "abc", { "%bar" } },
373  { "loop=%loop%\n" STR_SECTION, "loop", { "%loop2%" } },
374  { "%per%%cent%=100\n" STR_SECTION, "12", { "100" } },
375  { "a=%big%\n" STR_SECTION, "a", { A400 } },
376  { "a=%verybig%\n" STR_SECTION, "a", { A511 } }, /* truncated to 511, not on Vista/W2K8 */
377  { "a=%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 } },
378  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } },
379  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } },
380 
381  /* Prove expansion of system entries removes extra \'s and string
382  replacements doesn't */
383  { "ab=\"%24%\"\n" STR_SECTION, "ab", { "C:\\" } },
384  { "ab=\"%mydrive%\"\n" STR_SECTION, "ab", { "C:\\" } },
385  { "ab=\"%24%\\fred\"\n" STR_SECTION, "ab", { "C:\\fred" } },
386  { "ab=\"%mydrive%\\fred\"\n" STR_SECTION,"ab", { "C:\\\\fred" } },
387  /* Confirm duplicate \'s kept */
388  { "ab=\"%24%\\\\fred\"", "ab", { "C:\\\\fred" } },
389  { "ab=C:\\\\FRED", "ab", { "C:\\\\FRED" } },
390 };
391 
392 /* check the key of a certain line */
393 static const char *check_key( INFCONTEXT *context, const char *wanted )
394 {
395  const char *key = get_string_field( context, 0 );
396  DWORD err = GetLastError();
397 
398  if (!key)
399  {
400  ok( !wanted, "missing key %s\n", wanted );
401  ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %u\n", err );
402  }
403  else
404  {
405  ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
406  ok( err == 0, "last error set to %u\n", err );
407  }
408  return key;
409 }
410 
411 static void test_key_names(void)
412 {
413  char buffer[MAX_INF_STRING_LENGTH+32];
414  const char *line;
415  unsigned int i, index, count;
416  UINT err_line;
417  HINF hinf;
418  DWORD err;
419  BOOL ret;
421 
422  for (i = 0; i < ARRAY_SIZE(key_names); i++)
423  {
424  strcpy( buffer, STD_HEADER "[Test]\n" );
426  SetLastError( 0xdeadbeef );
427  hinf = test_file_contents( buffer, &err_line );
428  ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
429  if (hinf == INVALID_HANDLE_VALUE) continue;
430 
431  ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
432  ok(ret, "SetupFindFirstLineA failed: le=%u\n", GetLastError());
433  if (!ret)
434  {
435  SetupCloseInfFile( hinf );
436  continue;
437  }
438 
439  check_key( &context, key_names[i].key );
440 
441  buffer[0] = buffer[1] = 0; /* build the full line */
442  for (index = 0; ; index++)
443  {
444  const char *field = get_string_field( &context, index + 1 );
445  err = GetLastError();
446  if (field)
447  {
448  ok( err == 0, "line %u: bad error %u\n", i, err );
449  if (key_names[i].fields[index])
450  {
451  if (i == 49)
452  ok( !strcmp( field, key_names[i].fields[index] ) ||
453  !strcmp( field, A1200), /* Vista, W2K8 */
454  "line %u: bad field %s/%s\n",
455  i, field, key_names[i].fields[index] );
456  else if (i == 52)
457  ok( !strcmp( field, key_names[i].fields[index] ) ||
458  !strcmp( field, A4096), /* Win10 >= 1709 */
459  "line %u: bad field %s/%s\n",
460  i, field, key_names[i].fields[index] );
461  else /* don't compare drive letter of paths */
462  if (field[0] && field[1] == ':' && field[2] == '\\')
463  ok( !strcmp( field + 1, key_names[i].fields[index] + 1 ),
464  "line %u: bad field %s/%s\n",
465  i, field, key_names[i].fields[index] );
466  else
467  ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n",
468  i, field, key_names[i].fields[index] );
469  }
470  else
471  ok( 0, "line %u: got extra field %s\n", i, field );
472  strcat( buffer, "," );
473  strcat( buffer, field );
474  }
475  else
476  {
477  ok( err == 0 || err == ERROR_INVALID_PARAMETER,
478  "line %u: bad error %u\n", i, err );
479  if (key_names[i].fields[index])
480  ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
481  }
482  if (!key_names[i].fields[index]) break;
483  }
485  ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
486 
487  line = get_line_text( &context );
488  ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
489  if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
490 
491  SetupCloseInfFile( hinf );
492  }
493 
494 }
495 
496 static void test_close_inf_file(void)
497 {
498  SetLastError(0xdeadbeef);
500  ok(GetLastError() == 0xdeadbeef ||
501  GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
502  "Expected 0xdeadbeef, got %u\n", GetLastError());
503 
504  SetLastError(0xdeadbeef);
506  ok(GetLastError() == 0xdeadbeef ||
507  GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
508  "Expected 0xdeadbeef, got %u\n", GetLastError());
509 }
510 
511 static const char *contents = "[Version]\n"
512  "Signature=\"$Windows NT$\"\n"
513  "FileVersion=5.1.1.2\n"
514  "[FileBranchInfo]\n"
515  "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n"
516  "[Strings]\n"
517  "RTMQFE_NAME = \"RTMQFE\"\n";
518 
519 static const CHAR getfield_resA[][20] =
520 {
521  "RTMQFE",
522  "%RTMGFE_NAME%",
523  "SP1RTM",
524 };
525 
526 static const WCHAR getfield_resW[][20] =
527 {
528  {'R','T','M','Q','F','E',0},
529  {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
530  {'S','P','1','R','T','M',0},
531 };
532 
533 static void test_pSetupGetField(void)
534 {
535  UINT err;
536  BOOL ret;
537  HINF hinf;
538  LPCSTR fieldA;
539  LPCWSTR fieldW;
541  int i;
542  int len;
543  BOOL unicode = TRUE;
544 
545  SetLastError(0xdeadbeef);
546  lstrcmpW(NULL, NULL);
548  {
549  win_skip("Using A-functions instead of W\n");
550  unicode = FALSE;
551  }
552 
553  hinf = test_file_contents( contents, &err );
554  ok( hinf != NULL, "Expected valid INF file\n" );
555 
556  ret = SetupFindFirstLineA( hinf, "FileBranchInfo", NULL, &context );
557  ok( ret, "Failed to find first line\n" );
558 
559  /* native Windows crashes if a NULL context is sent in */
560 
561  for ( i = 0; i < 3; i++ )
562  {
563  if (unicode)
564  {
565  fieldW = pSetupGetFieldW( &context, i );
566  ok( fieldW != NULL, "Failed to get field %i\n", i );
567  ok( !lstrcmpW( getfield_resW[i], fieldW ), "Wrong string returned\n" );
568  }
569  else
570  {
571  fieldA = pSetupGetFieldA( &context, i );
572  ok( fieldA != NULL, "Failed to get field %i\n", i );
573  ok( !lstrcmpA( getfield_resA[i], fieldA ), "Wrong string returned\n" );
574  }
575  }
576 
577  if (unicode)
578  {
579  fieldW = pSetupGetFieldW( &context, 3 );
580  ok( fieldW != NULL, "Failed to get field 3\n" );
581  len = lstrlenW( fieldW );
582  ok( len == 511 || /* NT4, W2K, XP and W2K3 */
583  len == 4096, /* Vista */
584  "Unexpected length, got %d\n", len );
585 
586  fieldW = pSetupGetFieldW( &context, 4 );
587  ok( fieldW == NULL, "Expected NULL, got %p\n", fieldW );
589  "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
590  }
591  else
592  {
593  fieldA = pSetupGetFieldA( &context, 3 );
594  ok( fieldA != NULL, "Failed to get field 3\n" );
595  len = lstrlenA( fieldA );
596  ok( len == 511, /* Win9x, WinME */
597  "Unexpected length, got %d\n", len );
598 
599  fieldA = pSetupGetFieldA( &context, 4 );
600  ok( fieldA == NULL, "Expected NULL, got %p\n", fieldA );
602  "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
603  }
604 
605  SetupCloseInfFile( hinf );
606 }
607 
608 static void test_SetupGetIntField(void)
609 {
610  static const struct
611  {
612  const char *key;
613  const char *fields;
614  DWORD index;
615  INT value;
616  DWORD err;
617  } keys[] =
618  {
619  /* key fields index expected int errorcode */
620  { "Key", "48", 1, 48, ERROR_SUCCESS },
621  { "Key", "48", 0, -1, ERROR_INVALID_DATA },
622  { "123", "48", 0, 123, ERROR_SUCCESS },
623  { "Key", "0x4", 1, 4, ERROR_SUCCESS },
624  { "Key", "Field1", 1, -1, ERROR_INVALID_DATA },
625  { "Key", "Field1,34", 2, 34, ERROR_SUCCESS },
626  { "Key", "Field1,,Field3", 2, 0, ERROR_SUCCESS },
627  { "Key", "Field1,", 2, 0, ERROR_SUCCESS }
628  };
629  unsigned int i;
630 
631  for (i = 0; i < ARRAY_SIZE(keys); i++)
632  {
633  HINF hinf;
636  UINT err;
637  BOOL retb;
638  INT intfield;
639 
640  strcpy( buffer, STD_HEADER "[TestSection]\n" );
641  strcat( buffer, keys[i].key );
642  strcat( buffer, "=" );
643  strcat( buffer, keys[i].fields );
644  hinf = test_file_contents( buffer, &err);
645  ok( hinf != NULL, "Expected valid INF file\n" );
646 
647  SetupFindFirstLineA( hinf, "TestSection", keys[i].key, &context );
648  SetLastError( 0xdeadbeef );
649  intfield = -1;
650  retb = SetupGetIntField( &context, keys[i].index, &intfield );
651  if ( keys[i].err == ERROR_SUCCESS )
652  {
653  ok( retb, "%u: Expected success\n", i );
654  ok( GetLastError() == ERROR_SUCCESS ||
655  GetLastError() == 0xdeadbeef /* win9x, NT4 */,
656  "%u: Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", i, GetLastError() );
657  }
658  else
659  {
660  ok( !retb, "%u: Expected failure\n", i );
661  ok( GetLastError() == keys[i].err,
662  "%u: Expected %d, got %u\n", i, keys[i].err, GetLastError() );
663  }
664  ok( intfield == keys[i].value, "%u: Expected %d, got %d\n", i, keys[i].value, intfield );
665 
666  SetupCloseInfFile( hinf );
667  }
668 }
669 
670 static void test_GLE(void)
671 {
672  static const char *inf =
673  "[Version]\n"
674  "Signature=\"$Windows NT$\"\n"
675  "[Sectionname]\n"
676  "Keyname1=Field1,Field2,Field3\n"
677  "\n"
678  "Keyname2=Field4,Field5\n";
679  HINF hinf;
680  UINT err;
682  BOOL retb;
683  LONG retl;
686  DWORD retsize;
687 
688  hinf = test_file_contents( inf, &err );
689  ok( hinf != NULL, "Expected valid INF file\n" );
690 
691  SetLastError(0xdeadbeef);
692  retb = SetupFindFirstLineA( hinf, "ImNotThere", NULL, &context );
693  ok(!retb, "Expected failure\n");
695  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
696 
697  SetLastError(0xdeadbeef);
698  retb = SetupFindFirstLineA( hinf, "ImNotThere", "ImNotThere", &context );
699  ok(!retb, "Expected failure\n");
701  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
702 
703  SetLastError(0xdeadbeef);
704  retb = SetupFindFirstLineA( hinf, "Sectionname", NULL, &context );
705  ok(retb, "Expected success\n");
707  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
708 
709  SetLastError(0xdeadbeef);
710  retb = SetupFindFirstLineA( hinf, "Sectionname", "ImNotThere", &context );
711  ok(!retb, "Expected failure\n");
713  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
714 
715  SetLastError(0xdeadbeef);
716  retb = SetupFindFirstLineA( hinf, "Sectionname", "Keyname1", &context );
717  ok(retb, "Expected success\n");
719  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
720 
721  SetLastError(0xdeadbeef);
722  retb = SetupFindNextMatchLineA( &context, "ImNotThere", &context );
723  ok(!retb, "Expected failure\n");
725  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
726 
727  SetLastError(0xdeadbeef);
728  retb = SetupFindNextMatchLineA( &context, "Keyname2", &context );
729  ok(retb, "Expected success\n");
731  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
732 
733  SetLastError(0xdeadbeef);
734  retl = SetupGetLineCountA( hinf, "ImNotThere");
735  ok(retl == -1, "Expected -1, got %d\n", retl);
737  "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
738 
739  SetLastError(0xdeadbeef);
740  retl = SetupGetLineCountA( hinf, "Sectionname");
741  ok(retl == 2, "Expected 2, got %d\n", retl);
743  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
744 
745  SetLastError(0xdeadbeef);
746  retb = SetupGetLineTextA( NULL, hinf, "ImNotThere", "ImNotThere", buf, bufsize, &retsize);
747  ok(!retb, "Expected failure\n");
749  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
750 
751  SetLastError(0xdeadbeef);
752  retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "ImNotThere", buf, bufsize, &retsize);
753  ok(!retb, "Expected failure\n");
755  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
756 
757  SetLastError(0xdeadbeef);
758  retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "Keyname1", buf, bufsize, &retsize);
759  ok(retb, "Expected success\n");
761  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
762 
763  SetLastError(0xdeadbeef);
764  retb = SetupGetLineByIndexA( hinf, "ImNotThere", 1, &context );
765  ok(!retb, "Expected failure\n");
767  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
768 
769  SetLastError(0xdeadbeef);
770  retb = SetupGetLineByIndexA( hinf, "Sectionname", 1, &context );
771  ok(retb, "Expected success\n");
773  "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
774 
775  SetLastError(0xdeadbeef);
776  retb = SetupGetLineByIndexA( hinf, "Sectionname", 3, &context );
777  ok(!retb, "Expected failure\n");
779  "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
780 
781  SetupCloseInfFile( hinf );
782 }
783 
785 {
788  test_section_names();
789  test_enum_sections();
790  test_key_names();
791  test_close_inf_file();
792  test_pSetupGetField();
793  test_SetupGetIntField();
794  test_GLE();
796 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
BOOL WINAPI SetupFindNextMatchLineA(PINFCONTEXT context_in, PCSTR key, PINFCONTEXT context_out)
Definition: parser.c:1672
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define ERROR_SECTION_NOT_FOUND
Definition: setupapi.h:288
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
#define INF_STYLE_WIN4
Definition: infsupp.h:41
#define ERROR_SUCCESS
Definition: deptool.c:10
int WINAPI lstrcmpiA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:42
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
BOOL WINAPI SetupGetLineByIndexA(HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context)
Definition: parser.c:1515
#define START_TEST(x)
Definition: atltest.h:75
Definition: http.c:6587
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
static UINT index
Definition: parser.c:36
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
GLuint GLuint GLsizei count
Definition: gl.h:1545
char CHAR
Definition: xmlstorage.h:175
#define ERROR_SECTION_NAME_TOO_LONG
Definition: setupapi.h:284
static void init_function_pointers(void)
Definition: parser.c:38
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
GLuint buffer
Definition: glext.h:5915
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
Definition: parser.c:55
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
#define lstrlenW
Definition: compat.h:407
int32_t INT
Definition: typedefs.h:56
#define FILE_SHARE_READ
Definition: compat.h:125
BOOL todo
Definition: parser.c:107
#define A400
Definition: parser.c:57
#define ERROR_INVALID_USER_BUFFER
Definition: winerror.h:1091
#define ERROR_EXPECTED_SECTION_NAME
Definition: setupapi.h:282
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOL WINAPI SetupFindFirstLineA(HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context)
Definition: parser.c:1564
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define GENERIC_WRITE
Definition: nt_native.h:90
DWORD WINAPI SetupGetFieldCount(PINFCONTEXT context)
Definition: parser.c:1858
smooth NULL
Definition: ftsmooth.c:416
BOOL WINAPI DeleteFileA(IN LPCSTR lpFileName)
Definition: delete.c:24
Definition: parser.c:48
static LPCSTR(WINAPI *pSetupGetFieldA)(PINFCONTEXT
#define ERROR_LINE_NOT_FOUND
Definition: setupapi.h:289
GLuint index
Definition: glext.h:6031
const char * LPCSTR
Definition: xmlstorage.h:183
static UINT PSTR buffer
Definition: parser.c:36
BOOL WINAPI SetupGetLineTextA(PINFCONTEXT context, HINF hinf, PCSTR section_name, PCSTR key_name, PSTR buffer, DWORD size, PDWORD required)
Definition: parser.c:1807
#define todo_wine_if(is_todo)
Definition: test.h:155
const char * section
Definition: parser.c:191
static BOOL(WINAPI *pSetupEnumInfSectionsA)(HINF hinf
static void test_key_names(void)
Definition: input.c:1869
#define MAX_INF_STRING_LENGTH
Definition: infsupp.h:34
#define trace
Definition: atltest.h:70
__wchar_t WCHAR
Definition: xmlstorage.h:180
Definition: parser.c:43
#define WINAPI
Definition: msvc.h:8
static const char tmpfilename[]
Definition: parser.c:49
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD error
Definition: parser.c:105
static DWORD
Definition: parser.c:34
#define SetLastError(x)
Definition: compat.h:409
#define ERROR_BAD_SECTION_NAME_LINE
Definition: setupapi.h:283
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
int ret
static const struct @1636 invalid_files[]
#define STR_SECTION
Definition: parser.c:67
char line[200]
Definition: main.c:97
#define A511
Definition: parser.c:61
#define A256
Definition: parser.c:56
HKEY key
Definition: reg.c:42
GLenum GLsizei len
Definition: glext.h:6722
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:821
#define A4097
Definition: parser.c:63
static const char * get_string_field(INFCONTEXT *context, DWORD index)
Definition: parser.c:85
#define GENERIC_READ
Definition: compat.h:124
#define err(...)
GLsizei const GLfloat * value
Definition: glext.h:6069
HINF WINAPI SetupOpenInfFileA(PCSTR name, PCSTR class, DWORD style, UINT *error)
Definition: parser.c:1139
#define ERROR_INVALID_DATA
Definition: winerror.h:116
#define CREATE_ALWAYS
Definition: disk.h:72
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
BOOL WINAPI SetupGetStringFieldA(PINFCONTEXT context, DWORD index, PSTR buffer, DWORD size, PDWORD required)
Definition: parser.c:1871
#define ARRAY_SIZE(a)
Definition: main.h:24
#define ok(value,...)
Definition: atltest.h:57
static HINF test_file_contents(const char *data, UINT *err_line)
Definition: parser.c:74
signed char * PSTR
Definition: retypes.h:7
static HMODULE hSetupAPI
Definition: parser.c:33
unsigned int UINT
Definition: ndis.h:50
#define A4096
Definition: parser.c:62
UINT err_line
Definition: parser.c:106
#define A255
Definition: parser.c:52
struct _INFCONTEXT * PINFCONTEXT
#define STD_HEADER
Definition: parser.c:65
Definition: import.c:86
static LPCWSTR(WINAPI *pSetupGetFieldW)(PINFCONTEXT
GLuint res
Definition: glext.h:9613
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define ERROR_WRONG_INF_STYLE
Definition: setupapi.h:286
static const char * get_line_text(INFCONTEXT *context)
Definition: parser.c:92
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:92
#define GetProcAddress(x, y)
Definition: compat.h:410
const char * data
Definition: parser.c:104
ROSDATA VSC_LPWSTR key_names[]
Definition: kbda1.c:262
static void test_invalid_files(void)
Definition: parser.c:151
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
static UINT PSTR DWORD size
Definition: parser.c:36
struct contextA section_names[]
#define win_skip
Definition: test.h:141
LONG WINAPI SetupGetLineCountA(HINF hinf, PCSTR name)
Definition: parser.c:1475
static UINT PSTR DWORD UINT * need
Definition: parser.c:36
BOOL WINAPI SetupGetIntField(PINFCONTEXT context, DWORD index, PINT result)
Definition: parser.c:1933
void WINAPI SetupCloseInfFile(HINF hinf)
Definition: parser.c:1393
Definition: path.c:42
#define A1200
Definition: parser.c:60