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