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 A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
64 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
66 #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \
67 "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \
69 "mydrive=\"C:\\\"\n" \
72 /* create a new file with specified contents and open it */
73 static HINF
test_file_contents( const char *data
, UINT
*err_line
)
76 HANDLE handle
= CreateFileA( tmpfilename
, GENERIC_READ
|GENERIC_WRITE
,
77 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
78 if (handle
== INVALID_HANDLE_VALUE
) return 0;
79 if (!WriteFile( handle
, data
, strlen(data
), &res
, NULL
)) trace( "write error\n" );
80 CloseHandle( handle
);
81 return SetupOpenInfFileA( tmpfilename
, 0, INF_STYLE_WIN4
, err_line
);
84 static const char *get_string_field( INFCONTEXT
*context
, DWORD index
)
86 static char buffer
[MAX_INF_STRING_LENGTH
+32];
87 if (SetupGetStringFieldA( context
, index
, buffer
, sizeof(buffer
), NULL
)) return buffer
;
91 static const char *get_line_text( INFCONTEXT
*context
)
93 static char buffer
[MAX_INF_STRING_LENGTH
+32];
94 if (SetupGetLineTextA( context
, 0, 0, 0, buffer
, sizeof(buffer
), NULL
)) return buffer
;
99 /* Test various valid/invalid file formats */
109 /* file contents expected error (or 0) errline todo */
110 { "\r\n", ERROR_WRONG_INF_STYLE
, 0, FALSE
},
111 { "abcd\r\n", ERROR_WRONG_INF_STYLE
, 0, TRUE
},
112 { "[Version]\r\n", ERROR_WRONG_INF_STYLE
, 0, FALSE
},
113 { "[Version]\nSignature=", ERROR_WRONG_INF_STYLE
, 0, FALSE
},
114 { "[Version]\nSignature=foo", ERROR_WRONG_INF_STYLE
, 0, FALSE
},
115 { "[version]\nsignature=$chicago$", 0, 0, FALSE
},
116 { "[VERSION]\nSIGNATURE=$CHICAGO$", 0, 0, FALSE
},
117 { "[Version]\nSignature=$chicago$,abcd", 0, 0, FALSE
},
118 { "[Version]\nabc=def\nSignature=$chicago$", 0, 0, FALSE
},
119 { "[Version]\nabc=def\n[Version]\nSignature=$chicago$", 0, 0, FALSE
},
120 { STD_HEADER
, 0, 0, FALSE
},
121 { STD_HEADER
"[]\r\n", 0, 0, FALSE
},
122 { STD_HEADER
"]\r\n", 0, 0, FALSE
},
123 { STD_HEADER
"[" A255
"]\r\n", 0, 0, FALSE
},
124 { STD_HEADER
"[ab\r\n", ERROR_BAD_SECTION_NAME_LINE
, 3, FALSE
},
125 { STD_HEADER
"\n\n[ab\x1a]\n", ERROR_BAD_SECTION_NAME_LINE
, 5, FALSE
},
126 { STD_HEADER
"[" A256
"]\r\n", ERROR_SECTION_NAME_TOO_LONG
, 3, FALSE
},
127 { "[abc]\n" STD_HEADER
, 0, 0, FALSE
},
128 { "abc\r\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 1, FALSE
},
129 { ";\n;\nabc\r\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 3, FALSE
},
130 { ";\n;\nab\nab\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 3, FALSE
},
131 { ";aa\n;bb\n" STD_HEADER
, 0, 0, FALSE
},
132 { STD_HEADER
" [TestSection\x00]\n", ERROR_BAD_SECTION_NAME_LINE
, 3, FALSE
},
133 { STD_HEADER
" [Test\x00Section]\n", ERROR_BAD_SECTION_NAME_LINE
, 3, FALSE
},
134 { STD_HEADER
" [TestSection\x00]\n", ERROR_BAD_SECTION_NAME_LINE
, 3, FALSE
},
135 { STD_HEADER
" [Test\x00Section]\n", ERROR_BAD_SECTION_NAME_LINE
, 3, FALSE
},
136 { "garbage1\ngarbage2\n[abc]\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 1, FALSE
},
137 { "garbage1\ngarbage2\n[Strings]\n" STD_HEADER
, 0, 0, FALSE
},
138 { ";comment\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 2, FALSE
},
139 { ";comment\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER
, 0, 0, FALSE
},
140 { " \t\ngarbage1\ngarbage2\n[abc]\n" STD_HEADER
, ERROR_EXPECTED_SECTION_NAME
, 2, FALSE
},
141 { " \t\ngarbage1\ngarbage2\n[Strings]\n" STD_HEADER
, 0, 0, FALSE
},
142 { "garbage1\ngarbage2\n" STD_HEADER
"[abc]\n", ERROR_EXPECTED_SECTION_NAME
, 1, FALSE
},
143 { "garbage1\ngarbage2\n" STD_HEADER
"[Strings]\n", 0, 0, FALSE
},
144 { ";comment\ngarbage1\ngarbage2\n" STD_HEADER
"[abc]\n", ERROR_EXPECTED_SECTION_NAME
, 2, FALSE
},
145 { ";comment\ngarbage1\ngarbage2\n" STD_HEADER
"[Strings]\n", 0, 0, FALSE
},
146 { " \t\ngarbage1\ngarbage2\n" STD_HEADER
"[abc]\n", ERROR_EXPECTED_SECTION_NAME
, 2, FALSE
},
147 { " \t\ngarbage1\ngarbage2\n" STD_HEADER
"[Strings]\n", 0, 0, FALSE
},
150 static void test_invalid_files(void)
157 for (i
= 0; i
< sizeof(invalid_files
)/sizeof(invalid_files
[0]); i
++)
159 SetLastError( 0xdeadbeef );
160 err_line
= 0xdeadbeef;
161 hinf
= test_file_contents( invalid_files
[i
].data
, &err_line
);
162 err
= GetLastError();
163 trace( "hinf=%p err=0x%x line=%d\n", hinf
, err
, err_line
);
164 if (invalid_files
[i
].error
) /* should fail */
166 ok( hinf
== INVALID_HANDLE_VALUE
, "file %u: Open succeeded\n", i
);
167 todo_wine_if (invalid_files
[i
].todo
)
169 ok( err
== invalid_files
[i
].error
, "file %u: Bad error %u/%u\n",
170 i
, err
, invalid_files
[i
].error
);
171 ok( err_line
== invalid_files
[i
].err_line
, "file %u: Bad error line %d/%d\n",
172 i
, err_line
, invalid_files
[i
].err_line
);
175 else /* should succeed */
177 ok( hinf
!= INVALID_HANDLE_VALUE
, "file %u: Open failed\n", i
);
178 ok( err
== 0, "file %u: Error code set to %u\n", i
, err
);
180 SetupCloseInfFile( hinf
);
185 /* Test various section names */
194 /* file contents section name error code */
195 { STD_HEADER
"[TestSection]", "TestSection", 0 },
196 { STD_HEADER
"[TestSection]\n", "TestSection", 0 },
197 { STD_HEADER
"[TESTSECTION]\r\n", "TestSection", 0 },
198 { STD_HEADER
"[TestSection]\n[abc]", "testsection", 0 },
199 { STD_HEADER
";[TestSection]\n", "TestSection", ERROR_SECTION_NOT_FOUND
},
200 { STD_HEADER
"[TestSection]\n", "Bad name", ERROR_SECTION_NOT_FOUND
},
202 { STD_HEADER
"[TestSection] \r\n", "TestSection", 0 },
203 { STD_HEADER
" [TestSection]\r\n", "TestSection", 0 },
204 { STD_HEADER
" [TestSection] dummy\r\n", "TestSection", 0 },
205 { STD_HEADER
" [TestSection] [foo]\r\n", "TestSection", 0 },
206 { STD_HEADER
" [ Test Section ] dummy\r\n", " Test Section ", 0 },
207 { STD_HEADER
"[TestSection] \032\ndummy", "TestSection", 0 },
208 { STD_HEADER
"[TestSection] \n\032dummy", "TestSection", 0 },
209 /* special chars in section name */
210 { STD_HEADER
"[Test[Section]\r\n", "Test[Section", 0 },
211 { STD_HEADER
"[Test[S]ection]\r\n", "Test[S", 0 },
212 { STD_HEADER
"[Test[[[Section]\r\n", "Test[[[Section", 0 },
213 { STD_HEADER
"[]\r\n", "", 0 },
214 { STD_HEADER
"[[[]\n", "[[", 0 },
215 { STD_HEADER
"[Test\"Section]\r\n", "Test\"Section", 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 /* various control chars */
220 { STD_HEADER
" [Test\r\b\tSection] \n", "Test\r\b\tSection", 0 },
224 static void test_section_names(void)
232 for (i
= 0; i
< sizeof(section_names
)/sizeof(section_names
[0]); i
++)
234 SetLastError( 0xdeadbeef );
235 hinf
= test_file_contents( section_names
[i
].data
, &err_line
);
236 ok( hinf
!= INVALID_HANDLE_VALUE
, "line %u: open failed err %u\n", i
, GetLastError() );
237 if (hinf
== INVALID_HANDLE_VALUE
) continue;
239 ret
= SetupGetLineCountA( hinf
, section_names
[i
].section
);
240 err
= GetLastError();
241 trace( "hinf=%p ret=%d err=0x%x\n", hinf
, ret
, err
);
244 ok( !section_names
[i
].error
, "line %u: section name %s found\n",
245 i
, section_names
[i
].section
);
246 ok( !err
, "line %u: bad error code %u\n", i
, err
);
250 ok( section_names
[i
].error
, "line %u: section name %s not found\n",
251 i
, section_names
[i
].section
);
252 ok( err
== section_names
[i
].error
, "line %u: bad error %u/%u\n",
253 i
, err
, section_names
[i
].error
);
255 SetupCloseInfFile( hinf
);
259 static void test_enum_sections(void)
261 static const char *contents
= STD_HEADER
"[s1]\nfoo=bar\n[s2]\nbar=foo\n[s3]\n[strings]\na=b\n";
269 if (!pSetupEnumInfSectionsA
)
271 win_skip( "SetupEnumInfSectionsA not available\n" );
275 hinf
= test_file_contents( contents
, &err
);
276 ok( hinf
!= NULL
, "Expected valid INF file\n" );
278 for (index
= 0; ; index
++)
280 SetLastError( 0xdeadbeef );
281 ret
= pSetupEnumInfSectionsA( hinf
, index
, NULL
, 0, &len
);
282 err
= GetLastError();
283 if (!ret
&& GetLastError() == ERROR_NO_MORE_ITEMS
) break;
284 ok( ret
, "SetupEnumInfSectionsA failed\n" );
285 ok( len
== 3 || len
== 8, "wrong len %u\n", len
);
287 SetLastError( 0xdeadbeef );
288 ret
= pSetupEnumInfSectionsA( hinf
, index
, NULL
, sizeof(buffer
), &len
);
289 err
= GetLastError();
290 ok( !ret
, "SetupEnumInfSectionsA succeeded\n" );
291 ok( err
== ERROR_INVALID_USER_BUFFER
, "wrong error %u\n", err
);
292 ok( len
== 3 || len
== 8, "wrong len %u\n", len
);
294 SetLastError( 0xdeadbeef );
295 ret
= pSetupEnumInfSectionsA( hinf
, index
, buffer
, sizeof(buffer
), &len
);
296 ok( ret
, "SetupEnumInfSectionsA failed err %u\n", GetLastError() );
297 ok( len
== 3 || len
== 8, "wrong len %u\n", len
);
298 ok( !lstrcmpiA( buffer
, "version" ) || !lstrcmpiA( buffer
, "s1" ) ||
299 !lstrcmpiA( buffer
, "s2" ) || !lstrcmpiA( buffer
, "s3" ) || !lstrcmpiA( buffer
, "strings" ),
300 "bad section '%s'\n", buffer
);
302 SetupCloseInfFile( hinf
);
306 /* Test various key and value names */
312 const char *fields
[10];
315 /* file contents expected key expected fields */
316 { "ab=cd", "ab", { "cd" } },
317 { "ab=cd,ef,gh,ij", "ab", { "cd", "ef", "gh", "ij" } },
318 { "ab", "ab", { "ab" } },
319 { "ab,cd", NULL
, { "ab", "cd" } },
320 { "ab,cd=ef", NULL
, { "ab", "cd=ef" } },
321 { "=abcd,ef", "", { "abcd", "ef" } },
323 { "ba\\\ncd=ef", "bacd", { "ef" } },
324 { "ab \\ \ncd=ef", "abcd", { "ef" } },
325 { "ab\\\ncd,ef", NULL
, { "abcd", "ef" } },
326 { "ab \\ ;cc\ncd=ef", "abcd", { "ef" } },
327 { "ab \\ \\ \ncd=ef", "abcd", { "ef" } },
328 { "ba \\ dc=xx", "ba \\ dc", { "xx" } },
329 { "ba \\\\ \nc=d", "bac", { "d" } },
330 { "a=b\\\\c", "a", { "b\\\\c" } },
331 { "ab=cd \\ ", "ab", { "cd" } },
332 { "ba=c \\ \n \\ \n a", "ba", { "ca" } },
333 { "ba=c \\ \n \\ a", "ba", { "c\\ a" } },
334 { " \\ a= \\ b", "\\ a", { "\\ b" } },
336 { "Ab\"Cd\"=Ef", "AbCd", { "Ef" } },
337 { "Ab\"Cd=Ef\"", "AbCd=Ef", { "AbCd=Ef" } },
338 { "ab\"\"\"cd,ef=gh\"", "ab\"cd,ef=gh", { "ab\"cd,ef=gh" } },
339 { "ab\"\"cd=ef", "abcd", { "ef" } },
340 { "ab\"\"cd=ef,gh", "abcd", { "ef", "gh" } },
341 { "ab=cd\"\"ef", "ab", { "cdef" } },
342 { "ab=cd\",\"ef", "ab", { "cd,ef" } },
343 { "ab=cd\",ef", "ab", { "cd,ef" } },
344 { "ab=cd\",ef\\\nab", "ab", { "cd,ef\\" } },
346 /* single quotes (unhandled)*/
347 { "HKLM,A,B,'C',D", NULL
, { "HKLM", "A","B","'C'","D" } },
349 { " a b = c , d \n", "a b", { "c", "d" } },
350 { " a b = c ,\" d\" \n", "a b", { "c", " d" } },
351 { " a b\r = c\r\n", "a b", { "c" } },
353 { "a=b,,,c,,,d", "a", { "b", "", "", "c", "", "", "d" } },
354 { "a=b,\"\",c,\" \",d", "a", { "b", "", "c", " ", "d" } },
355 { "=,,b", "", { "", "", "b" } },
356 { ",=,,b", NULL
, { "", "=", "", "b" } },
357 { "a=\n", "a", { "" } },
360 { "ab=c\032d", "ab", { "c" } },
361 { "ab\032=cd", "ab", { "ab" } },
363 { "abcd=ef\x0gh", "abcd", { "ef" } },
364 /* multiple sections with same name */
365 { "[Test2]\nab\n[Test]\nee=ff\n", "ee", { "ff" } },
366 /* string substitution */
367 { "%foo%=%bar%\n" STR_SECTION
, "aaa", { "bbb" } },
368 { "%foo%xx=%bar%yy\n" STR_SECTION
, "aaaxx", { "bbbyy" } },
369 { "%% %foo%=%bar%\n" STR_SECTION
, "% aaa", { "bbb" } },
370 { "%f\"o\"o%=ccc\n" STR_SECTION
, "aaa", { "ccc" } },
371 { "abc=%bar;bla%\n" STR_SECTION
, "abc", { "%bar" } },
372 { "loop=%loop%\n" STR_SECTION
, "loop", { "%loop2%" } },
373 { "%per%%cent%=100\n" STR_SECTION
, "12", { "100" } },
374 { "a=%big%\n" STR_SECTION
, "a", { A400
} },
375 { "a=%verybig%\n" STR_SECTION
, "a", { A511
} }, /* truncated to 511, not on Vista/W2K8 */
376 { "a=%big%%big%%big%%big%\n" STR_SECTION
, "a", { A400 A400 A400 A400
} },
377 { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION
, "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400
} },
378 { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION
, "a", { A4097
/*MAX_INF_STRING_LENGTH+1*/ } },
380 /* Prove expansion of system entries removes extra \'s and string
381 replacements doesn't */
382 { "ab=\"%24%\"\n" STR_SECTION
, "ab", { "C:\\" } },
383 { "ab=\"%mydrive%\"\n" STR_SECTION
, "ab", { "C:\\" } },
384 { "ab=\"%24%\\fred\"\n" STR_SECTION
, "ab", { "C:\\fred" } },
385 { "ab=\"%mydrive%\\fred\"\n" STR_SECTION
,"ab", { "C:\\\\fred" } },
386 /* Confirm duplicate \'s kept */
387 { "ab=\"%24%\\\\fred\"", "ab", { "C:\\\\fred" } },
388 { "ab=C:\\\\FRED", "ab", { "C:\\\\FRED" } },
391 /* check the key of a certain line */
392 static const char *check_key( INFCONTEXT
*context
, const char *wanted
)
394 const char *key
= get_string_field( context
, 0 );
395 DWORD err
= GetLastError();
399 ok( !wanted
, "missing key %s\n", wanted
);
400 ok( err
== 0 || err
== ERROR_INVALID_PARAMETER
, "last error set to %u\n", err
);
404 ok( !strcmp( key
, wanted
), "bad key %s/%s\n", key
, wanted
);
405 ok( err
== 0, "last error set to %u\n", err
);
410 static void test_key_names(void)
412 char buffer
[MAX_INF_STRING_LENGTH
+32];
414 unsigned int i
, index
, count
;
421 for (i
= 0; i
< sizeof(key_names
)/sizeof(key_names
[0]); i
++)
423 strcpy( buffer
, STD_HEADER
"[Test]\n" );
424 strcat( buffer
, key_names
[i
].data
);
425 SetLastError( 0xdeadbeef );
426 hinf
= test_file_contents( buffer
, &err_line
);
427 ok( hinf
!= INVALID_HANDLE_VALUE
, "line %u: open failed err %u\n", i
, GetLastError() );
428 if (hinf
== INVALID_HANDLE_VALUE
) continue;
430 ret
= SetupFindFirstLineA( hinf
, "Test", 0, &context
);
431 ok(ret
, "SetupFindFirstLineA failed: le=%u\n", GetLastError());
434 SetupCloseInfFile( hinf
);
438 check_key( &context
, key_names
[i
].key
);
440 buffer
[0] = buffer
[1] = 0; /* build the full line */
441 for (index
= 0; ; index
++)
443 const char *field
= get_string_field( &context
, index
+ 1 );
444 err
= GetLastError();
447 ok( err
== 0, "line %u: bad error %u\n", i
, err
);
448 if (key_names
[i
].fields
[index
])
451 ok( !strcmp( field
, key_names
[i
].fields
[index
] ) ||
452 !strcmp( field
, A1200
), /* Vista, W2K8 */
453 "line %u: bad field %s/%s\n",
454 i
, field
, key_names
[i
].fields
[index
] );
455 else /* don't compare drive letter of paths */
456 if (field
[0] && field
[1] == ':' && field
[2] == '\\')
457 ok( !strcmp( field
+ 1, key_names
[i
].fields
[index
] + 1 ),
458 "line %u: bad field %s/%s\n",
459 i
, field
, key_names
[i
].fields
[index
] );
461 ok( !strcmp( field
, key_names
[i
].fields
[index
] ), "line %u: bad field %s/%s\n",
462 i
, field
, key_names
[i
].fields
[index
] );
465 ok( 0, "line %u: got extra field %s\n", i
, field
);
466 strcat( buffer
, "," );
467 strcat( buffer
, field
);
471 ok( err
== 0 || err
== ERROR_INVALID_PARAMETER
,
472 "line %u: bad error %u\n", i
, err
);
473 if (key_names
[i
].fields
[index
])
474 ok( 0, "line %u: missing field %s\n", i
, key_names
[i
].fields
[index
] );
476 if (!key_names
[i
].fields
[index
]) break;
478 count
= SetupGetFieldCount( &context
);
479 ok( count
== index
, "line %u: bad count %d/%d\n", i
, index
, count
);
481 line
= get_line_text( &context
);
482 ok( line
!= NULL
, "line %u: SetupGetLineText failed\n", i
);
483 if (line
) ok( !strcmp( line
, buffer
+1 ), "line %u: bad text %s/%s\n", i
, line
, buffer
+1 );
485 SetupCloseInfFile( hinf
);
490 static void test_close_inf_file(void)
492 SetLastError(0xdeadbeef);
493 SetupCloseInfFile(NULL
);
494 ok(GetLastError() == 0xdeadbeef ||
495 GetLastError() == ERROR_INVALID_PARAMETER
, /* Win9x, WinMe */
496 "Expected 0xdeadbeef, got %u\n", GetLastError());
498 SetLastError(0xdeadbeef);
499 SetupCloseInfFile(INVALID_HANDLE_VALUE
);
500 ok(GetLastError() == 0xdeadbeef ||
501 GetLastError() == ERROR_INVALID_PARAMETER
, /* Win9x, WinMe */
502 "Expected 0xdeadbeef, got %u\n", GetLastError());
505 static const char *contents
= "[Version]\n"
506 "Signature=\"$Windows NT$\"\n"
507 "FileVersion=5.1.1.2\n"
509 "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097
"\n"
511 "RTMQFE_NAME = \"RTMQFE\"\n";
513 static const CHAR getfield_resA
[][20] =
520 static const WCHAR getfield_resW
[][20] =
522 {'R','T','M','Q','F','E',0},
523 {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
524 {'S','P','1','R','T','M',0},
527 static void test_pSetupGetField(void)
539 SetLastError(0xdeadbeef);
540 lstrcmpW(NULL
, NULL
);
541 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
543 win_skip("Using A-functions instead of W\n");
547 hinf
= test_file_contents( contents
, &err
);
548 ok( hinf
!= NULL
, "Expected valid INF file\n" );
550 ret
= SetupFindFirstLineA( hinf
, "FileBranchInfo", NULL
, &context
);
551 ok( ret
, "Failed to find first line\n" );
553 /* native Windows crashes if a NULL context is sent in */
555 for ( i
= 0; i
< 3; i
++ )
559 fieldW
= pSetupGetFieldW( &context
, i
);
560 ok( fieldW
!= NULL
, "Failed to get field %i\n", i
);
561 ok( !lstrcmpW( getfield_resW
[i
], fieldW
), "Wrong string returned\n" );
565 fieldA
= pSetupGetFieldA( &context
, i
);
566 ok( fieldA
!= NULL
, "Failed to get field %i\n", i
);
567 ok( !lstrcmpA( getfield_resA
[i
], fieldA
), "Wrong string returned\n" );
573 fieldW
= pSetupGetFieldW( &context
, 3 );
574 ok( fieldW
!= NULL
, "Failed to get field 3\n" );
575 len
= lstrlenW( fieldW
);
576 ok( len
== 511 || /* NT4, W2K, XP and W2K3 */
577 len
== 4096, /* Vista */
578 "Unexpected length, got %d\n", len
);
580 fieldW
= pSetupGetFieldW( &context
, 4 );
581 ok( fieldW
== NULL
, "Expected NULL, got %p\n", fieldW
);
582 ok( GetLastError() == ERROR_INVALID_PARAMETER
,
583 "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
587 fieldA
= pSetupGetFieldA( &context
, 3 );
588 ok( fieldA
!= NULL
, "Failed to get field 3\n" );
589 len
= lstrlenA( fieldA
);
590 ok( len
== 511, /* Win9x, WinME */
591 "Unexpected length, got %d\n", len
);
593 fieldA
= pSetupGetFieldA( &context
, 4 );
594 ok( fieldA
== NULL
, "Expected NULL, got %p\n", fieldA
);
595 ok( GetLastError() == ERROR_INVALID_PARAMETER
,
596 "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
599 SetupCloseInfFile( hinf
);
602 static void test_SetupGetIntField(void)
613 /* key fields index expected int errorcode */
614 { "Key", "48", 1, 48, ERROR_SUCCESS
},
615 { "Key", "48", 0, -1, ERROR_INVALID_DATA
},
616 { "123", "48", 0, 123, ERROR_SUCCESS
},
617 { "Key", "0x4", 1, 4, ERROR_SUCCESS
},
618 { "Key", "Field1", 1, -1, ERROR_INVALID_DATA
},
619 { "Key", "Field1,34", 2, 34, ERROR_SUCCESS
},
620 { "Key", "Field1,,Field3", 2, 0, ERROR_SUCCESS
},
621 { "Key", "Field1,", 2, 0, ERROR_SUCCESS
}
625 for (i
= 0; i
< sizeof(keys
)/sizeof(keys
[0]); i
++)
628 char buffer
[MAX_INF_STRING_LENGTH
];
634 strcpy( buffer
, STD_HEADER
"[TestSection]\n" );
635 strcat( buffer
, keys
[i
].key
);
636 strcat( buffer
, "=" );
637 strcat( buffer
, keys
[i
].fields
);
638 hinf
= test_file_contents( buffer
, &err
);
639 ok( hinf
!= NULL
, "Expected valid INF file\n" );
641 SetupFindFirstLineA( hinf
, "TestSection", keys
[i
].key
, &context
);
642 SetLastError( 0xdeadbeef );
644 retb
= SetupGetIntField( &context
, keys
[i
].index
, &intfield
);
645 if ( keys
[i
].err
== ERROR_SUCCESS
)
647 ok( retb
, "%u: Expected success\n", i
);
648 ok( GetLastError() == ERROR_SUCCESS
||
649 GetLastError() == 0xdeadbeef /* win9x, NT4 */,
650 "%u: Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", i
, GetLastError() );
654 ok( !retb
, "%u: Expected failure\n", i
);
655 ok( GetLastError() == keys
[i
].err
,
656 "%u: Expected %d, got %u\n", i
, keys
[i
].err
, GetLastError() );
658 ok( intfield
== keys
[i
].value
, "%u: Expected %d, got %d\n", i
, keys
[i
].value
, intfield
);
660 SetupCloseInfFile( hinf
);
664 static void test_GLE(void)
666 static const char *inf
=
668 "Signature=\"$Windows NT$\"\n"
670 "Keyname1=Field1,Field2,Field3\n"
672 "Keyname2=Field4,Field5\n";
678 char buf
[MAX_INF_STRING_LENGTH
];
679 int bufsize
= MAX_INF_STRING_LENGTH
;
682 hinf
= test_file_contents( inf
, &err
);
683 ok( hinf
!= NULL
, "Expected valid INF file\n" );
685 SetLastError(0xdeadbeef);
686 retb
= SetupFindFirstLineA( hinf
, "ImNotThere", NULL
, &context
);
687 ok(!retb
, "Expected failure\n");
688 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
689 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
691 SetLastError(0xdeadbeef);
692 retb
= SetupFindFirstLineA( hinf
, "ImNotThere", "ImNotThere", &context
);
693 ok(!retb
, "Expected failure\n");
694 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
695 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
697 SetLastError(0xdeadbeef);
698 retb
= SetupFindFirstLineA( hinf
, "Sectionname", NULL
, &context
);
699 ok(retb
, "Expected success\n");
700 ok(GetLastError() == ERROR_SUCCESS
,
701 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
703 SetLastError(0xdeadbeef);
704 retb
= SetupFindFirstLineA( hinf
, "Sectionname", "ImNotThere", &context
);
705 ok(!retb
, "Expected failure\n");
706 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
707 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
709 SetLastError(0xdeadbeef);
710 retb
= SetupFindFirstLineA( hinf
, "Sectionname", "Keyname1", &context
);
711 ok(retb
, "Expected success\n");
712 ok(GetLastError() == ERROR_SUCCESS
,
713 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
715 SetLastError(0xdeadbeef);
716 retb
= SetupFindNextMatchLineA( &context
, "ImNotThere", &context
);
717 ok(!retb
, "Expected failure\n");
718 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
719 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
721 SetLastError(0xdeadbeef);
722 retb
= SetupFindNextMatchLineA( &context
, "Keyname2", &context
);
723 ok(retb
, "Expected success\n");
724 ok(GetLastError() == ERROR_SUCCESS
,
725 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
727 SetLastError(0xdeadbeef);
728 retl
= SetupGetLineCountA( hinf
, "ImNotThere");
729 ok(retl
== -1, "Expected -1, got %d\n", retl
);
730 ok(GetLastError() == ERROR_SECTION_NOT_FOUND
,
731 "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
733 SetLastError(0xdeadbeef);
734 retl
= SetupGetLineCountA( hinf
, "Sectionname");
735 ok(retl
== 2, "Expected 2, got %d\n", retl
);
736 ok(GetLastError() == ERROR_SUCCESS
,
737 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
739 SetLastError(0xdeadbeef);
740 retb
= SetupGetLineTextA( NULL
, hinf
, "ImNotThere", "ImNotThere", buf
, bufsize
, &retsize
);
741 ok(!retb
, "Expected failure\n");
742 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
743 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
745 SetLastError(0xdeadbeef);
746 retb
= SetupGetLineTextA( NULL
, hinf
, "Sectionname", "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());
751 SetLastError(0xdeadbeef);
752 retb
= SetupGetLineTextA( NULL
, hinf
, "Sectionname", "Keyname1", buf
, bufsize
, &retsize
);
753 ok(retb
, "Expected success\n");
754 ok(GetLastError() == ERROR_SUCCESS
,
755 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
757 SetLastError(0xdeadbeef);
758 retb
= SetupGetLineByIndexA( hinf
, "ImNotThere", 1, &context
);
759 ok(!retb
, "Expected failure\n");
760 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
761 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
763 SetLastError(0xdeadbeef);
764 retb
= SetupGetLineByIndexA( hinf
, "Sectionname", 1, &context
);
765 ok(retb
, "Expected success\n");
766 ok(GetLastError() == ERROR_SUCCESS
,
767 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
769 SetLastError(0xdeadbeef);
770 retb
= SetupGetLineByIndexA( hinf
, "Sectionname", 3, &context
);
771 ok(!retb
, "Expected failure\n");
772 ok(GetLastError() == ERROR_LINE_NOT_FOUND
,
773 "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError());
775 SetupCloseInfFile( hinf
);
780 init_function_pointers();
781 test_invalid_files();
782 test_section_names();
783 test_enum_sections();
785 test_close_inf_file();
786 test_pSetupGetField();
787 test_SetupGetIntField();
789 DeleteFileA( tmpfilename
);