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