1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Tests for (Rtl)IsTextUnicode.
5  * PROGRAMMERS:     Hermes Belusca-Maito
6  *                  Dmitry Chapyshev
7  *                  Katayama Hirofumi MZ
8  */
9 
10 #include "precomp.h"
11 
12 #include <stdio.h>
13 
LoadCodePageData(ULONG Code)14 PVOID LoadCodePageData(ULONG Code)
15 {
16     char filename[MAX_PATH], sysdir[MAX_PATH];
17     HANDLE hFile;
18     PVOID Data = NULL;
19     GetSystemDirectoryA(sysdir, MAX_PATH);
20 
21     if (Code != -1)
22         StringCbPrintfA(filename, sizeof(filename),  "%s\\c_%lu.nls", sysdir, Code);
23     else
24         StringCbPrintfA(filename, sizeof(filename),  "%s\\l_intl.nls", sysdir);
25 
26     hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
27     if (hFile != INVALID_HANDLE_VALUE)
28     {
29         DWORD dwRead;
30         DWORD dwFileSize = GetFileSize(hFile, NULL);
31         Data = malloc(dwFileSize);
32         ReadFile(hFile, Data, dwFileSize, &dwRead, NULL);
33         CloseHandle(hFile);
34     }
35     return Data;
36 }
37 
38 /* https://www.microsoft.com/resources/msdn/goglobal/default.mspx */
SetupLocale(ULONG AnsiCode,ULONG OemCode,ULONG Unicode)39 void SetupLocale(ULONG AnsiCode, ULONG OemCode, ULONG Unicode)
40 {
41     NLSTABLEINFO NlsTable;
42     PVOID AnsiCodePageData;
43     PVOID OemCodePageData;
44     PVOID UnicodeCaseTableData;
45 
46     AnsiCodePageData = LoadCodePageData(AnsiCode);
47     OemCodePageData = LoadCodePageData(OemCode);
48     UnicodeCaseTableData = LoadCodePageData(Unicode);
49 
50     RtlInitNlsTables(AnsiCodePageData, OemCodePageData, UnicodeCaseTableData, &NlsTable);
51     RtlResetRtlTranslations(&NlsTable);
52     /* Do NOT free the buffers here, they are directly used!
53         Yes, we leak the old buffers, but this is a test anyway... */
54 
55 }
56 
START_TEST(IsTextUnicode)57 START_TEST(IsTextUnicode)
58 {
59 #define INVALID_FLAG    0xFFFFFFFF
60 
61 #define NEW_TEST(Buffer, Flags, ResultFlags, Success)   \
62     { __LINE__, (PVOID)(Buffer), sizeof((Buffer)), (Flags), (ResultFlags), (Success) }
63 
64     static struct
65     {
66         INT lineno;
67 
68         /* Input */
69         PVOID Buffer;
70         INT   Size;
71         INT   Flags;
72 
73         /* Output */
74         INT   ResultFlags;
75         BOOL  Success;
76     } Tests[] =
77     {
78         /* ANSI string */
79         NEW_TEST("ANSI string", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
80         NEW_TEST("ANSI string", IS_TEXT_UNICODE_STATISTICS, 0, FALSE),
81         NEW_TEST("ANSI string", INVALID_FLAG, 0, FALSE),
82 
83         /* UNICODE strings */
84         NEW_TEST(L"a", IS_TEXT_UNICODE_ASCII16, IS_TEXT_UNICODE_ASCII16, TRUE),
85         NEW_TEST(L"a", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_ASCII16, TRUE),
86         NEW_TEST(L"a", IS_TEXT_UNICODE_STATISTICS, IS_TEXT_UNICODE_STATISTICS, TRUE),
87         NEW_TEST(L"a", INVALID_FLAG, 0, TRUE),
88 
89         NEW_TEST(L"UNICODE String 0", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
90         NEW_TEST(L"UNICODE String 0", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_CONTROLS | IS_TEXT_UNICODE_STATISTICS, TRUE),
91         NEW_TEST(L"UNICODE String 0", IS_TEXT_UNICODE_STATISTICS, IS_TEXT_UNICODE_STATISTICS, TRUE),
92         NEW_TEST(L"UNICODE String 0", INVALID_FLAG, 0, TRUE),
93 
94         NEW_TEST(L"\xFEFF" L"UNICODE String 1", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
95         NEW_TEST(L"\xFEFF" L"UNICODE String 1", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_CONTROLS, TRUE),
96         NEW_TEST(L"\xFEFF" L"UNICODE String 1", IS_TEXT_UNICODE_STATISTICS, 0, FALSE),
97         NEW_TEST(L"\xFEFF" L"UNICODE String 1", INVALID_FLAG, 0, TRUE),
98 
99         NEW_TEST(L"\xFFFE" L"UNICODE String 2", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
100         NEW_TEST(L"\xFFFE" L"UNICODE String 2", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_CONTROLS, TRUE),
101         NEW_TEST(L"\xFFFE" L"UNICODE String 2", IS_TEXT_UNICODE_STATISTICS, 0, FALSE),
102         NEW_TEST(L"\xFFFE" L"UNICODE String 2", INVALID_FLAG, 0, FALSE),
103 
104         NEW_TEST(L"UNICODE String 3 Привет!", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
105         NEW_TEST(L"UNICODE String 3 Привет!", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_CONTROLS | IS_TEXT_UNICODE_STATISTICS, TRUE),
106         NEW_TEST(L"UNICODE String 3 Привет!", IS_TEXT_UNICODE_STATISTICS, IS_TEXT_UNICODE_STATISTICS, TRUE),
107         NEW_TEST(L"UNICODE String 3 Привет!", INVALID_FLAG, 0, TRUE),
108 
109         NEW_TEST(L"\xFEFF" L"UNICODE String 4 Привет!", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
110         NEW_TEST(L"\xFEFF" L"UNICODE String 4 Привет!", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_CONTROLS, TRUE),
111         NEW_TEST(L"\xFEFF" L"UNICODE String 4 Привет!", IS_TEXT_UNICODE_STATISTICS, 0, FALSE),
112         NEW_TEST(L"\xFEFF" L"UNICODE String 4 Привет!", INVALID_FLAG, 0, TRUE),
113 
114         NEW_TEST(L"\xFFFE" L"UNICODE String 5 Привет!", IS_TEXT_UNICODE_ASCII16, 0, FALSE),
115         NEW_TEST(L"\xFFFE" L"UNICODE String 5 Привет!", IS_TEXT_UNICODE_UNICODE_MASK, IS_TEXT_UNICODE_CONTROLS, TRUE),
116         NEW_TEST(L"\xFFFE" L"UNICODE String 5 Привет!", IS_TEXT_UNICODE_STATISTICS, 0, FALSE),
117         NEW_TEST(L"\xFFFE" L"UNICODE String 5 Привет!", INVALID_FLAG, 0, FALSE),
118 
119         /* Reverse BOM */
120         NEW_TEST(L"UNICODE S" L"\xFFFE" L"tring 5 Привет!", IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ILLEGAL_CHARS, FALSE),
121         /* UNICODE_NUL */
122         NEW_TEST(L"UNICODE S" L"\x0000" L"tring 5 Привет!", IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ILLEGAL_CHARS, FALSE),
123         /* ASCII CRLF (packed into one word) */
124         NEW_TEST(L"UNICODE S" L"\x0A0D" L"tring 5 Привет!", IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ILLEGAL_CHARS, FALSE),
125         /* Unicode 0xFFFF */
126         NEW_TEST(L"UNICODE S" L"\xFFFF" L"tring 5 Привет!", IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ILLEGAL_CHARS, FALSE),
127 
128         NEW_TEST(L"UNICODE String 0", IS_TEXT_UNICODE_DBCS_LEADBYTE, 0, FALSE)
129     };
130 
131     const char japanese_with_lead[] = "ABC" "\x83\x40" "D";
132     const char japanese_sjis[] = "\x93\xFA\x96\x7B\x8C\xEA\x31\x32\x33\x93\xFA\x96\x7B\x8C\xEA";
133     const char japanese_utf8[] = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\x31\x32\x33\xE6\x97\xA5"
134                                  "\xE6\x9C\xAC\xE8\xAA\x9E";
135     const char simplfied_chinese_with_lead[] = "ABC" "\xC5\xC5" "D";
136     const char korean_with_lead[] = "ABC" "\xBF\xAD" "D";
137     const char traditional_chinese_with_lead[] = "ABC" "\xB1\xC1" "D";
138 
139     UINT i;
140     BOOL Success;
141     INT Result;
142 
143     for (i = 0; i < ARRAYSIZE(Tests); ++i)
144     {
145         Result = Tests[i].Flags;
146         Success = IsTextUnicode(Tests[i].Buffer, Tests[i].Size, ((Result != INVALID_FLAG) ? &Result : NULL));
147         ok(Success == Tests[i].Success, "Line %u: IsTextUnicode() returned 0x%x, expected %s\n", Tests[i].lineno, Success, (Tests[i].Success ? "TRUE" : "FALSE"));
148         if (Result != INVALID_FLAG)
149             ok(Result == Tests[i].ResultFlags, "Line %u: IsTextUnicode() Result returned 0x%x, expected 0x%x\n", Tests[i].lineno, Result, Tests[i].ResultFlags);
150     }
151 
152     /* Japanese */
153     SetupLocale(932, 932, -1);
154 
155     Result = IS_TEXT_UNICODE_DBCS_LEADBYTE;
156     ok_int(IsTextUnicode(japanese_with_lead, sizeof(japanese_with_lead), &Result), FALSE);
157     ok_int(Result, IS_TEXT_UNICODE_DBCS_LEADBYTE);
158 
159     ok_int(IsTextUnicode(japanese_sjis, sizeof(japanese_sjis) - 1, NULL), FALSE);
160 
161     Result = IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_REVERSE_STATISTICS;
162     ok_int(IsTextUnicode(japanese_sjis, sizeof(japanese_sjis) - 1, &Result), FALSE);
163     ok_int(Result, 0);
164 
165     Result = IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_REVERSE_STATISTICS |
166              IS_TEXT_UNICODE_DBCS_LEADBYTE;
167     ok_int(IsTextUnicode(japanese_sjis, sizeof(japanese_sjis) - 1, &Result), FALSE);
168     ok_int(Result, (IS_TEXT_UNICODE_DBCS_LEADBYTE | IS_TEXT_UNICODE_REVERSE_STATISTICS));
169 
170     ok_int(IsTextUnicode(japanese_utf8, sizeof(japanese_utf8) - 1, NULL), FALSE);
171 
172     Result = IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_REVERSE_STATISTICS;
173     ok_int(IsTextUnicode(japanese_utf8, sizeof(japanese_utf8) - 1, &Result), FALSE);
174     ok_int(Result, 0);
175 
176     Result = IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_REVERSE_STATISTICS |
177              IS_TEXT_UNICODE_DBCS_LEADBYTE;
178     ok_int(IsTextUnicode(japanese_utf8, sizeof(japanese_utf8) - 1, &Result), FALSE);
179     ok_int(Result, (IS_TEXT_UNICODE_DBCS_LEADBYTE | IS_TEXT_UNICODE_STATISTICS));
180 
181     /* Simplified Chinese */
182     SetupLocale(936, 936, -1);
183 
184     Result = IS_TEXT_UNICODE_DBCS_LEADBYTE;
185     ok(!IsTextUnicode(simplfied_chinese_with_lead, sizeof(simplfied_chinese_with_lead), &Result), "IsTextUnicode() returned TRUE, expected FALSE\n");
186     ok(Result == IS_TEXT_UNICODE_DBCS_LEADBYTE, "Result returned 0x%x, expected 0x%x\n", Result, IS_TEXT_UNICODE_DBCS_LEADBYTE);
187 
188     /* Korean */
189     SetupLocale(949, 949, -1);
190 
191     Result = IS_TEXT_UNICODE_DBCS_LEADBYTE;
192     ok(!IsTextUnicode(korean_with_lead, sizeof(korean_with_lead), &Result), "IsTextUnicode() returned TRUE, expected FALSE\n");
193     ok(Result == IS_TEXT_UNICODE_DBCS_LEADBYTE, "Result returned 0x%x, expected 0x%x\n", Result, IS_TEXT_UNICODE_DBCS_LEADBYTE);
194 
195     /* Traditional Chinese */
196     SetupLocale(950, 950, -1);
197 
198     Result = IS_TEXT_UNICODE_DBCS_LEADBYTE;
199     ok(!IsTextUnicode(traditional_chinese_with_lead, sizeof(traditional_chinese_with_lead), &Result), "IsTextUnicode() returned TRUE, expected FALSE\n");
200     ok(Result == IS_TEXT_UNICODE_DBCS_LEADBYTE, "Result returned 0x%x, expected 0x%x\n", Result, IS_TEXT_UNICODE_DBCS_LEADBYTE);
201 }
202