1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for GetFontResourceInfoW
5  * PROGRAMMERS:     Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include "precomp.h"
9 
10 /* GetFontResourceInfoW is undocumented */
11 BOOL WINAPI GetFontResourceInfoW(LPCWSTR lpFileName, DWORD *pdwBufSize, void* lpBuffer, DWORD dwType);
12 
13 /* structure of test entry */
14 typedef struct GFRI_ENTRY
15 {
16     LPCWSTR     File;
17     BOOL        Preinstalled;
18     WCHAR       FontInfo[64];
19     INT         FontCount;
20     WCHAR       FaceNames[10][64];
21 } GFRI_ENTRY;
22 
23 /* test entries */
24 static const GFRI_ENTRY TestEntries[] =
25 {
26     { L"symbol.ttf", TRUE, L"Symbol|", 1, { L"Symbol" } },
27     { L"tahoma.ttf", TRUE, L"Tahoma|", 1, { L"Tahoma" } },
28     { L"tahomabd.ttf", TRUE, L"Tahoma Bold|", 1, { L"Tahoma" } }
29 };
30 
31 /* Japanese */
32 static const GFRI_ENTRY AdditionalTestEntriesJapanese[] =
33 {
34     {
35         /* MS Gothic & MS UI Gothic & MS PGothic */
36         L"msgothic.ttc", TRUE,
37         {
38             0xFF2D, 0xFF33, 0x0020, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0x0020,
39             0x0026, 0x0020, 0x004D, 0x0053, 0x0020, 0x0055, 0x0049, 0x0020,
40             0x0047, 0x006F, 0x0074, 0x0068, 0x0069, 0x0063, 0x0020, 0x0026,
41             0x0020, 0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x30B4, 0x30B7, 0x30C3,
42             0x30AF, L'|', 0
43         },
44         6,
45         {
46             { 0xFF2D, 0xFF33, 0x0020, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 },
47             { L'@', 0xFF2D, 0xFF33, 0x0020, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 },
48             L"MS UI Gothic",
49             L"@MS UI Gothic",
50             { 0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 },
51             { L'@', 0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }
52         }
53     },
54     {
55         L"ExampleFont.ttf", FALSE,
56         L"JapaneseDisplayName|",
57         1,
58         {
59             L"JapaneseFamilyName"
60         }
61     }
62 };
63 
64 /* English */
65 static const GFRI_ENTRY AdditionalTestEntriesEnglish[] =
66 {
67     {
68         /* MS Gothic & MS UI Gothic & MS PGothic */
69         L"msgothic.ttc", TRUE,
70         L"MS Gothic & MS UI Gothic & MS PGothic|",
71         6,
72         {
73             L"MS Gothic",
74             L"@MS Gothic",
75             L"MS UI Gothic",
76             L"@MS UI Gothic",
77             L"MS PGothic",
78             L"@MS PGothic"
79         }
80     },
81     {
82         L"ExampleFont.ttf", FALSE,
83         L"EnglishDisplayName|",
84         1,
85         {
86             L"EnglishFamilyName"
87         }
88     }
89 };
90 
91 static void
GetSystemFontDirectory(LPWSTR pszDir)92 GetSystemFontDirectory(LPWSTR pszDir)
93 {
94     GetWindowsDirectoryW(pszDir, MAX_PATH);
95     lstrcatW(pszDir, L"\\Fonts");
96 }
97 
98 static void
GetSystemFontPath(LPWSTR pszPath,LPCWSTR pszFile)99 GetSystemFontPath(LPWSTR pszPath, LPCWSTR pszFile)
100 {
101     GetSystemFontDirectory(pszPath);
102     lstrcatW(pszPath, L"\\");
103     lstrcatW(pszPath, pszFile);
104 }
105 
106 static INT
GetMultiSzLength(const WCHAR * pszz)107 GetMultiSzLength(const WCHAR *pszz)
108 {
109     INT Len, TotalLen = 0;
110     for (;;)
111     {
112         Len = lstrlenW(pszz);
113         TotalLen += Len + 1;
114         pszz += Len + 1;
115         if (*pszz == 0)
116             break;
117     }
118     ++TotalLen;
119     return TotalLen;
120 }
121 
122 static void
ReplaceChars(WCHAR * pch,INT Len,WCHAR From,WCHAR To)123 ReplaceChars(WCHAR *pch, INT Len, WCHAR From, WCHAR To)
124 {
125     while (Len > 0)
126     {
127         if (*pch == From)
128         {
129             *pch = To;
130         }
131         //printf("0x%04X, ", *pch);
132         ++pch;
133         --Len;
134     }
135 }
136 
137 static void
SzFromMultiSz(WCHAR * pszz)138 SzFromMultiSz(WCHAR *pszz)
139 {
140     INT Length = GetMultiSzLength(pszz);
141     //printf("Length: %d\n", Length);
142     if (Length > 0)
143     {
144         ReplaceChars(pszz, Length - 1, L'\0', L'|');
145         pszz[Length - 1] = 0;
146     }
147     else
148     {
149         pszz[0] = 0;
150     }
151     //printf("pszz: %S\n", pszz);
152 }
153 
154 static void
Test_GetFontResourceInfoW_case0(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)155 Test_GetFontResourceInfoW_case0(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
156 {
157     BOOL Ret;
158     DWORD Size, Case = 0;
159     DWORD Data;
160 
161     /* data NULL, size zero */
162     Size = 0;
163     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
164     ok_int(Ret, 1);
165     ok_int(Size, 4);
166 
167     /* data NULL, size non-zero */
168     Size = 1024;
169     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
170     ok_int(Ret, 0);
171     ok_int(Size, 1024);
172 
173     /* size zero */
174     Data = 0xDEADFACE;
175     Size = 0;
176     Ret = GetFontResourceInfoW(pszFilePath, &Size, &Data, Case);
177     ok_int(Ret, 1);
178     ok_int(Data, 0xDEADFACE);
179     ok_int(Size, 4);
180 
181     /* size non-zero */
182     Data = 0xDEADFACE;
183     Size = sizeof(Data);
184     Ret = GetFontResourceInfoW(pszFilePath, &Size, &Data, Case);
185     ok_int(Ret, 1);
186     ok_int(Data, Entry->FontCount);
187     ok_int(Size, 4);
188 }
189 
190 static void
Test_GetFontResourceInfoW_case1(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)191 Test_GetFontResourceInfoW_case1(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
192 {
193     BOOL Ret;
194     DWORD Size, Case = 1;
195     static WCHAR Data[1024 / sizeof(WCHAR)];
196 
197     /* data NULL, size zero */
198     Size = 0;
199     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
200     ok_int(Ret, 1);
201     /* FIXME: What's the result of Size? */
202     ok(Size != 0, "Size expected non-zero but zero\n");
203 
204     /* data NULL, size non-zero */
205     Size = 1024;
206     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
207     ok_int(Ret, 0);
208     ok_int(Size, 1024);
209 
210     /* size zero */
211     Size = 0;
212     CopyMemory(Data, L"ABC\0", sizeof(L"ABC\0"));
213     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
214     ok_int(Ret, 1);
215     /* FIXME: What's the result of Size? */
216     ok(Size != 0, "Size expected non-zero but zero\n");
217     ok(lstrcmpiW(Data, L"ABC") == 0, "data mismatched: \"%S\"\n", Data);
218 
219     /* size non-zero */
220     Size = 1024;
221     CopyMemory(Data, L"ABC\0", sizeof(L"ABC\0"));
222     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
223     ok_int(Ret, 1);
224     /* FIXME: What's the result of Size? */
225     ok(Size != 0, "Size expected non-zero but zero\n");
226 
227     SzFromMultiSz(Data);
228     ok(lstrcmpiW(Data, Entry->FontInfo) == 0, "data mismatched: \"%S\" and \"%S\"\n",
229        Data, Entry->FontInfo);
230 #if 0
231     if (lstrcmpiW(Data, Entry->FontInfo) != 0)
232     {
233         int i, len = lstrlenW(Data) + 1;
234         for (i = 0; i < len; ++i)
235         {
236             printf("0x%04X <=> 0x%04X\n", Data[i], Entry->FontInfo[i]);
237         }
238     }
239 #endif
240 }
241 
242 static void
Test_GetFontResourceInfoW_case2(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)243 Test_GetFontResourceInfoW_case2(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
244 {
245     BOOL Ret;
246     DWORD i, Size, Case = 2;
247     static LOGFONTW Data[100];
248 
249     /* data NULL, size zero */
250     Size = 0;
251     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
252     ok_int(Ret, 1);
253     ok_int(Size, Entry->FontCount * sizeof(LOGFONTW));
254 
255     /* data NULL, size non-zero */
256     Size = 1024;
257     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
258     ok_int(Ret, 0);
259     ok_int(Size, 1024);
260 
261     /* size zero */
262     Size = 0;
263     ZeroMemory(Data, sizeof(Data));
264     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
265     ok_int(Ret, 1);
266     ok_int(Size, Entry->FontCount * sizeof(LOGFONTW));
267 
268     /* size non-zero */
269     Size = sizeof(Data);
270     ZeroMemory(Data, sizeof(Data));
271     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
272     ok_int(Ret, 1);
273     ok_int(Size, Entry->FontCount * sizeof(LOGFONTW));
274     for (i = 0; i < Entry->FontCount; ++i)
275     {
276         ok(lstrcmpiW(Data[i].lfFaceName, Entry->FaceNames[i]) == 0,
277             "face name #%d mismatched: \"%S\" and \"%S\"\n", (int)i, Data[i].lfFaceName, Entry->FaceNames[i]);
278 #if 0
279         if (lstrcmpiW(Data[i].lfFaceName, Entry->FaceNames[i]) != 0)
280         {
281             int k, len = lstrlenW(Data[i].lfFaceName);
282             for (k = 0; k < len; ++k)
283             {
284                 printf("0x%04X <=> 0x%04X\n", Entry->FaceNames[i][k], Data[i].lfFaceName[k]);
285             }
286         }
287 #endif
288     }
289 }
290 
291 static void
Test_GetFontResourceInfoW_case3(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)292 Test_GetFontResourceInfoW_case3(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
293 {
294     BOOL Ret;
295     DWORD Size, Case = 3;
296     DWORD Data[2];
297 
298     /* data NULL, size zero */
299     Size = 0;
300     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
301     ok_int(Ret, 1);
302     ok_int(Size, 4);
303 
304     /* data NULL, size non-zero */
305     Size = sizeof(Data);
306     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
307     ok_int(Ret, 0);
308     ok_int(Size, 8);
309 
310     /* size zero */
311     Size = 0;
312     Data[0] = 0xDEADFACE;
313     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
314     ok_int(Ret, 1);
315     ok_int(Size, 4);
316     ok_int(Data[0], 0xDEADFACE);
317 
318     /* size non-zero */
319     Size = sizeof(Data);
320     Data[0] = 0xDEADFACE;
321     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
322     ok_int(Ret, 1);
323     ok_int(Size, 4);
324     ok_int(Data[0], 1);
325 }
326 
327 static void
Test_GetFontResourceInfoW_case4(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)328 Test_GetFontResourceInfoW_case4(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
329 {
330     BOOL Ret;
331     DWORD Size, Case = 4;
332     WCHAR Data[MAX_PATH];
333 
334     /* data NULL, size zero */
335     Size = 0;
336     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
337     ok_int(Ret, 1);
338     ok_int(Size, (lstrlenW(pszFilePath) + 1) * sizeof(WCHAR));
339 
340     /* data NULL, size non-zero */
341     Size = MAX_PATH;
342     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
343     ok_int(Ret, 0);
344     ok_int(Size, MAX_PATH);
345 
346     /* size zero */
347     Size = 0;
348     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
349     ok_int(Ret, 1);
350     ok_int(Size, (lstrlenW(pszFilePath) + 1) * sizeof(WCHAR));
351 
352     /* size non-zero */
353     Size = MAX_PATH;
354     Ret = GetFontResourceInfoW(pszFilePath, &Size, Data, Case);
355     ok_int(Ret, 1);
356     ok_int(Size, (lstrlenW(pszFilePath) + 1) * sizeof(WCHAR));
357     ok(lstrcmpiW(pszFilePath, Data) == 0, "data mismatched: \"%S\"\n", Data);
358 }
359 
360 static void
Test_GetFontResourceInfoW_case5(LPCWSTR pszFilePath,const GFRI_ENTRY * Entry)361 Test_GetFontResourceInfoW_case5(LPCWSTR pszFilePath, const GFRI_ENTRY *Entry)
362 {
363     BOOL Ret;
364     DWORD Size, Case = 5;
365     DWORD Data;
366 
367     /* data NULL, size zero */
368     Size = 0;
369     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
370     ok_int(Ret, 1);
371     ok_int(Size, 4);
372 
373     /* data NULL, size non-zero */
374     Size = sizeof(Data);
375     Ret = GetFontResourceInfoW(pszFilePath, &Size, NULL, Case);
376     ok_int(Ret, 0);
377     ok_int(Size, 4);
378 
379     /* size zero */
380     Size = 0;
381     Data = 0xDEADFACE;
382     Ret = GetFontResourceInfoW(pszFilePath, &Size, &Data, Case);
383     ok_int(Ret, 1);
384     ok_int(Size, 4);
385     ok_int(Data, 0xDEADFACE);
386 
387     /* size non-zero */
388     Size = sizeof(Data);
389     Data = 0xDEADFACE;
390     Ret = GetFontResourceInfoW(pszFilePath, &Size, &Data, Case);
391     ok_int(Ret, 1);
392     ok_int(Size, 4);
393     ok_int(Data, 0);
394 }
395 
396 static void
DoEntry(const GFRI_ENTRY * Entry)397 DoEntry(const GFRI_ENTRY *Entry)
398 {
399     WCHAR szPath[MAX_PATH], szTempPath[MAX_PATH];
400     BOOL Installed = FALSE;
401 
402     if (Entry->Preinstalled)
403     {
404         GetSystemFontPath(szPath, Entry->File);
405         printf("GetSystemFontPath: %S\n", szPath);
406         if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES)
407         {
408             skip("Font file \"%S\" was not found\n", szPath);
409             return;
410         }
411     }
412     else
413     {
414         /* load font data from resource */
415         HANDLE hFile;
416         HMODULE hMod = GetModuleHandleW(NULL);
417         HRSRC hRsrc = FindResourceW(hMod, Entry->File, (LPCWSTR)RT_RCDATA);
418         HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
419         DWORD Size = SizeofResource(hMod, hRsrc);
420         LPVOID pFont = LockResource(hGlobal);
421 
422         /* get temporary file name */
423         GetTempPathW(_countof(szTempPath), szTempPath);
424         GetTempFileNameW(szTempPath, L"FNT", 0, szPath);
425         printf("GetTempFileNameW: %S\n", szPath);
426 
427         /* write to file */
428         hFile = CreateFileW(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
429                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
430         WriteFile(hFile, pFont, Size, &Size, NULL);
431         CloseHandle(hFile);
432 
433         /* check existence */
434         if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES)
435         {
436             skip("Font file \"%S\" was not stored\n", szPath);
437             return;
438         }
439 
440         /* install */
441         Installed = !!AddFontResourceW(szPath);
442         if (!Installed)
443         {
444             skip("Font file \"%S\" was not installed\n", szPath);
445             RemoveFontResourceW(szPath);
446             DeleteFileW(szPath);
447             return;
448         }
449     }
450 
451     Test_GetFontResourceInfoW_case0(szPath, Entry);
452     Test_GetFontResourceInfoW_case1(szPath, Entry);
453     Test_GetFontResourceInfoW_case2(szPath, Entry);
454     Test_GetFontResourceInfoW_case3(szPath, Entry);
455     Test_GetFontResourceInfoW_case4(szPath, Entry);
456     Test_GetFontResourceInfoW_case5(szPath, Entry);
457 
458     if (!Entry->Preinstalled)
459     {
460         if (Installed)
461         {
462             RemoveFontResourceW(szPath);
463             DeleteFileW(szPath);
464         }
465     }
466 }
467 
START_TEST(GetFontResourceInfoW)468 START_TEST(GetFontResourceInfoW)
469 {
470     INT i;
471     const GFRI_ENTRY *Entry;
472 
473     printf("sizeof(LOGFONTW) == %u\n", (int)sizeof(LOGFONTW));
474 
475     for (i = 0; i < _countof(TestEntries); ++i)
476     {
477         Entry = &TestEntries[i];
478         DoEntry(Entry);
479     }
480 
481     if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_JAPANESE)
482     {
483         /* Japanese */
484         for (i = 0; i < _countof(AdditionalTestEntriesJapanese); ++i)
485         {
486             Entry = &AdditionalTestEntriesJapanese[i];
487             DoEntry(Entry);
488         }
489     }
490     else
491     {
492         /* non-Japanese */
493         for (i = 0; i < _countof(AdditionalTestEntriesEnglish); ++i)
494         {
495             Entry = &AdditionalTestEntriesEnglish[i];
496             DoEntry(Entry);
497         }
498     }
499 }
500