setupapi/tests: Added some tests for SetupEnumInfSectionsA/W.
[wine] / dlls / setupapi / tests / parser.c
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 <assert.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30
31 #include "wine/test.h"
32
33 /* function pointers */
34 static HMODULE hSetupAPI;
35 static LPCWSTR (WINAPI *pSetupGetField)(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     pSetupGetField = (void *)GetProcAddress(hSetupAPI, "pSetupGetField");
43     pSetupEnumInfSectionsA = (void *)GetProcAddress(hSetupAPI, "SetupEnumInfSectionsA" );
44 }
45
46 static const char tmpfilename[] = ".\\tmp.inf";
47
48 /* some large strings */
49 #define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
50              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
51              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
52              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
53 #define A256 "a" A255
54 #define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
55              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
56              "aaaaaaaaaaaaaaaa" A256
57 #define A1200 A400 A400 A400
58 #define A511 A255 A256
59 #define A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
60
61 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
62
63 #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \
64                     "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \
65                     "big=" A400 "\n" \
66                     "mydrive=\"C:\\\"\n" \
67                     "verybig=" A1200 "\n"
68
69 /* create a new file with specified contents and open it */
70 static HINF test_file_contents( const char *data, UINT *err_line )
71 {
72     DWORD res;
73     HANDLE handle = CreateFileA( tmpfilename, GENERIC_READ|GENERIC_WRITE,
74                                  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
75     if (handle == INVALID_HANDLE_VALUE) return 0;
76     if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" );
77     CloseHandle( handle );
78     return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line );
79 }
80
81 static const char *get_string_field( INFCONTEXT *context, DWORD index )
82 {
83     static char buffer[MAX_INF_STRING_LENGTH+32];
84     if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
85     return NULL;
86 }
87
88 static const char *get_line_text( INFCONTEXT *context )
89 {
90     static char buffer[MAX_INF_STRING_LENGTH+32];
91     if (SetupGetLineTextA( context, 0, 0, 0, buffer, sizeof(buffer), NULL )) return buffer;
92     return NULL;
93 }
94
95
96 /* Test various valid/invalid file formats */
97
98 static const struct
99 {
100     const char *data;
101     DWORD error;
102     UINT err_line;
103     int todo;
104 } invalid_files[] =
105 {
106     /* file contents                                         expected error (or 0)     errline  todo */
107     { "\r\n",                                                ERROR_WRONG_INF_STYLE,       0,    0 },
108     { "abcd\r\n",                                            ERROR_WRONG_INF_STYLE,       0,    1 },
109     { "[Version]\r\n",                                       ERROR_WRONG_INF_STYLE,       0,    0 },
110     { "[Version]\nSignature=",                               ERROR_WRONG_INF_STYLE,       0,    0 },
111     { "[Version]\nSignature=foo",                            ERROR_WRONG_INF_STYLE,       0,    0 },
112     { "[version]\nsignature=$chicago$",                      0,                           0,    0 },
113     { "[VERSION]\nSIGNATURE=$CHICAGO$",                      0,                           0,    0 },
114     { "[Version]\nSignature=$chicago$,abcd",                 0,                           0,    0 },
115     { "[Version]\nabc=def\nSignature=$chicago$",             0,                           0,    0 },
116     { "[Version]\nabc=def\n[Version]\nSignature=$chicago$",  0,                           0,    0 },
117     { STD_HEADER,                                            0,                           0,    0 },
118     { STD_HEADER "[]\r\n",                                   0,                           0,    0 },
119     { STD_HEADER "]\r\n",                                    0,                           0,    0 },
120     { STD_HEADER "[" A255 "]\r\n",                           0,                           0,    0 },
121     { STD_HEADER "[ab\r\n",                                  ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
122     { STD_HEADER "\n\n[ab\x1a]\n",                           ERROR_BAD_SECTION_NAME_LINE, 5,    0 },
123     { STD_HEADER "[" A256 "]\r\n",                           ERROR_SECTION_NAME_TOO_LONG, 3,    0 },
124     { "[abc]\n" STD_HEADER,                                  0,                           0,    0 },
125     { "abc\r\n" STD_HEADER,                                  ERROR_EXPECTED_SECTION_NAME, 1,    0 },
126     { ";\n;\nabc\r\n" STD_HEADER,                            ERROR_EXPECTED_SECTION_NAME, 3,    0 },
127     { ";\n;\nab\nab\n" STD_HEADER,                           ERROR_EXPECTED_SECTION_NAME, 3,    0 },
128     { ";aa\n;bb\n" STD_HEADER,                               0,                           0,    0 },
129     { STD_HEADER " [TestSection\x00] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
130     { STD_HEADER " [Test\x00Section] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
131     { STD_HEADER " [TestSection\x00] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
132     { STD_HEADER " [Test\x00Section] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
133 };
134
135 static void test_invalid_files(void)
136 {
137     unsigned int i;
138     UINT err_line;
139     HINF hinf;
140     DWORD err;
141
142     for (i = 0; i < sizeof(invalid_files)/sizeof(invalid_files[0]); i++)
143     {
144         SetLastError( 0xdeadbeef );
145         err_line = 0xdeadbeef;
146         hinf = test_file_contents( invalid_files[i].data, &err_line );
147         err = GetLastError();
148         trace( "hinf=%p err=0x%x line=%d\n", hinf, err, err_line );
149         if (invalid_files[i].error)  /* should fail */
150         {
151             ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i );
152             if (invalid_files[i].todo) todo_wine
153             {
154                 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
155                     i, err, invalid_files[i].error );
156                 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
157                     i, err_line, invalid_files[i].err_line );
158             }
159             else
160             {
161                 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
162                     i, err, invalid_files[i].error );
163                 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
164                     i, err_line, invalid_files[i].err_line );
165             }
166         }
167         else  /* should succeed */
168         {
169             ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i );
170             ok( err == 0, "file %u: Error code set to %u\n", i, err );
171         }
172         SetupCloseInfFile( hinf );
173     }
174 }
175
176
177 /* Test various section names */
178
179 static const struct
180 {
181     const char *data;
182     const char *section;
183     DWORD error;
184 } section_names[] =
185 {
186     /* file contents                              section name       error code */
187     { STD_HEADER "[TestSection]",                 "TestSection",         0 },
188     { STD_HEADER "[TestSection]\n",               "TestSection",         0 },
189     { STD_HEADER "[TESTSECTION]\r\n",             "TestSection",         0 },
190     { STD_HEADER "[TestSection]\n[abc]",          "testsection",         0 },
191     { STD_HEADER ";[TestSection]\n",              "TestSection",         ERROR_SECTION_NOT_FOUND },
192     { STD_HEADER "[TestSection]\n",               "Bad name",            ERROR_SECTION_NOT_FOUND },
193     /* spaces */
194     { STD_HEADER "[TestSection]   \r\n",          "TestSection",         0 },
195     { STD_HEADER "   [TestSection]\r\n",          "TestSection",         0 },
196     { STD_HEADER "   [TestSection]   dummy\r\n",  "TestSection",         0 },
197     { STD_HEADER "   [TestSection]   [foo]\r\n",  "TestSection",         0 },
198     { STD_HEADER " [  Test Section  ] dummy\r\n", "  Test Section  ",    0 },
199     { STD_HEADER "[TestSection] \032\ndummy",     "TestSection",         0 },
200     { STD_HEADER "[TestSection] \n\032dummy",     "TestSection",         0 },
201     /* special chars in section name */
202     { STD_HEADER "[Test[Section]\r\n",            "Test[Section",        0 },
203     { STD_HEADER "[Test[S]ection]\r\n",           "Test[S",              0 },
204     { STD_HEADER "[Test[[[Section]\r\n",          "Test[[[Section",      0 },
205     { STD_HEADER "[]\r\n",                        "",                    0 },
206     { STD_HEADER "[[[]\n",                        "[[",                  0 },
207     { STD_HEADER "[Test\"Section]\r\n",           "Test\"Section",       0 },
208     { STD_HEADER "[Test\\Section]\r\n",           "Test\\Section",       0 },
209     { STD_HEADER "[Test\\ Section]\r\n",          "Test\\ Section",      0 },
210     { STD_HEADER "[Test;Section]\r\n",            "Test;Section",        0 },
211     /* various control chars */
212     { STD_HEADER " [Test\r\b\tSection] \n",       "Test\r\b\tSection", 0 },
213     /* nulls */
214 };
215
216 static void test_section_names(void)
217 {
218     unsigned int i;
219     UINT err_line;
220     HINF hinf;
221     DWORD err;
222     LONG ret;
223
224     for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); i++)
225     {
226         SetLastError( 0xdeadbeef );
227         hinf = test_file_contents( section_names[i].data, &err_line );
228         ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
229         if (hinf == INVALID_HANDLE_VALUE) continue;
230
231         ret = SetupGetLineCountA( hinf, section_names[i].section );
232         err = GetLastError();
233         trace( "hinf=%p ret=%d err=0x%x\n", hinf, ret, err );
234         if (ret != -1)
235         {
236             ok( !section_names[i].error, "line %u: section name %s found\n",
237                 i, section_names[i].section );
238             ok( !err, "line %u: bad error code %u\n", i, err );
239         }
240         else
241         {
242             ok( section_names[i].error, "line %u: section name %s not found\n",
243                 i, section_names[i].section );
244             ok( err == section_names[i].error, "line %u: bad error %u/%u\n",
245                 i, err, section_names[i].error );
246         }
247         SetupCloseInfFile( hinf );
248     }
249 }
250
251 static void test_enum_sections(void)
252 {
253     static const char *contents = STD_HEADER "[s1]\nfoo=bar\n[s2]\nbar=foo\n[s3]\n[strings]\na=b\n";
254
255     BOOL ret;
256     DWORD len;
257     HINF hinf;
258     UINT err, index;
259     char buffer[256];
260
261     if (!pSetupEnumInfSectionsA)
262     {
263         win_skip( "SetupEnumInfSectionsA not available\n" );
264         return;
265     }
266
267     hinf = test_file_contents( contents, &err );
268     ok( hinf != NULL, "Expected valid INF file\n" );
269
270     for (index = 0; ; index++)
271     {
272         SetLastError( 0xdeadbeef );
273         ret = pSetupEnumInfSectionsA( hinf, index, NULL, 0, &len );
274         err = GetLastError();
275         if (!ret && GetLastError() == ERROR_NO_MORE_ITEMS) break;
276         ok( ret, "SetupEnumInfSectionsA failed\n" );
277         ok( len == 3 || len == 8, "wrong len %u\n", len );
278
279         SetLastError( 0xdeadbeef );
280         ret = pSetupEnumInfSectionsA( hinf, index, NULL, sizeof(buffer), &len );
281         err = GetLastError();
282         ok( !ret, "SetupEnumInfSectionsA succeeded\n" );
283         ok( err == ERROR_INVALID_USER_BUFFER, "wrong error %u\n", err );
284         ok( len == 3 || len == 8, "wrong len %u\n", len );
285
286         SetLastError( 0xdeadbeef );
287         ret = pSetupEnumInfSectionsA( hinf, index, buffer, sizeof(buffer), &len );
288         ok( ret, "SetupEnumInfSectionsA failed err %u\n", GetLastError() );
289         ok( len == 3 || len == 8, "wrong len %u\n", len );
290         ok( !lstrcmpi( buffer, "version" ) || !lstrcmpi( buffer, "s1" ) ||
291             !lstrcmpi( buffer, "s2" ) || !lstrcmpi( buffer, "s3" ) || !lstrcmpi( buffer, "strings" ),
292             "bad section '%s'\n", buffer );
293     }
294     SetupCloseInfFile( hinf );
295 }
296
297
298 /* Test various key and value names */
299
300 static const struct
301 {
302     const char *data;
303     const char *key;
304     const char *fields[10];
305 } key_names[] =
306 {
307 /* file contents          expected key       expected fields */
308  { "ab=cd",                "ab",            { "cd" } },
309  { "ab=cd,ef,gh,ij",       "ab",            { "cd", "ef", "gh", "ij" } },
310  { "ab",                   "ab",            { "ab" } },
311  { "ab,cd",                NULL,            { "ab", "cd" } },
312  { "ab,cd=ef",             NULL,            { "ab", "cd=ef" } },
313  { "=abcd,ef",             "",              { "abcd", "ef" } },
314  /* backslashes */
315  { "ba\\\ncd=ef",          "bacd",          { "ef" } },
316  { "ab  \\  \ncd=ef",      "abcd",          { "ef" } },
317  { "ab\\\ncd,ef",          NULL,            { "abcd", "ef" } },
318  { "ab  \\ ;cc\ncd=ef",    "abcd",          { "ef" } },
319  { "ab \\ \\ \ncd=ef",     "abcd",          { "ef" } },
320  { "ba \\ dc=xx",          "ba \\ dc",      { "xx" } },
321  { "ba \\\\ \nc=d",        "bac",           { "d" } },
322  { "a=b\\\\c",             "a",             { "b\\\\c" } },
323  { "ab=cd \\ ",            "ab",            { "cd" } },
324  { "ba=c \\ \n \\ \n a",   "ba",            { "ca" } },
325  { "ba=c \\ \n \\ a",      "ba",            { "c\\ a" } },
326  { "  \\ a= \\ b",         "\\ a",          { "\\ b" } },
327  /* quotes */
328  { "Ab\"Cd\"=Ef",          "AbCd",          { "Ef" } },
329  { "Ab\"Cd=Ef\"",          "AbCd=Ef",       { "AbCd=Ef" } },
330  { "ab\"\"\"cd,ef=gh\"",   "ab\"cd,ef=gh",  { "ab\"cd,ef=gh" } },
331  { "ab\"\"cd=ef",          "abcd",          { "ef" } },
332  { "ab\"\"cd=ef,gh",       "abcd",          { "ef", "gh" } },
333  { "ab=cd\"\"ef",          "ab",            { "cdef" } },
334  { "ab=cd\",\"ef",         "ab",            { "cd,ef" } },
335  { "ab=cd\",ef",           "ab",            { "cd,ef" } },
336  { "ab=cd\",ef\\\nab",     "ab",            { "cd,ef\\" } },
337
338  /* single quotes (unhandled)*/
339  { "HKLM,A,B,'C',D",       NULL,            { "HKLM", "A","B","'C'","D" } },
340  /* spaces */
341  { " a b = c , d \n",      "a b",           { "c", "d" } },
342  { " a b = c ,\" d\" \n",  "a b",           { "c", " d" } },
343  { " a b\r = c\r\n",       "a b",           { "c" } },
344  /* empty fields */
345  { "a=b,,,c,,,d",          "a",             { "b", "", "", "c", "", "", "d" } },
346  { "a=b,\"\",c,\" \",d",   "a",             { "b", "", "c", " ", "d" } },
347  { "=,,b",                 "",              { "", "", "b" } },
348  { ",=,,b",                NULL,            { "", "=", "", "b" } },
349  { "a=\n",                 "a",             { "" } },
350  { "=",                    "",              { "" } },
351  /* eof */
352  { "ab=c\032d",            "ab",            { "c" } },
353  { "ab\032=cd",            "ab",            { "ab" } },
354  /* nulls */
355  { "abcd=ef\x0gh",         "abcd",          { "ef" } },
356  /* multiple sections with same name */
357  { "[Test2]\nab\n[Test]\nee=ff\n",  "ee",    { "ff" } },
358  /* string substitution */
359  { "%foo%=%bar%\n" STR_SECTION,     "aaa",   { "bbb" } },
360  { "%foo%xx=%bar%yy\n" STR_SECTION, "aaaxx", { "bbbyy" } },
361  { "%% %foo%=%bar%\n" STR_SECTION,  "% aaa", { "bbb" } },
362  { "%f\"o\"o%=ccc\n" STR_SECTION,   "aaa",   { "ccc" } },
363  { "abc=%bar;bla%\n" STR_SECTION,   "abc",   { "%bar" } },
364  { "loop=%loop%\n" STR_SECTION,     "loop",  { "%loop2%" } },
365  { "%per%%cent%=100\n" STR_SECTION, "12",    { "100" } },
366  { "a=%big%\n" STR_SECTION,         "a",     { A400 } },
367  { "a=%verybig%\n" STR_SECTION,     "a",     { A511 } },  /* truncated to 511, not on Vista/W2K8 */
368  { "a=%big%%big%%big%%big%\n" STR_SECTION,   "a", { A400 A400 A400 A400 } },
369  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION,   "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } },
370  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION,   "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } },
371
372  /* Prove expansion of system entries removes extra \'s and string
373     replacements doesn't                                            */
374  { "ab=\"%24%\"\n" STR_SECTION,           "ab", { "C:\\" } },
375  { "ab=\"%mydrive%\"\n" STR_SECTION,      "ab", { "C:\\" } },
376  { "ab=\"%24%\\fred\"\n" STR_SECTION,     "ab", { "C:\\fred" } },
377  { "ab=\"%mydrive%\\fred\"\n" STR_SECTION,"ab", { "C:\\\\fred" } },
378  /* Confirm duplicate \'s kept */
379  { "ab=\"%24%\\\\fred\"",      "ab",            { "C:\\\\fred" } },
380  { "ab=C:\\\\FRED",            "ab",            { "C:\\\\FRED" } },
381 };
382
383 /* check the key of a certain line */
384 static const char *check_key( INFCONTEXT *context, const char *wanted )
385 {
386     const char *key = get_string_field( context, 0 );
387     DWORD err = GetLastError();
388
389     if (!key)
390     {
391         ok( !wanted, "missing key %s\n", wanted );
392         ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %u\n", err );
393     }
394     else
395     {
396         ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
397         ok( err == 0, "last error set to %u\n", err );
398     }
399     return key;
400 }
401
402 static void test_key_names(void)
403 {
404     char buffer[MAX_INF_STRING_LENGTH+32];
405     const char *key, *line;
406     unsigned int i, index, count;
407     UINT err_line;
408     HINF hinf;
409     DWORD err;
410     BOOL ret;
411     INFCONTEXT context;
412
413     for (i = 0; i < sizeof(key_names)/sizeof(key_names[0]); i++)
414     {
415         strcpy( buffer, STD_HEADER "[Test]\n" );
416         strcat( buffer, key_names[i].data );
417         SetLastError( 0xdeadbeef );
418         hinf = test_file_contents( buffer, &err_line );
419         ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
420         if (hinf == INVALID_HANDLE_VALUE) continue;
421
422         ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
423         assert( ret );
424
425         key = check_key( &context, key_names[i].key );
426
427         buffer[0] = buffer[1] = 0;  /* build the full line */
428         for (index = 0; ; index++)
429         {
430             const char *field = get_string_field( &context, index + 1 );
431             err = GetLastError();
432             if (field)
433             {
434                 ok( err == 0, "line %u: bad error %u\n", i, err );
435                 if (key_names[i].fields[index])
436                 {
437                     if (i == 49)
438                         ok( !strcmp( field, key_names[i].fields[index] ) ||
439                             !strcmp( field, A1200), /* Vista, W2K8 */
440                             "line %u: bad field %s/%s\n",
441                             i, field, key_names[i].fields[index] );
442                     else
443                         ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n",
444                             i, field, key_names[i].fields[index] );
445                 }
446                 else
447                     ok( 0, "line %u: got extra field %s\n", i, field );
448                 strcat( buffer, "," );
449                 strcat( buffer, field );
450             }
451             else
452             {
453                 ok( err == 0 || err == ERROR_INVALID_PARAMETER,
454                     "line %u: bad error %u\n", i, err );
455                 if (key_names[i].fields[index])
456                     ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
457             }
458             if (!key_names[i].fields[index]) break;
459         }
460         count = SetupGetFieldCount( &context );
461         ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
462
463         line = get_line_text( &context );
464         ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
465         if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
466
467         SetupCloseInfFile( hinf );
468     }
469
470 }
471
472 static void test_close_inf_file(void)
473 {
474     SetLastError(0xdeadbeef);
475     SetupCloseInfFile(NULL);
476     ok(GetLastError() == 0xdeadbeef ||
477         GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
478         "Expected 0xdeadbeef, got %u\n", GetLastError());
479
480     SetLastError(0xdeadbeef);
481     SetupCloseInfFile(INVALID_HANDLE_VALUE);
482     ok(GetLastError() == 0xdeadbeef ||
483         GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
484         "Expected 0xdeadbeef, got %u\n", GetLastError());
485 }
486
487 static const char *contents = "[Version]\n"
488                               "Signature=\"$Windows NT$\"\n"
489                               "FileVersion=5.1.1.2\n"
490                               "[FileBranchInfo]\n"
491                               "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n"
492                               "[Strings]\n"
493                               "RTMQFE_NAME = \"RTMQFE\"\n";
494
495 static const WCHAR getfield_res[][20] =
496 {
497     {'R','T','M','Q','F','E',0},
498     {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
499     {'S','P','1','R','T','M',0},
500 };
501
502 static void test_pSetupGetField(void)
503 {
504     UINT err;
505     BOOL ret;
506     HINF hinf;
507     LPCWSTR field;
508     INFCONTEXT context;
509     int i;
510     int len;
511
512     hinf = test_file_contents( contents, &err );
513     ok( hinf != NULL, "Expected valid INF file\n" );
514
515     ret = SetupFindFirstLine( hinf, "FileBranchInfo", NULL, &context );
516     ok( ret, "Failed to find first line\n" );
517
518     /* native Windows crashes if a NULL context is sent in */
519
520     for ( i = 0; i < 3; i++ )
521     {
522         field = pSetupGetField( &context, i );
523         ok( field != NULL, "Failed to get field %i\n", i );
524         ok( !lstrcmpW( getfield_res[i], field ), "Wrong string returned\n" );
525     }
526
527     field = pSetupGetField( &context, 3 );
528     ok( field != NULL, "Failed to get field 3\n" );
529     len = lstrlenW( field );
530     ok( len == 511 /* NT4, W2K, XP and W2K3 */ ||
531         len == 4096 /* Vista */ ||
532         len == 256 /* Win9x and WinME */,
533         "Unexpected length, got %d\n", len );
534
535     field = pSetupGetField( &context, 4 );
536     ok( field == NULL, "Expected NULL, got %p\n", field );
537     ok( GetLastError() == ERROR_INVALID_PARAMETER,
538         "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
539
540     SetupCloseInfFile( hinf );
541 }
542
543 static void test_SetupGetIntField(void)
544 {
545     static const struct
546     {
547         const char *key;
548         const char *fields;
549         DWORD index;
550         INT value;
551         DWORD err;
552     } keys[] =
553     {
554     /* key     fields            index   expected int  errorcode */
555     {  "Key=", "48",             1,      48,           ERROR_SUCCESS },
556     {  "Key=", "48",             0,      -1,           ERROR_INVALID_DATA },
557     {  "123=", "48",             0,      123,          ERROR_SUCCESS },
558     {  "Key=", "0x4",            1,      4,            ERROR_SUCCESS },
559     {  "Key=", "Field1",         1,      -1,           ERROR_INVALID_DATA },
560     {  "Key=", "Field1,34",      2,      34,           ERROR_SUCCESS },
561     {  "Key=", "Field1,,Field3", 2,      0,            ERROR_SUCCESS },
562     {  "Key=", "Field1,",        2,      0,            ERROR_SUCCESS }
563     };
564     unsigned int i;
565
566     for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++)
567     {
568         HINF hinf;
569         char buffer[MAX_INF_STRING_LENGTH];
570         INFCONTEXT context;
571         UINT err;
572         BOOL retb;
573         INT intfield;
574
575         strcpy( buffer, STD_HEADER "[TestSection]\n" );
576         strcat( buffer, keys[i].key );
577         strcat( buffer, keys[i].fields );
578         hinf = test_file_contents( buffer, &err);
579         ok( hinf != NULL, "Expected valid INF file\n" );
580
581         SetupFindFirstLineA( hinf, "TestSection", "Key", &context );
582         SetLastError( 0xdeadbeef );
583         intfield = -1;
584         retb = SetupGetIntField( &context, keys[i].index, &intfield );
585         if ( keys[i].err == ERROR_SUCCESS )
586         {
587             ok( retb, "Expected success\n" );
588             ok( GetLastError() == ERROR_SUCCESS ||
589                 GetLastError() == 0xdeadbeef /* win9x, NT4 */,
590                 "Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", GetLastError() );
591         }
592         else
593         {
594             ok( !retb, "Expected failure\n" );
595             ok( GetLastError() == keys[i].err,
596                 "Expected %d, got %u\n", keys[i].err, GetLastError() );
597         }
598         ok( intfield == keys[i].value, "Expected %d, got %d\n", keys[i].value, intfield );
599
600         SetupCloseInfFile( hinf );
601     }
602 }
603
604 static void test_GLE(void)
605 {
606     static const char *inf =
607         "[Version]\n"
608         "Signature=\"$Windows NT$\"\n"
609         "[Sectionname]\n"
610         "Keyname1=Field1,Field2,Field3\n"
611         "\n"
612         "Keyname2=Field4,Field5\n";
613     HINF hinf;
614     UINT err;
615     INFCONTEXT context;
616     BOOL retb;
617     LONG retl;
618     char buf[MAX_INF_STRING_LENGTH];
619     int bufsize = MAX_INF_STRING_LENGTH;
620     DWORD retsize;
621
622     hinf = test_file_contents( inf, &err );
623     ok( hinf != NULL, "Expected valid INF file\n" );
624
625     SetLastError(0xdeadbeef);
626     retb = SetupFindFirstLineA( hinf, "ImNotThere", NULL, &context );
627     ok(!retb, "Expected failure\n");
628     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
629         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
630
631     SetLastError(0xdeadbeef);
632     retb = SetupFindFirstLineA( hinf, "ImNotThere", "ImNotThere", &context );
633     ok(!retb, "Expected failure\n");
634     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
635         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
636
637     SetLastError(0xdeadbeef);
638     retb = SetupFindFirstLineA( hinf, "Sectionname", NULL, &context );
639     ok(retb, "Expected success\n");
640     ok(GetLastError() == ERROR_SUCCESS,
641         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
642
643     SetLastError(0xdeadbeef);
644     retb = SetupFindFirstLineA( hinf, "Sectionname", "ImNotThere", &context );
645     ok(!retb, "Expected failure\n");
646     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
647         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
648
649     SetLastError(0xdeadbeef);
650     retb = SetupFindFirstLineA( hinf, "Sectionname", "Keyname1", &context );
651     ok(retb, "Expected success\n");
652     ok(GetLastError() == ERROR_SUCCESS,
653         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
654
655     SetLastError(0xdeadbeef);
656     retb = SetupFindNextMatchLineA( &context, "ImNotThere", &context );
657     ok(!retb, "Expected failure\n");
658     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
659         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
660
661     SetLastError(0xdeadbeef);
662     retb = SetupFindNextMatchLineA( &context, "Keyname2", &context );
663     ok(retb, "Expected success\n");
664     ok(GetLastError() == ERROR_SUCCESS,
665         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
666
667     SetLastError(0xdeadbeef);
668     retl = SetupGetLineCountA( hinf, "ImNotThere");
669     ok(retl == -1, "Expected -1, got %d\n", retl);
670     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
671         "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
672
673     SetLastError(0xdeadbeef);
674     retl = SetupGetLineCountA( hinf, "Sectionname");
675     ok(retl == 2, "Expected 2, got %d\n", retl);
676     ok(GetLastError() == ERROR_SUCCESS,
677         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
678
679     SetLastError(0xdeadbeef);
680     retb = SetupGetLineTextA( NULL, hinf, "ImNotThere", "ImNotThere", buf, bufsize, &retsize);
681     ok(!retb, "Expected failure\n");
682     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
683         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
684
685     SetLastError(0xdeadbeef);
686     retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "ImNotThere", buf, bufsize, &retsize);
687     ok(!retb, "Expected failure\n");
688     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
689         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
690
691     SetLastError(0xdeadbeef);
692     retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "Keyname1", buf, bufsize, &retsize);
693     ok(retb, "Expected success\n");
694     ok(GetLastError() == ERROR_SUCCESS,
695         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
696
697     SetLastError(0xdeadbeef);
698     retb = SetupGetLineByIndexA( hinf, "ImNotThere", 1, &context );
699     ok(!retb, "Expected failure\n");
700     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
701         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
702
703     SetLastError(0xdeadbeef);
704     retb = SetupGetLineByIndexA( hinf, "Sectionname", 1, &context );
705     ok(retb, "Expected success\n");
706     ok(GetLastError() == ERROR_SUCCESS,
707         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
708
709     SetLastError(0xdeadbeef);
710     retb = SetupGetLineByIndexA( hinf, "Sectionname", 3, &context );
711     ok(!retb, "Expected failure\n");
712     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
713         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
714
715     SetupCloseInfFile( hinf );
716 }
717
718 START_TEST(parser)
719 {
720     init_function_pointers();
721     test_invalid_files();
722     test_section_names();
723     test_enum_sections();
724     test_key_names();
725     test_close_inf_file();
726     test_pSetupGetField();
727     test_SetupGetIntField();
728     test_GLE();
729     DeleteFileA( tmpfilename );
730 }