xactengine3_7: Map IXACT3Wave interfaces.
[wine.git] / dlls / setupapi / tests / parser.c
blob7c58acdc362104504fd5a4abba2e6c72e1de982f
1 /*
2 * INF file parsing tests
4 * Copyright 2002, 2005 Alexandre Julliard for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "setupapi.h"
30 #include "wine/test.h"
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 );
38 static void init_function_pointers(void)
40 hSetupAPI = GetModuleHandleA("setupapi.dll");
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" );
49 static const char tmpfilename[] = ".\\tmp.inf";
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
65 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
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"
73 /* create a new file with specified contents and open it */
74 static HINF test_file_contents( const char *data, int size, UINT *err_line )
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, size, &res, NULL )) trace( "write error\n" );
81 CloseHandle( handle );
82 return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line );
85 static const char *get_string_field( INFCONTEXT *context, DWORD index )
87 static char buffer[MAX_INF_STRING_LENGTH+32];
88 if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
89 return NULL;
92 static const char *get_line_text( INFCONTEXT *context )
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;
100 /* Test various valid/invalid file formats */
102 static const struct
104 const char *data;
105 int data_size;
106 DWORD error;
107 UINT err_line;
108 BOOL todo;
109 } invalid_files[] =
111 #define C(s) s, sizeof(s)-1
112 /* file contents expected error (or 0) errline todo */
113 { C("\r\n"), ERROR_WRONG_INF_STYLE, 0, FALSE },
114 { C("abcd\r\n"), ERROR_WRONG_INF_STYLE, 0, TRUE },
115 { C("[Version]\r\n"), ERROR_WRONG_INF_STYLE, 0, FALSE },
116 { C("[Version]\nSignature="), ERROR_WRONG_INF_STYLE, 0, FALSE },
117 { C("[Version]\nSignature=foo"), ERROR_WRONG_INF_STYLE, 0, FALSE },
118 { C("[version]\nsignature=$chicago$"), 0, 0, FALSE },
119 { C("[VERSION]\nSIGNATURE=$CHICAGO$"), 0, 0, FALSE },
120 { C("[Version]\nSignature=$chicago$,abcd"), 0, 0, FALSE },
121 { C("[Version]\nabc=def\nSignature=$chicago$"), 0, 0, FALSE },
122 { C("[Version]\nabc=def\n[Version]\nSignature=$chicago$"), 0, 0, FALSE },
123 { C(STD_HEADER), 0, 0, FALSE },
124 { C(STD_HEADER "[]\r\n"), 0, 0, FALSE },
125 { C(STD_HEADER "]\r\n"), 0, 0, FALSE },
126 { C(STD_HEADER "[" A255 "]\r\n"), 0, 0, FALSE },
127 { C(STD_HEADER "[ab\r\n"), ERROR_BAD_SECTION_NAME_LINE, 3, FALSE },
128 { C(STD_HEADER "\n\n[ab\x1a]\n"), ERROR_BAD_SECTION_NAME_LINE, 5, FALSE },
129 { C(STD_HEADER "[" A256 "]\r\n"), ERROR_SECTION_NAME_TOO_LONG, 3, FALSE },
130 { C("[abc]\n" STD_HEADER), 0, 0, FALSE },
131 { C("abc\r\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
132 { C(";\n;\nabc\r\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 3, FALSE },
133 { C(";\n;\nab\nab\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 3, FALSE },
134 { C(";aa\n;bb\n" STD_HEADER), 0, 0, FALSE },
135 { C(STD_HEADER " [TestSection\x00]\n"), 0, 0, TRUE },
136 { C(STD_HEADER " [Test\x00Section]\n"), 0, 0, TRUE },
137 { C(STD_HEADER " [TestSection\x00]\n"), 0, 0, TRUE },
138 { C(STD_HEADER " [Test\x00Section]\n"), 0, 0, TRUE },
139 { C("garbage1\ngarbage2\n[abc]\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
140 { C("garbage1\ngarbage2\n[Strings]\n" STD_HEADER), 0, 0, FALSE },
141 { C(";comment\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
142 { C(";comment\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER), 0, 0, FALSE },
143 { C(" \t\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER), ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
144 { C(" \t\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER), 0, 0, FALSE },
145 { C("garbage1\ngarbage2\n" STD_HEADER "[abc]\n"), ERROR_EXPECTED_SECTION_NAME, 1, FALSE },
146 { C("garbage1\ngarbage2\n" STD_HEADER "[Strings]\n"), 0, 0, FALSE },
147 { C(";comment\ngarbage1\ngarbage2\n" STD_HEADER "[abc]\n"), ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
148 { C(";comment\ngarbage1\ngarbage2\n" STD_HEADER "[Strings]\n"), 0, 0, FALSE },
149 { C(" \t\ngarbage1\ngarbage2\n" STD_HEADER "[abc]\n"), ERROR_EXPECTED_SECTION_NAME, 2, FALSE },
150 { C(" \t\ngarbage1\ngarbage2\n" STD_HEADER "[Strings]\n"), 0, 0, FALSE },
151 #undef C
154 static void test_invalid_files(void)
156 unsigned int i;
157 UINT err_line;
158 HINF hinf;
159 DWORD err;
161 for (i = 0; i < ARRAY_SIZE(invalid_files); i++)
163 SetLastError( 0xdeadbeef );
164 err_line = 0xdeadbeef;
165 hinf = test_file_contents( invalid_files[i].data, invalid_files[i].data_size, &err_line );
166 err = GetLastError();
167 trace( "hinf=%p err=0x%lx line=%d\n", hinf, err, err_line );
168 if (invalid_files[i].error) /* should fail */
170 ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i );
171 todo_wine_if (invalid_files[i].todo)
173 ok( err == invalid_files[i].error, "file %u: Bad error %lu/%lu\n",
174 i, err, invalid_files[i].error );
175 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
176 i, err_line, invalid_files[i].err_line );
179 else /* should succeed */
181 todo_wine_if (invalid_files[i].todo)
183 ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i );
184 ok( err == 0, "file %u: Error code set to %lu\n", i, err );
187 SetupCloseInfFile( hinf );
192 /* Test various section names */
194 static const struct
196 const char *data;
197 const char *section;
198 DWORD error;
199 } section_names[] =
201 /* file contents section name error code */
202 { STD_HEADER "[TestSection]", "TestSection", 0 },
203 { STD_HEADER "[TestSection]\n", "TestSection", 0 },
204 { STD_HEADER "[TESTSECTION]\r\n", "TestSection", 0 },
205 { STD_HEADER "[TestSection]\n[abc]", "testsection", 0 },
206 { STD_HEADER ";[TestSection]\n", "TestSection", ERROR_SECTION_NOT_FOUND },
207 { STD_HEADER "[TestSection]\n", "Bad name", ERROR_SECTION_NOT_FOUND },
208 /* spaces */
209 { STD_HEADER "[TestSection] \r\n", "TestSection", 0 },
210 { STD_HEADER " [TestSection]\r\n", "TestSection", 0 },
211 { STD_HEADER " [TestSection] dummy\r\n", "TestSection", 0 },
212 { STD_HEADER " [TestSection] [foo]\r\n", "TestSection", 0 },
213 { STD_HEADER " [ Test Section ] dummy\r\n", " Test Section ", 0 },
214 { STD_HEADER "[TestSection] \032\ndummy", "TestSection", 0 },
215 { STD_HEADER "[TestSection] \n\032dummy", "TestSection", 0 },
216 /* special chars in section name */
217 { STD_HEADER "[Test[Section]\r\n", "Test[Section", 0 },
218 { STD_HEADER "[Test[S]ection]\r\n", "Test[S", 0 },
219 { STD_HEADER "[Test[[[Section]\r\n", "Test[[[Section", 0 },
220 { STD_HEADER "[]\r\n", "", 0 },
221 { STD_HEADER "[[[]\n", "[[", 0 },
222 { STD_HEADER "[Test\"Section]\r\n", "Test\"Section", 0 },
223 { STD_HEADER "[Test\\Section]\r\n", "Test\\Section", 0 },
224 { STD_HEADER "[Test\\ Section]\r\n", "Test\\ Section", 0 },
225 { STD_HEADER "[Test;Section]\r\n", "Test;Section", 0 },
226 /* various control chars */
227 { STD_HEADER " [Test\r\b\tSection] \n", "Test\r\b\tSection", 0 },
228 /* nulls */
231 static void test_section_names(void)
233 unsigned int i;
234 UINT err_line;
235 HINF hinf;
236 DWORD err;
237 LONG ret;
239 for (i = 0; i < ARRAY_SIZE(section_names); i++)
241 SetLastError( 0xdeadbeef );
242 hinf = test_file_contents( section_names[i].data, strlen(section_names[i].data), &err_line );
243 ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %lu\n", i, GetLastError() );
244 if (hinf == INVALID_HANDLE_VALUE) continue;
246 ret = SetupGetLineCountA( hinf, section_names[i].section );
247 err = GetLastError();
248 trace( "hinf=%p ret=%ld err=0x%lx\n", hinf, ret, err );
249 if (ret != -1)
251 ok( !section_names[i].error, "line %u: section name %s found\n",
252 i, section_names[i].section );
253 ok( !err, "line %u: bad error code %lu\n", i, err );
255 else
257 ok( section_names[i].error, "line %u: section name %s not found\n",
258 i, section_names[i].section );
259 ok( err == section_names[i].error, "line %u: bad error %lu/%lu\n",
260 i, err, section_names[i].error );
262 SetupCloseInfFile( hinf );
266 static void test_enum_sections(void)
268 static const char *contents = STD_HEADER "[s1]\nfoo=bar\n[s2]\nbar=foo\n[s3]\n[strings]\na=b\n";
270 BOOL ret;
271 HINF hinf;
272 UINT err, index, len;
273 char buffer[256];
275 if (!pSetupEnumInfSectionsA)
277 win_skip( "SetupEnumInfSectionsA not available\n" );
278 return;
281 hinf = test_file_contents( contents, strlen(contents), &err );
282 ok( hinf != NULL, "Expected valid INF file\n" );
284 for (index = 0; ; index++)
286 SetLastError( 0xdeadbeef );
287 ret = pSetupEnumInfSectionsA( hinf, index, NULL, 0, &len );
288 err = GetLastError();
289 if (!ret && GetLastError() == ERROR_NO_MORE_ITEMS) break;
290 ok( ret, "SetupEnumInfSectionsA failed\n" );
291 ok( len == 3 || len == 8, "wrong len %u\n", len );
293 SetLastError( 0xdeadbeef );
294 ret = pSetupEnumInfSectionsA( hinf, index, NULL, sizeof(buffer), &len );
295 err = GetLastError();
296 ok( !ret, "SetupEnumInfSectionsA succeeded\n" );
297 ok( err == ERROR_INVALID_USER_BUFFER, "wrong error %u\n", err );
298 ok( len == 3 || len == 8, "wrong len %u\n", len );
300 SetLastError( 0xdeadbeef );
301 ret = pSetupEnumInfSectionsA( hinf, index, buffer, sizeof(buffer), &len );
302 ok( ret, "SetupEnumInfSectionsA failed err %lu\n", GetLastError() );
303 ok( len == 3 || len == 8, "wrong len %u\n", len );
304 ok( !lstrcmpiA( buffer, "version" ) || !lstrcmpiA( buffer, "s1" ) ||
305 !lstrcmpiA( buffer, "s2" ) || !lstrcmpiA( buffer, "s3" ) || !lstrcmpiA( buffer, "strings" ),
306 "bad section '%s'\n", buffer );
308 SetupCloseInfFile( hinf );
312 /* Test various key and value names */
314 static const struct
316 const char *data;
317 int data_size;
318 const char *key;
319 const char *fields[10];
320 } key_names[] =
322 #define C(s) s, sizeof(s)-1
323 /* file contents expected key expected fields */
324 { C("ab=cd"), "ab", { "cd" } },
325 { C("ab=cd,ef,gh,ij"), "ab", { "cd", "ef", "gh", "ij" } },
326 { C("ab"), "ab", { "ab" } },
327 { C("ab,cd"), NULL, { "ab", "cd" } },
328 { C("ab,cd=ef"), NULL, { "ab", "cd=ef" } },
329 { C("=abcd,ef"), "", { "abcd", "ef" } },
330 /* backslashes */
331 { C("ba\\\ncd=ef"), "bacd", { "ef" } },
332 { C("ab \\ \ncd=ef"), "abcd", { "ef" } },
333 { C("ab\\\ncd,ef"), NULL, { "abcd", "ef" } },
334 { C("ab \\ ;cc\ncd=ef"), "abcd", { "ef" } },
335 { C("ab \\ \\ \ncd=ef"), "abcd", { "ef" } },
336 { C("ba \\ dc=xx"), "ba \\ dc", { "xx" } },
337 { C("ba \\\\ \nc=d"), "bac", { "d" } },
338 { C("a=b\\\\c"), "a", { "b\\\\c" } },
339 { C("ab=cd \\ "), "ab", { "cd" } },
340 { C("ba=c \\ \n \\ \n a"), "ba", { "ca" } },
341 { C("ba=c \\ \n \\ a"), "ba", { "c\\ a" } },
342 { C(" \\ a= \\ b"), "\\ a", { "\\ b" } },
343 /* quotes */
344 { C("Ab\"Cd\"=Ef"), "AbCd", { "Ef" } },
345 { C("Ab\"Cd=Ef\""), "AbCd=Ef", { "AbCd=Ef" } },
346 { C("ab\"\"\"cd,ef=gh\""), "ab\"cd,ef=gh", { "ab\"cd,ef=gh" } },
347 { C("ab\"\"cd=ef"), "abcd", { "ef" } },
348 { C("ab\"\"cd=ef,gh"), "abcd", { "ef", "gh" } },
349 { C("ab=cd\"\"ef"), "ab", { "cdef" } },
350 { C("ab=cd\",\"ef"), "ab", { "cd,ef" } },
351 { C("ab=cd\",ef"), "ab", { "cd,ef" } },
352 { C("ab=cd\",ef\\\nab"), "ab", { "cd,ef\\" } },
354 /* single quotes (unhandled)*/
355 { C("HKLM,A,B,'C',D"), NULL, { "HKLM", "A","B","'C'","D" } },
356 /* spaces */
357 { C(" a b = c , d \n"), "a b", { "c", "d" } },
358 { C(" a b = c ,\" d\" \n"), "a b", { "c", " d" } },
359 { C(" a b\r = c\r\n"), "a b", { "c" } },
360 /* empty fields */
361 { C("a=b,,,c,,,d"), "a", { "b", "", "", "c", "", "", "d" } },
362 { C("a=b,\"\",c,\" \",d"), "a", { "b", "", "c", " ", "d" } },
363 { C("=,,b"), "", { "", "", "b" } },
364 { C(",=,,b"), NULL, { "", "=", "", "b" } },
365 { C("a=\n"), "a", { "" } },
366 { C("="), "", { "" } },
367 /* eof */
368 { C("ab=c\032d"), "ab", { "c" } },
369 { C("ab\032=cd"), "ab", { "ab" } },
370 /* nulls */
371 { C("abcd=ef\x0gh"), "abcd", { "ef gh" } },
372 { C("foo=%bar%\n[Strings]\nbar=bbb\0\n"), "foo", { "bbb" } },
373 { C("foo=%bar%\n[Strings]\nbar=bbb \0\n"), "foo", { "bbb" } },
374 { C("foo=%bar%\n[Strings]\nbar=aaa\0bbb \0\n"), "foo", { "aaa bbb" } },
375 /* multiple sections with same name */
376 { C("[Test2]\nab\n[Test]\nee=ff\n"), "ee", { "ff" } },
377 /* string substitution */
378 { C("%foo%=%bar%\n" STR_SECTION), "aaa", { "bbb" } },
379 { C("%foo%xx=%bar%yy\n" STR_SECTION), "aaaxx", { "bbbyy" } },
380 { C("%% %foo%=%bar%\n" STR_SECTION), "% aaa", { "bbb" } },
381 { C("%f\"o\"o%=ccc\n" STR_SECTION), "aaa", { "ccc" } },
382 { C("abc=%bar;bla%\n" STR_SECTION), "abc", { "%bar" } },
383 { C("loop=%loop%\n" STR_SECTION), "loop", { "%loop2%" } },
384 { C("%per%%cent%=100\n" STR_SECTION), "12", { "100" } },
385 { C("a=%big%\n" STR_SECTION), "a", { A400 } },
386 { C("a=%verybig%\n" STR_SECTION), "a", { A511 } }, /* truncated to 511, not on Vista/W2K8 */
387 { C("a=%big%%big%%big%%big%\n" STR_SECTION), "a", { A400 A400 A400 A400 } },
388 { C("a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION), "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } },
389 { C("a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION), "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } },
391 /* Prove expansion of system entries removes extra \'s and string
392 replacements doesn't */
393 { C("ab=\"%24%\"\n" STR_SECTION), "ab", { "C:\\" } },
394 { C("ab=\"%mydrive%\"\n" STR_SECTION), "ab", { "C:\\" } },
395 { C("ab=\"%24%\\fred\"\n" STR_SECTION), "ab", { "C:\\fred" } },
396 { C("ab=\"%mydrive%\\fred\"\n" STR_SECTION),"ab", { "C:\\\\fred" } },
397 /* Confirm duplicate \'s kept */
398 { C("ab=\"%24%\\\\fred\""), "ab", { "C:\\\\fred" } },
399 { C("ab=C:\\\\FRED"), "ab", { "C:\\\\FRED" } },
402 /* check the key of a certain line */
403 static const char *check_key( INFCONTEXT *context, const char *wanted )
405 const char *key = get_string_field( context, 0 );
406 DWORD err = GetLastError();
408 if (!key)
410 ok( !wanted, "missing key %s\n", wanted );
411 ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %lu\n", err );
413 else
415 ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
416 ok( err == 0, "last error set to %lu\n", err );
418 return key;
421 static void test_key_names(void)
423 char buffer[MAX_INF_STRING_LENGTH+32];
424 const char *line;
425 unsigned int i, index, count;
426 UINT err_line;
427 HINF hinf;
428 DWORD err;
429 BOOL ret;
430 INFCONTEXT context;
432 for (i = 0; i < ARRAY_SIZE(key_names); i++)
434 int data_size;
436 strcpy( buffer, STD_HEADER "[Test]\n" );
437 data_size = strlen(buffer);
438 memcpy( buffer + data_size, key_names[i].data, key_names[i].data_size );
439 data_size += key_names[i].data_size;
440 SetLastError( 0xdeadbeef );
441 hinf = test_file_contents( buffer, data_size, &err_line );
442 ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %lu\n", i, GetLastError() );
443 if (hinf == INVALID_HANDLE_VALUE) continue;
445 ret = SetupFindFirstLineA( hinf, "Test", key_names[i].key, &context );
446 ok(ret, "Test %d: failed to find key %s\n", i, key_names[i].key);
448 if (!strncmp( key_names[i].data, "%foo%", strlen( "%foo%" ) ))
450 ret = SetupFindFirstLineA( hinf, "Test", "%foo%", &context );
451 ok(!ret, "SetupFindFirstLine() should not match unsubstituted keys\n");
452 ok(GetLastError() == ERROR_LINE_NOT_FOUND, "got wrong error %lu\n", GetLastError());
455 ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
456 ok(ret, "SetupFindFirstLineA failed: le=%lu\n", GetLastError());
457 if (!ret)
459 SetupCloseInfFile( hinf );
460 continue;
463 check_key( &context, key_names[i].key );
465 buffer[0] = buffer[1] = 0; /* build the full line */
466 for (index = 0; ; index++)
468 const char *field = get_string_field( &context, index + 1 );
469 err = GetLastError();
470 if (field)
472 ok( err == 0, "line %u: bad error %lu\n", i, err );
473 if (key_names[i].fields[index])
475 if (i == 52)
476 ok( !strcmp( field, key_names[i].fields[index] ) ||
477 !strcmp( field, A1200), /* Vista, W2K8 */
478 "line %u: bad field %s/%s\n",
479 i, field, key_names[i].fields[index] );
480 else if (i == 55)
481 ok( !strcmp( field, key_names[i].fields[index] ) ||
482 !strcmp( field, A4096), /* Win10 >= 1709 */
483 "line %u: bad field %s/%s\n",
484 i, field, key_names[i].fields[index] );
485 else /* don't compare drive letter of paths */
486 if (field[0] && field[1] == ':' && field[2] == '\\')
487 ok( !strcmp( field + 1, key_names[i].fields[index] + 1 ),
488 "line %u: bad field %s/%s\n",
489 i, field, key_names[i].fields[index] );
490 else
491 ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n",
492 i, field, key_names[i].fields[index] );
494 else
495 ok( 0, "line %u: got extra field %s\n", i, field );
496 strcat( buffer, "," );
497 strcat( buffer, field );
499 else
501 ok( err == 0 || err == ERROR_INVALID_PARAMETER,
502 "line %u: bad error %lu\n", i, err );
503 if (key_names[i].fields[index])
504 ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
506 if (!key_names[i].fields[index]) break;
508 count = SetupGetFieldCount( &context );
509 ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
511 line = get_line_text( &context );
512 ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
513 if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
515 SetupCloseInfFile( hinf );
520 static void test_close_inf_file(void)
522 SetLastError(0xdeadbeef);
523 SetupCloseInfFile(NULL);
524 ok(GetLastError() == 0xdeadbeef ||
525 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
526 "Expected 0xdeadbeef, got %lu\n", GetLastError());
528 SetLastError(0xdeadbeef);
529 SetupCloseInfFile(INVALID_HANDLE_VALUE);
530 ok(GetLastError() == 0xdeadbeef ||
531 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
532 "Expected 0xdeadbeef, got %lu\n", GetLastError());
535 static const char *contents = "[Version]\n"
536 "Signature=\"$Windows NT$\"\n"
537 "FileVersion=5.1.1.2\n"
538 "[FileBranchInfo]\n"
539 "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n"
540 "[Strings]\n"
541 "RTMQFE_NAME = \"RTMQFE\"\n";
543 static const CHAR getfield_resA[][20] =
545 "RTMQFE",
546 "%RTMGFE_NAME%",
547 "SP1RTM",
550 static const WCHAR getfield_resW[][20] =
552 {'R','T','M','Q','F','E',0},
553 {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
554 {'S','P','1','R','T','M',0},
557 static void test_pSetupGetField(void)
559 UINT err;
560 BOOL ret;
561 HINF hinf;
562 LPCSTR fieldA;
563 LPCWSTR fieldW;
564 INFCONTEXT context;
565 int i;
566 int len;
567 BOOL unicode = TRUE;
569 SetLastError(0xdeadbeef);
570 lstrcmpW(NULL, NULL);
571 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
573 win_skip("Using A-functions instead of W\n");
574 unicode = FALSE;
577 hinf = test_file_contents( contents, strlen(contents), &err );
578 ok( hinf != NULL, "Expected valid INF file\n" );
580 ret = SetupFindFirstLineA( hinf, "FileBranchInfo", NULL, &context );
581 ok( ret, "Failed to find first line\n" );
583 /* native Windows crashes if a NULL context is sent in */
585 for ( i = 0; i < 3; i++ )
587 if (unicode)
589 fieldW = pSetupGetFieldW( &context, i );
590 ok( fieldW != NULL, "Failed to get field %i\n", i );
591 ok( !lstrcmpW( getfield_resW[i], fieldW ), "Wrong string returned\n" );
593 else
595 fieldA = pSetupGetFieldA( &context, i );
596 ok( fieldA != NULL, "Failed to get field %i\n", i );
597 ok( !lstrcmpA( getfield_resA[i], fieldA ), "Wrong string returned\n" );
601 if (unicode)
603 fieldW = pSetupGetFieldW( &context, 3 );
604 ok( fieldW != NULL, "Failed to get field 3\n" );
605 len = lstrlenW( fieldW );
606 ok( len == 511 || /* NT4, W2K, XP and W2K3 */
607 len == 4096, /* Vista */
608 "Unexpected length, got %d\n", len );
610 fieldW = pSetupGetFieldW( &context, 4 );
611 ok( fieldW == NULL, "Expected NULL, got %p\n", fieldW );
612 ok( GetLastError() == ERROR_INVALID_PARAMETER,
613 "Expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() );
615 else
617 fieldA = pSetupGetFieldA( &context, 3 );
618 ok( fieldA != NULL, "Failed to get field 3\n" );
619 len = lstrlenA( fieldA );
620 ok( len == 511, /* Win9x, WinME */
621 "Unexpected length, got %d\n", len );
623 fieldA = pSetupGetFieldA( &context, 4 );
624 ok( fieldA == NULL, "Expected NULL, got %p\n", fieldA );
625 ok( GetLastError() == ERROR_INVALID_PARAMETER,
626 "Expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() );
629 SetupCloseInfFile( hinf );
632 static void test_SetupGetIntField(void)
634 static const struct
636 const char *key;
637 const char *fields;
638 DWORD index;
639 INT value;
640 DWORD err;
641 } keys[] =
643 /* key fields index expected int errorcode */
644 { "Key", "48", 1, 48, ERROR_SUCCESS },
645 { "Key", "48", 0, -1, ERROR_INVALID_DATA },
646 { "123", "48", 0, 123, ERROR_SUCCESS },
647 { "Key", "0x4", 1, 4, ERROR_SUCCESS },
648 { "Key", "Field1", 1, -1, ERROR_INVALID_DATA },
649 { "Key", "Field1,34", 2, 34, ERROR_SUCCESS },
650 { "Key", "Field1,,Field3", 2, 0, ERROR_SUCCESS },
651 { "Key", "Field1,", 2, 0, ERROR_SUCCESS }
653 unsigned int i;
655 for (i = 0; i < ARRAY_SIZE(keys); i++)
657 HINF hinf;
658 char buffer[MAX_INF_STRING_LENGTH];
659 INFCONTEXT context;
660 UINT err;
661 BOOL retb;
662 INT intfield;
664 strcpy( buffer, STD_HEADER "[TestSection]\n" );
665 strcat( buffer, keys[i].key );
666 strcat( buffer, "=" );
667 strcat( buffer, keys[i].fields );
668 hinf = test_file_contents( buffer, strlen(buffer), &err);
669 ok( hinf != NULL, "Expected valid INF file\n" );
671 SetupFindFirstLineA( hinf, "TestSection", keys[i].key, &context );
672 SetLastError( 0xdeadbeef );
673 intfield = -1;
674 retb = SetupGetIntField( &context, keys[i].index, &intfield );
675 if ( keys[i].err == ERROR_SUCCESS )
677 ok( retb, "%u: Expected success\n", i );
678 ok( GetLastError() == ERROR_SUCCESS ||
679 GetLastError() == 0xdeadbeef /* win9x, NT4 */,
680 "%u: Expected ERROR_SUCCESS or 0xdeadbeef, got %lu\n", i, GetLastError() );
682 else
684 ok( !retb, "%u: Expected failure\n", i );
685 ok( GetLastError() == keys[i].err,
686 "%u: Expected %ld, got %lu\n", i, keys[i].err, GetLastError() );
688 ok( intfield == keys[i].value, "%u: Expected %d, got %d\n", i, keys[i].value, intfield );
690 SetupCloseInfFile( hinf );
694 static void test_GLE(void)
696 static const char *inf =
697 "[Version]\n"
698 "Signature=\"$Windows NT$\"\n"
699 "[Sectionname]\n"
700 "Keyname1=Field1,Field2,Field3\n"
701 "\n"
702 "Keyname2=Field4,Field5\n";
703 HINF hinf;
704 UINT err;
705 INFCONTEXT context;
706 BOOL retb;
707 LONG retl;
708 char buf[MAX_INF_STRING_LENGTH];
709 int bufsize = MAX_INF_STRING_LENGTH;
710 DWORD retsize;
712 hinf = test_file_contents( inf, strlen(inf), &err );
713 ok( hinf != NULL, "Expected valid INF file\n" );
715 SetLastError(0xdeadbeef);
716 retb = SetupFindFirstLineA( hinf, "ImNotThere", NULL, &context );
717 ok(!retb, "Expected failure\n");
718 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
719 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
721 SetLastError(0xdeadbeef);
722 retb = SetupFindFirstLineA( hinf, "ImNotThere", "ImNotThere", &context );
723 ok(!retb, "Expected failure\n");
724 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
725 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
727 SetLastError(0xdeadbeef);
728 retb = SetupFindFirstLineA( hinf, "Sectionname", NULL, &context );
729 ok(retb, "Expected success\n");
730 ok(GetLastError() == ERROR_SUCCESS,
731 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
733 SetLastError(0xdeadbeef);
734 retb = SetupFindFirstLineA( hinf, "Sectionname", "ImNotThere", &context );
735 ok(!retb, "Expected failure\n");
736 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
737 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
739 SetLastError(0xdeadbeef);
740 retb = SetupFindFirstLineA( hinf, "Sectionname", "Keyname1", &context );
741 ok(retb, "Expected success\n");
742 ok(GetLastError() == ERROR_SUCCESS,
743 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
745 SetLastError(0xdeadbeef);
746 retb = SetupFindNextMatchLineA( &context, "ImNotThere", &context );
747 ok(!retb, "Expected failure\n");
748 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
749 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
751 SetLastError(0xdeadbeef);
752 retb = SetupFindNextMatchLineA( &context, "Keyname2", &context );
753 ok(retb, "Expected success\n");
754 ok(GetLastError() == ERROR_SUCCESS,
755 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
757 SetLastError(0xdeadbeef);
758 retl = SetupGetLineCountA( hinf, "ImNotThere");
759 ok(retl == -1, "Expected -1, got %ld\n", retl);
760 ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
761 "Expected ERROR_SECTION_NOT_FOUND, got %08lx\n", GetLastError());
763 SetLastError(0xdeadbeef);
764 retl = SetupGetLineCountA( hinf, "Sectionname");
765 ok(retl == 2, "Expected 2, got %ld\n", retl);
766 ok(GetLastError() == ERROR_SUCCESS,
767 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
769 SetLastError(0xdeadbeef);
770 retb = SetupGetLineTextA( NULL, hinf, "ImNotThere", "ImNotThere", buf, bufsize, &retsize);
771 ok(!retb, "Expected failure\n");
772 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
773 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
775 SetLastError(0xdeadbeef);
776 retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "ImNotThere", buf, bufsize, &retsize);
777 ok(!retb, "Expected failure\n");
778 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
779 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
781 SetLastError(0xdeadbeef);
782 retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "Keyname1", buf, bufsize, &retsize);
783 ok(retb, "Expected success\n");
784 ok(GetLastError() == ERROR_SUCCESS,
785 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
787 SetLastError(0xdeadbeef);
788 retb = SetupGetLineByIndexA( hinf, "ImNotThere", 1, &context );
789 ok(!retb, "Expected failure\n");
790 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
791 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
793 SetLastError(0xdeadbeef);
794 retb = SetupGetLineByIndexA( hinf, "Sectionname", 1, &context );
795 ok(retb, "Expected success\n");
796 ok(GetLastError() == ERROR_SUCCESS,
797 "Expected ERROR_SUCCESS, got %08lx\n", GetLastError());
799 SetLastError(0xdeadbeef);
800 retb = SetupGetLineByIndexA( hinf, "Sectionname", 3, &context );
801 ok(!retb, "Expected failure\n");
802 ok(GetLastError() == ERROR_LINE_NOT_FOUND,
803 "Expected ERROR_LINE_NOT_FOUND, got %08lx\n", GetLastError());
805 SetupCloseInfFile( hinf );
808 START_TEST(parser)
810 init_function_pointers();
811 test_invalid_files();
812 test_section_names();
813 test_enum_sections();
814 test_key_names();
815 test_close_inf_file();
816 test_pSetupGetField();
817 test_SetupGetIntField();
818 test_GLE();
819 DeleteFileA( tmpfilename );