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 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 */ 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 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 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 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 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 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 */ 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 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 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 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 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 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 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