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
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"
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" \
70 "mydrive=\"C:\\\"\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
)
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
;
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
;
100 /* Test various valid/invalid file formats */
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
},
154 static void test_invalid_files(void)
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 */
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
},
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 },
231 static void test_section_names(void)
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
);
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
);
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";
272 UINT err
, index
, len
;
275 if (!pSetupEnumInfSectionsA
)
277 win_skip( "SetupEnumInfSectionsA not available\n" );
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 */
319 const char *fields
[10];
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" } },
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" } },
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" } },
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" } },
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("="), "", { "" } },
368 { C("ab=c\032d"), "ab", { "c" } },
369 { C("ab\032=cd"), "ab", { "ab" } },
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();
410 ok( !wanted
, "missing key %s\n", wanted
);
411 ok( err
== 0 || err
== ERROR_INVALID_PARAMETER
, "last error set to %lu\n", err
);
415 ok( !strcmp( key
, wanted
), "bad key %s/%s\n", key
, wanted
);
416 ok( err
== 0, "last error set to %lu\n", err
);
421 static void test_key_names(void)
423 char buffer
[MAX_INF_STRING_LENGTH
+32];
425 unsigned int i
, index
, count
;
432 for (i
= 0; i
< ARRAY_SIZE(key_names
); i
++)
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());
459 SetupCloseInfFile( hinf
);
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();
472 ok( err
== 0, "line %u: bad error %lu\n", i
, err
);
473 if (key_names
[i
].fields
[index
])
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
] );
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
] );
491 ok( !strcmp( field
, key_names
[i
].fields
[index
] ), "line %u: bad field %s/%s\n",
492 i
, field
, key_names
[i
].fields
[index
] );
495 ok( 0, "line %u: got extra field %s\n", i
, field
);
496 strcat( buffer
, "," );
497 strcat( buffer
, field
);
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"
539 "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097
"\n"
541 "RTMQFE_NAME = \"RTMQFE\"\n";
543 static const CHAR getfield_resA
[][20] =
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)
569 SetLastError(0xdeadbeef);
570 lstrcmpW(NULL
, NULL
);
571 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
573 win_skip("Using A-functions instead of W\n");
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
++ )
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" );
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" );
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() );
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)
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
}
655 for (i
= 0; i
< ARRAY_SIZE(keys
); i
++)
658 char buffer
[MAX_INF_STRING_LENGTH
];
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 );
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() );
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
=
698 "Signature=\"$Windows NT$\"\n"
700 "Keyname1=Field1,Field2,Field3\n"
702 "Keyname2=Field4,Field5\n";
708 char buf
[MAX_INF_STRING_LENGTH
];
709 int bufsize
= MAX_INF_STRING_LENGTH
;
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
);
810 init_function_pointers();
811 test_invalid_files();
812 test_section_names();
813 test_enum_sections();
815 test_close_inf_file();
816 test_pSetupGetField();
817 test_SetupGetIntField();
819 DeleteFileA( tmpfilename
);