wined3d: Optimize render states in the stateblock.
[wine] / dlls / setupapi / tests / parser.c
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 <assert.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30
31 #include "wine/test.h"
32
33 /* function pointers */
34 static HMODULE hSetupAPI;
35 static LPCWSTR (WINAPI *pSetupGetField)(PINFCONTEXT,DWORD);
36
37 static void init_function_pointers(void)
38 {
39     hSetupAPI = GetModuleHandleA("setupapi.dll");
40
41     pSetupGetField = (void *)GetProcAddress(hSetupAPI, "pSetupGetField"); 
42 }
43
44 static const char tmpfilename[] = ".\\tmp.inf";
45
46 /* some large strings */
47 #define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
48              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
49              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
50              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
51 #define A256 "a" A255
52 #define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
53              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
54              "aaaaaaaaaaaaaaaa" A256
55 #define A511 A255 A256
56 #define A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
57
58 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
59
60 #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \
61                     "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \
62                     "big=" A400 "\n" \
63                     "verybig=" A400 A400 A400 "\n"
64
65 /* create a new file with specified contents and open it */
66 static HINF test_file_contents( const char *data, UINT *err_line )
67 {
68     DWORD res;
69     HANDLE handle = CreateFileA( tmpfilename, GENERIC_READ|GENERIC_WRITE,
70                                  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
71     if (handle == INVALID_HANDLE_VALUE) return 0;
72     if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" );
73     CloseHandle( handle );
74     return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line );
75 }
76
77 static const char *get_string_field( INFCONTEXT *context, DWORD index )
78 {
79     static char buffer[MAX_INF_STRING_LENGTH+32];
80     if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
81     return NULL;
82 }
83
84 static const char *get_line_text( INFCONTEXT *context )
85 {
86     static char buffer[MAX_INF_STRING_LENGTH+32];
87     if (SetupGetLineTextA( context, 0, 0, 0, buffer, sizeof(buffer), NULL )) return buffer;
88     return NULL;
89 }
90
91
92 /* Test various valid/invalid file formats */
93
94 static const struct
95 {
96     const char *data;
97     DWORD error;
98     UINT err_line;
99     int todo;
100 } invalid_files[] =
101 {
102     /* file contents                                         expected error (or 0)     errline  todo */
103     { "\r\n",                                                ERROR_WRONG_INF_STYLE,       0,    0 },
104     { "abcd\r\n",                                            ERROR_WRONG_INF_STYLE,       0,    1 },
105     { "[Version]\r\n",                                       ERROR_WRONG_INF_STYLE,       0,    0 },
106     { "[Version]\nSignature=",                               ERROR_WRONG_INF_STYLE,       0,    0 },
107     { "[Version]\nSignature=foo",                            ERROR_WRONG_INF_STYLE,       0,    0 },
108     { "[version]\nsignature=$chicago$",                      0,                           0,    0 },
109     { "[VERSION]\nSIGNATURE=$CHICAGO$",                      0,                           0,    0 },
110     { "[Version]\nSignature=$chicago$,abcd",                 0,                           0,    0 },
111     { "[Version]\nabc=def\nSignature=$chicago$",             0,                           0,    0 },
112     { "[Version]\nabc=def\n[Version]\nSignature=$chicago$",  0,                           0,    0 },
113     { STD_HEADER,                                            0,                           0,    0 },
114     { STD_HEADER "[]\r\n",                                   0,                           0,    0 },
115     { STD_HEADER "]\r\n",                                    0,                           0,    0 },
116     { STD_HEADER "[" A255 "]\r\n",                           0,                           0,    0 },
117     { STD_HEADER "[ab\r\n",                                  ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
118     { STD_HEADER "\n\n[ab\x1a]\n",                           ERROR_BAD_SECTION_NAME_LINE, 5,    0 },
119     { STD_HEADER "[" A256 "]\r\n",                           ERROR_SECTION_NAME_TOO_LONG, 3,    0 },
120     { "[abc]\n" STD_HEADER,                                  0,                           0,    0 },
121     { "abc\r\n" STD_HEADER,                                  ERROR_EXPECTED_SECTION_NAME, 1,    0 },
122     { ";\n;\nabc\r\n" STD_HEADER,                            ERROR_EXPECTED_SECTION_NAME, 3,    0 },
123     { ";\n;\nab\nab\n" STD_HEADER,                           ERROR_EXPECTED_SECTION_NAME, 3,    0 },
124     { ";aa\n;bb\n" STD_HEADER,                               0,                           0,    0 },
125     { STD_HEADER " [TestSection\x00] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
126     { STD_HEADER " [Test\x00Section] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
127     { STD_HEADER " [TestSection\x00] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
128     { STD_HEADER " [Test\x00Section] \n",                    ERROR_BAD_SECTION_NAME_LINE, 3,    0 },
129 };
130
131 static void test_invalid_files(void)
132 {
133     unsigned int i;
134     UINT err_line;
135     HINF hinf;
136     DWORD err;
137
138     for (i = 0; i < sizeof(invalid_files)/sizeof(invalid_files[0]); i++)
139     {
140         SetLastError( 0xdeadbeef );
141         err_line = 0xdeadbeef;
142         hinf = test_file_contents( invalid_files[i].data, &err_line );
143         err = GetLastError();
144         trace( "hinf=%p err=0x%x line=%d\n", hinf, err, err_line );
145         if (invalid_files[i].error)  /* should fail */
146         {
147             ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i );
148             if (invalid_files[i].todo) todo_wine
149             {
150                 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
151                     i, err, invalid_files[i].error );
152                 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
153                     i, err_line, invalid_files[i].err_line );
154             }
155             else
156             {
157                 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
158                     i, err, invalid_files[i].error );
159                 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
160                     i, err_line, invalid_files[i].err_line );
161             }
162         }
163         else  /* should succeed */
164         {
165             ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i );
166             ok( err == 0, "file %u: Error code set to %u\n", i, err );
167         }
168         SetupCloseInfFile( hinf );
169     }
170 }
171
172
173 /* Test various section names */
174
175 static const struct
176 {
177     const char *data;
178     const char *section;
179     DWORD error;
180 } section_names[] =
181 {
182     /* file contents                              section name       error code */
183     { STD_HEADER "[TestSection]",                 "TestSection",         0 },
184     { STD_HEADER "[TestSection]\n",               "TestSection",         0 },
185     { STD_HEADER "[TESTSECTION]\r\n",             "TestSection",         0 },
186     { STD_HEADER "[TestSection]\n[abc]",          "testsection",         0 },
187     { STD_HEADER ";[TestSection]\n",              "TestSection",         ERROR_SECTION_NOT_FOUND },
188     { STD_HEADER "[TestSection]\n",               "Bad name",            ERROR_SECTION_NOT_FOUND },
189     /* spaces */
190     { STD_HEADER "[TestSection]   \r\n",          "TestSection",         0 },
191     { STD_HEADER "   [TestSection]\r\n",          "TestSection",         0 },
192     { STD_HEADER "   [TestSection]   dummy\r\n",  "TestSection",         0 },
193     { STD_HEADER "   [TestSection]   [foo]\r\n",  "TestSection",         0 },
194     { STD_HEADER " [  Test Section  ] dummy\r\n", "  Test Section  ",    0 },
195     { STD_HEADER "[TestSection] \032\ndummy",     "TestSection",         0 },
196     { STD_HEADER "[TestSection] \n\032dummy",     "TestSection",         0 },
197     /* special chars in section name */
198     { STD_HEADER "[Test[Section]\r\n",            "Test[Section",        0 },
199     { STD_HEADER "[Test[S]ection]\r\n",           "Test[S",              0 },
200     { STD_HEADER "[Test[[[Section]\r\n",          "Test[[[Section",      0 },
201     { STD_HEADER "[]\r\n",                        "",                    0 },
202     { STD_HEADER "[[[]\n",                        "[[",                  0 },
203     { STD_HEADER "[Test\"Section]\r\n",           "Test\"Section",       0 },
204     { STD_HEADER "[Test\\Section]\r\n",           "Test\\Section",       0 },
205     { STD_HEADER "[Test\\ Section]\r\n",          "Test\\ Section",      0 },
206     { STD_HEADER "[Test;Section]\r\n",            "Test;Section",        0 },
207     /* various control chars */
208     { STD_HEADER " [Test\r\b\tSection] \n",       "Test\r\b\tSection", 0 },
209     /* nulls */
210 };
211
212 static void test_section_names(void)
213 {
214     unsigned int i;
215     UINT err_line;
216     HINF hinf;
217     DWORD err;
218     LONG ret;
219
220     for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); i++)
221     {
222         SetLastError( 0xdeadbeef );
223         hinf = test_file_contents( section_names[i].data, &err_line );
224         ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
225         if (hinf == INVALID_HANDLE_VALUE) continue;
226
227         ret = SetupGetLineCountA( hinf, section_names[i].section );
228         err = GetLastError();
229         trace( "hinf=%p ret=%d err=0x%x\n", hinf, ret, err );
230         if (ret != -1)
231         {
232             ok( !section_names[i].error, "line %u: section name %s found\n",
233                 i, section_names[i].section );
234             ok( !err, "line %u: bad error code %u\n", i, err );
235         }
236         else
237         {
238             ok( section_names[i].error, "line %u: section name %s not found\n",
239                 i, section_names[i].section );
240             ok( err == section_names[i].error, "line %u: bad error %u/%u\n",
241                 i, err, section_names[i].error );
242         }
243         SetupCloseInfFile( hinf );
244     }
245 }
246
247
248 /* Test various key and value names */
249
250 static const struct
251 {
252     const char *data;
253     const char *key;
254     const char *fields[10];
255 } key_names[] =
256 {
257 /* file contents          expected key       expected fields */
258  { "ab=cd",                "ab",            { "cd" } },
259  { "ab=cd,ef,gh,ij",       "ab",            { "cd", "ef", "gh", "ij" } },
260  { "ab",                   "ab",            { "ab" } },
261  { "ab,cd",                NULL,            { "ab", "cd" } },
262  { "ab,cd=ef",             NULL,            { "ab", "cd=ef" } },
263  { "=abcd,ef",             "",              { "abcd", "ef" } },
264  /* backslashes */
265  { "ba\\\ncd=ef",          "bacd",          { "ef" } },
266  { "ab  \\  \ncd=ef",      "abcd",          { "ef" } },
267  { "ab\\\ncd,ef",          NULL,            { "abcd", "ef" } },
268  { "ab  \\ ;cc\ncd=ef",    "abcd",          { "ef" } },
269  { "ab \\ \\ \ncd=ef",     "abcd",          { "ef" } },
270  { "ba \\ dc=xx",          "ba \\ dc",      { "xx" } },
271  { "ba \\\\ \nc=d",        "bac",           { "d" } },
272  { "a=b\\\\c",             "a",             { "b\\\\c" } },
273  { "ab=cd \\ ",            "ab",            { "cd" } },
274  { "ba=c \\ \n \\ \n a",   "ba",            { "ca" } },
275  { "ba=c \\ \n \\ a",      "ba",            { "c\\ a" } },
276  { "  \\ a= \\ b",         "\\ a",          { "\\ b" } },
277  /* quotes */
278  { "Ab\"Cd\"=Ef",          "AbCd",          { "Ef" } },
279  { "Ab\"Cd=Ef\"",          "AbCd=Ef",       { "AbCd=Ef" } },
280  { "ab\"\"\"cd,ef=gh\"",   "ab\"cd,ef=gh",  { "ab\"cd,ef=gh" } },
281  { "ab\"\"cd=ef",          "abcd",          { "ef" } },
282  { "ab\"\"cd=ef,gh",       "abcd",          { "ef", "gh" } },
283  { "ab=cd\"\"ef",          "ab",            { "cdef" } },
284  { "ab=cd\",\"ef",         "ab",            { "cd,ef" } },
285  { "ab=cd\",ef",           "ab",            { "cd,ef" } },
286  { "ab=cd\",ef\\\nab",     "ab",            { "cd,ef\\" } },
287  /* single quotes (unhandled)*/
288  { "HKLM,A,B,'C',D",       NULL,            { "HKLM", "A","B","'C'","D" } },
289  /* spaces */
290  { " a b = c , d \n",      "a b",           { "c", "d" } },
291  { " a b = c ,\" d\" \n",  "a b",           { "c", " d" } },
292  { " a b\r = c\r\n",       "a b",           { "c" } },
293  /* empty fields */
294  { "a=b,,,c,,,d",          "a",             { "b", "", "", "c", "", "", "d" } },
295  { "a=b,\"\",c,\" \",d",   "a",             { "b", "", "c", " ", "d" } },
296  { "=,,b",                 "",              { "", "", "b" } },
297  { ",=,,b",                NULL,            { "", "=", "", "b" } },
298  { "a=\n",                 "a",             { "" } },
299  { "=",                    "",              { "" } },
300  /* eof */
301  { "ab=c\032d",            "ab",            { "c" } },
302  { "ab\032=cd",            "ab",            { "ab" } },
303  /* nulls */
304  { "abcd=ef\x0gh",         "abcd",          { "ef" } },
305  /* multiple sections with same name */
306  { "[Test2]\nab\n[Test]\nee=ff\n",  "ee",    { "ff" } },
307  /* string substitution */
308  { "%foo%=%bar%\n" STR_SECTION,     "aaa",   { "bbb" } },
309  { "%foo%xx=%bar%yy\n" STR_SECTION, "aaaxx", { "bbbyy" } },
310  { "%% %foo%=%bar%\n" STR_SECTION,  "% aaa", { "bbb" } },
311  { "%f\"o\"o%=ccc\n" STR_SECTION,   "aaa",   { "ccc" } },
312  { "abc=%bar;bla%\n" STR_SECTION,   "abc",   { "%bar" } },
313  { "loop=%loop%\n" STR_SECTION,     "loop",  { "%loop2%" } },
314  { "%per%%cent%=100\n" STR_SECTION, "12",    { "100" } },
315  { "a=%big%\n" STR_SECTION,         "a",     { A400 } },
316  { "a=%verybig%\n" STR_SECTION,     "a",     { A511 } },  /* truncated to 511 */
317  { "a=%big%%big%%big%%big%\n" STR_SECTION,   "a", { A400 A400 A400 A400 } },
318  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION,   "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } },
319  { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION,   "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } },
320 };
321
322 /* check the key of a certain line */
323 static const char *check_key( INFCONTEXT *context, const char *wanted )
324 {
325     const char *key = get_string_field( context, 0 );
326     DWORD err = GetLastError();
327
328     if (!key)
329     {
330         ok( !wanted, "missing key %s\n", wanted );
331         ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %u\n", err );
332     }
333     else
334     {
335         ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
336         ok( err == 0, "last error set to %u\n", err );
337     }
338     return key;
339 }
340
341 static void test_key_names(void)
342 {
343     char buffer[MAX_INF_STRING_LENGTH+32];
344     const char *key, *line;
345     unsigned int i, index, count;
346     UINT err_line;
347     HINF hinf;
348     DWORD err;
349     BOOL ret;
350     INFCONTEXT context;
351
352     for (i = 0; i < sizeof(key_names)/sizeof(key_names[0]); i++)
353     {
354         strcpy( buffer, STD_HEADER "[Test]\n" );
355         strcat( buffer, key_names[i].data );
356         SetLastError( 0xdeadbeef );
357         hinf = test_file_contents( buffer, &err_line );
358         ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
359         if (hinf == INVALID_HANDLE_VALUE) continue;
360
361         ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
362         assert( ret );
363
364         key = check_key( &context, key_names[i].key );
365
366         buffer[0] = buffer[1] = 0;  /* build the full line */
367         for (index = 0; ; index++)
368         {
369             const char *field = get_string_field( &context, index + 1 );
370             err = GetLastError();
371             if (field)
372             {
373                 ok( err == 0, "line %u: bad error %u\n", i, err );
374                 if (key_names[i].fields[index])
375                     ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n",
376                         i, field, key_names[i].fields[index] );
377                 else
378                     ok( 0, "line %u: got extra field %s\n", i, field );
379                 strcat( buffer, "," );
380                 strcat( buffer, field );
381             }
382             else
383             {
384                 ok( err == 0 || err == ERROR_INVALID_PARAMETER,
385                     "line %u: bad error %u\n", i, err );
386                 if (key_names[i].fields[index])
387                     ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
388             }
389             if (!key_names[i].fields[index]) break;
390         }
391         count = SetupGetFieldCount( &context );
392         ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
393
394         line = get_line_text( &context );
395         ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
396         if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
397
398         SetupCloseInfFile( hinf );
399     }
400
401 }
402
403 static void test_close_inf_file(void)
404 {
405     SetLastError(0xdeadbeef);
406     SetupCloseInfFile(NULL);
407     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError());
408
409     SetLastError(0xdeadbeef);
410     SetupCloseInfFile(INVALID_HANDLE_VALUE);
411     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError());
412
413 }
414
415 static const char *contents = "[Version]\n"
416                               "Signature=\"$Windows NT$\"\n"
417                               "FileVersion=5.1.1.2\n"
418                               "[FileBranchInfo]\n"
419                               "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n"
420                               "[Strings]\n"
421                               "RTMQFE_NAME = \"RTMQFE\"\n";
422
423 static const WCHAR getfield_res[][20] =
424 {
425     {'R','T','M','Q','F','E',0},
426     {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
427     {'S','P','1','R','T','M',0},
428 };
429
430 static void test_pSetupGetField(void)
431 {
432     UINT err;
433     BOOL ret;
434     HINF hinf;
435     LPCWSTR field;
436     INFCONTEXT context;
437     int i;
438
439     hinf = test_file_contents( contents, &err );
440     ok( hinf != NULL, "Expected valid INF file\n" );
441
442     ret = SetupFindFirstLine( hinf, "FileBranchInfo", NULL, &context );
443     ok( ret, "Failed to find first line\n" );
444
445     /* native Windows crashes if a NULL context is sent in */
446
447     for ( i = 0; i < 3; i++ )
448     {
449         field = pSetupGetField( &context, i );
450         ok( field != NULL, "Failed to get field %i\n", i );
451         ok( !lstrcmpW( getfield_res[i], field ), "Wrong string returned\n" );
452
453         ret = HeapFree( GetProcessHeap(), 0, (LPVOID)field );
454         ok( !ret, "Expected HeapFree to fail\n" );
455         ok( GetLastError() == ERROR_INVALID_PARAMETER,
456             "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
457     }
458
459     field = pSetupGetField( &context, 3 );
460     ok( field != NULL, "Failed to get field 3\n" );
461     ok( lstrlenW( field ) == 511, "Expected 511, got %d\n", lstrlenW( field ) );
462
463     field = pSetupGetField( &context, 4 );
464     ok( field == NULL, "Expected NULL, got %p\n", field );
465     ok( GetLastError() == ERROR_INVALID_PARAMETER,
466         "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
467
468     SetupCloseInfFile( hinf );
469 }
470
471 START_TEST(parser)
472 {
473     init_function_pointers();
474     test_invalid_files();
475     test_section_names();
476     test_key_names();
477     test_close_inf_file();
478     test_pSetupGetField();
479     DeleteFileA( tmpfilename );
480 }