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 */
33 static HMODULE hSetupAPI;
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 
init_function_pointers(void)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 */
test_file_contents(const char * data,UINT * err_line)74 static HINF test_file_contents( const char *data, UINT *err_line )
75 {
76     DWORD res;
77     HANDLE handle = CreateFileA( tmpfilename, GENERIC_READ|GENERIC_WRITE,
78                                  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
79     if (handle == INVALID_HANDLE_VALUE) return 0;
80     if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" );
81     CloseHandle( handle );
82     return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line );
83 }
84 
get_string_field(INFCONTEXT * context,DWORD index)85 static const char *get_string_field( INFCONTEXT *context, DWORD index )
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 
get_line_text(INFCONTEXT * context)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;
105     DWORD error;
106     UINT err_line;
107     BOOL todo;
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 
test_invalid_files(void)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;
162         hinf = test_file_contents( invalid_files[i].data, &err_line );
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 );
168             todo_wine_if (invalid_files[i].todo)
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",
173                     i, err_line, invalid_files[i].err_line );
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 
test_section_names(void)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 );
236         hinf = test_file_contents( section_names[i].data, &err_line );
237         ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
238         if (hinf == INVALID_HANDLE_VALUE) continue;
239 
240         ret = SetupGetLineCountA( hinf, section_names[i].section );
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 
test_enum_sections(void)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 */
check_key(INFCONTEXT * context,const char * wanted)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 
test_key_names(void)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;
420     INFCONTEXT context;
421 
422     for (i = 0; i < ARRAY_SIZE(key_names); i++)
423     {
424         strcpy( buffer, STD_HEADER "[Test]\n" );
425         strcat( buffer, key_names[i].data );
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         }
484         count = SetupGetFieldCount( &context );
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 
test_close_inf_file(void)496 static void test_close_inf_file(void)
497 {
498     SetLastError(0xdeadbeef);
499     SetupCloseInfFile(NULL);
500     ok(GetLastError() == 0xdeadbeef ||
501         GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
502         "Expected 0xdeadbeef, got %u\n", GetLastError());
503 
504     SetLastError(0xdeadbeef);
505     SetupCloseInfFile(INVALID_HANDLE_VALUE);
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 
test_pSetupGetField(void)533 static void test_pSetupGetField(void)
534 {
535     UINT err;
536     BOOL ret;
537     HINF hinf;
538     LPCSTR fieldA;
539     LPCWSTR fieldW;
540     INFCONTEXT context;
541     int i;
542     int len;
543     BOOL unicode = TRUE;
544 
545     SetLastError(0xdeadbeef);
546     lstrcmpW(NULL, NULL);
547     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
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 );
588         ok( GetLastError() == ERROR_INVALID_PARAMETER,
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 );
601         ok( GetLastError() == ERROR_INVALID_PARAMETER,
602             "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
603     }
604 
605     SetupCloseInfFile( hinf );
606 }
607 
test_SetupGetIntField(void)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;
634         char buffer[MAX_INF_STRING_LENGTH];
635         INFCONTEXT context;
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 
test_GLE(void)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;
681     INFCONTEXT context;
682     BOOL retb;
683     LONG retl;
684     char buf[MAX_INF_STRING_LENGTH];
685     int bufsize = MAX_INF_STRING_LENGTH;
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");
694     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
700     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
706     ok(GetLastError() == ERROR_SUCCESS,
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");
712     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
718     ok(GetLastError() == ERROR_SUCCESS,
719         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
720 
721     SetLastError(0xdeadbeef);
722     retb = SetupFindNextMatchLineA( &context, "ImNotThere", &context );
723     ok(!retb, "Expected failure\n");
724     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
730     ok(GetLastError() == ERROR_SUCCESS,
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);
736     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
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);
742     ok(GetLastError() == ERROR_SUCCESS,
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");
748     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
754     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
760     ok(GetLastError() == ERROR_SUCCESS,
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");
766     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
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");
772     ok(GetLastError() == ERROR_SUCCESS,
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");
778     ok(GetLastError() == ERROR_LINE_NOT_FOUND,
779         "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
780 
781     SetupCloseInfFile( hinf );
782 }
783 
START_TEST(parser)784 START_TEST(parser)
785 {
786     init_function_pointers();
787     test_invalid_files();
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();
795     DeleteFileA( tmpfilename );
796 }
797