1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | #include <xplatform.h> |
6 | |
7 | const int NSTRINGS = 6; |
8 | #ifdef _WIN32 |
9 | const wchar_t *utf8strings[] = { L"Managed" , |
10 | L"S\x00EEne kl\x00E2wen durh die wolken sint geslagen" , |
11 | L"\x0915\x093E\x091A\x0902 \x0936\x0915\x094D\x0928\x094B\x092E\x094D\x092F\x0924\x094D\x0924\x0941\x092E\x094D \x0964 \x0928\x094B\x092A\x0939\x093F\x0928\x0938\x094D\x0924\x093F \x092E\x093E\x092E\x094D" , |
12 | L"\x6211\x80FD\x541E\x4E0B\x73BB\x7483\x800C\x4E0D\x4F24\x8EAB\x4F53" , |
13 | L"\x10E6\x10DB\x10D4\x10E0\x10D7\x10E1\x10D8 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10DC\x10E3\x10D7\x10E3 \x10D9\x10D5\x10DA\x10D0 \x10D3\x10D0\x10DB\x10EE\x10E1\x10DC\x10D0\x10E1 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E1\x10DD\x10E4\x10DA\x10D8\x10E1\x10D0 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0, \x10EA\x10D4\x10EA\x10EE\x10DA\x10E1, \x10EC\x10E7\x10D0\x10DA\x10E1\x10D0 \x10D3\x10D0 \x10DB\x10D8\x10EC\x10D0\x10E1\x10D0, \x10F0\x10D0\x10D4\x10E0\x10D7\x10D0 \x10D7\x10D0\x10DC\x10D0 \x10DB\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0; \x10DB\x10DD\x10DB\x10EA\x10DC\x10D4\x10E1 \x10E4\x10E0\x10D7\x10D4\x10DC\x10D8 \x10D3\x10D0 \x10D0\x10E6\x10D5\x10E4\x10E0\x10D8\x10DC\x10D3\x10D4, \x10DB\x10D8\x10D5\x10F0\x10EE\x10D5\x10D3\x10D4 \x10DB\x10D0\x10E1 \x10E9\x10D4\x10DB\x10E1\x10D0 \x10DC\x10D3\x10DD\x10DB\x10D0\x10E1\x10D0, \x10D3\x10E6\x10D8\x10E1\x10D8\x10D7 \x10D3\x10D0 \x10E6\x10D0\x10DB\x10D8\x10D7 \x10D5\x10F0\x10EE\x10D4\x10D3\x10D5\x10D8\x10D3\x10D4 \x10DB\x10D6\x10D8\x10E1\x10D0 \x10D4\x10DA\x10D5\x10D0\x10D7\x10D0 \x10D9\x10E0\x10D7\x10DD\x10DB\x10D0\x10D0\x10E1\x10D0\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4," , |
14 | L"\x03A4\x03B7 \x03B3\x03BB\x03CE\x03C3\x03C3\x03B1 \x03BC\x03BF\x03C5 \x03AD\x03B4\x03C9\x03C3\x03B1\x03BD \x03B5\x03BB\x03BB\x03B7\x03BD\x03B9\x03BA\x03AE" , |
15 | L"\0" |
16 | }; |
17 | |
18 | |
19 | |
20 | char* utf16_to_utf8(const wchar_t *srcstring) |
21 | { |
22 | if ((srcstring == NULL) || (*srcstring == L'\0')) { |
23 | return 0; |
24 | } |
25 | size_t cchUTF16 = wcslen(srcstring) + 1; |
26 | int cbUTF8 = WideCharToMultiByte(CP_UTF8, 0, |
27 | srcstring, |
28 | (int)cchUTF16, |
29 | NULL, |
30 | 0/* request buffer size*/, |
31 | NULL, |
32 | NULL); |
33 | |
34 | char *pszUTF8 = (char*)CoreClrAlloc(sizeof(char) * (cbUTF8 + 1)); |
35 | int nc = WideCharToMultiByte(CP_UTF8, // convert to UTF-8 |
36 | 0, //default flags |
37 | srcstring, //source wide string |
38 | (int)cchUTF16, // length of wide string |
39 | pszUTF8, // destination buffer |
40 | cbUTF8, // destination buffer size |
41 | NULL, |
42 | NULL); |
43 | |
44 | if (!nc) |
45 | { |
46 | throw; |
47 | } |
48 | |
49 | pszUTF8[nc] = '\0'; |
50 | return pszUTF8; |
51 | } |
52 | |
53 | wchar_t* utf8_to_utf16(const char *utf8) |
54 | { |
55 | // Special case of empty input string |
56 | //wszTextUTF16 |
57 | wchar_t *wszTextUTF16 = 0; |
58 | if (!utf8 || !(*utf8)) |
59 | return wszTextUTF16; |
60 | size_t szUtf8 = strlen(utf8); |
61 | |
62 | //Get length (in wchar_t's) of resulting UTF-16 string |
63 | int cbUTF16 = ::MultiByteToWideChar( |
64 | CP_UTF8, // convert from UTF-8 |
65 | 0, // default flags |
66 | utf8, // source UTF-8 string |
67 | (int)szUtf8, // length (in chars) of source UTF-8 string |
68 | NULL, // unused - no conversion done in this step |
69 | 0 // request size of destination buffer, in wchar_t's |
70 | ); |
71 | |
72 | wszTextUTF16 = (wchar_t*)(CoreClrAlloc((cbUTF16 + 1) * sizeof(wchar_t))); |
73 | // Do the actual conversion from UTF-8 to UTF-16 |
74 | int nc = ::MultiByteToWideChar( |
75 | CP_UTF8, // convert from UTF-8 |
76 | 0, // default flags |
77 | utf8, // source UTF-8 string |
78 | (int)szUtf8, // length (in chars) of source UTF-8 string |
79 | wszTextUTF16, // destination buffer |
80 | cbUTF16); // size of destination buffer, in wchar_t's |
81 | |
82 | if (!nc) |
83 | { |
84 | throw; |
85 | } |
86 | //MultiByteToWideChar do not null terminate the string when cbMultiByte is not -1 |
87 | wszTextUTF16[nc] = '\0'; |
88 | return wszTextUTF16; |
89 | } |
90 | |
91 | char *get_utf8_string(int index) { |
92 | char *pszTextutf8 = utf16_to_utf8(utf8strings[index]); |
93 | return pszTextutf8; |
94 | } |
95 | |
96 | void free_utf8_string(char *str) |
97 | { |
98 | CoreClrFree(str); |
99 | } |
100 | |
101 | #else //Not WIndows |
102 | |
103 | //test strings |
104 | const char *utf8strings[] = { "Managed" , |
105 | "Sîne klâwen durh die wolken sint geslagen" , |
106 | "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्" , |
107 | "我能吞下玻璃而不伤身体" , |
108 | "ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე," , |
109 | "Τη γλώσσα μου έδωσαν ελληνική" , |
110 | "\0" |
111 | }; |
112 | |
113 | char *get_utf8_string(int index) { |
114 | return (char*)utf8strings[index]; |
115 | } |
116 | |
117 | void free_utf8_string(char *str) |
118 | { |
119 | // do nothing , we never allocated the temp buffer on non-windows |
120 | } |
121 | |
122 | #endif |
123 | |
124 | LPSTR build_return_string(const char* pReturn) |
125 | { |
126 | char *ret = 0; |
127 | if (pReturn == 0 || *pReturn == 0) |
128 | return ret; |
129 | |
130 | size_t strLength = strlen(pReturn); |
131 | ret = (LPSTR)(CoreClrAlloc(sizeof(char)* (strLength + 1))); |
132 | memset(ret, '\0', strLength + 1); |
133 | strncpy_s(ret, strLength + 1, pReturn, strLength); |
134 | return ret; |
135 | } |
136 | |
137 | // Modify the string builder in place, managed side validates. |
138 | extern "C" DLL_EXPORT void __cdecl StringBuilderParameterInOut(/*[In,Out] StringBuilder*/ char *s, int index) |
139 | { |
140 | // if string.empty |
141 | if (s == 0 || *s == 0) |
142 | return; |
143 | |
144 | char *pszTextutf8 = get_utf8_string(index); |
145 | |
146 | // do byte by byte validation of in string |
147 | size_t szLen = strlen(s); |
148 | for (size_t i = 0; i < szLen; i++) |
149 | { |
150 | if (s[i] != pszTextutf8[i]) |
151 | { |
152 | printf("[in] managed string do not match native string\n" ); |
153 | throw; |
154 | } |
155 | } |
156 | |
157 | // modify the string inplace |
158 | size_t outLen = strlen(pszTextutf8); |
159 | for (size_t i = 0; i < outLen; i++) { |
160 | s[i] = pszTextutf8[i]; |
161 | } |
162 | s[outLen] = '\0'; |
163 | free_utf8_string(pszTextutf8); |
164 | } |
165 | |
166 | //out string builder |
167 | extern "C" DLL_EXPORT void __cdecl StringBuilderParameterOut(/*[Out] StringBuilder*/ char *s, int index) |
168 | { |
169 | char *pszTextutf8 = get_utf8_string(index); |
170 | // modify the string inplace |
171 | size_t outLen = strlen(pszTextutf8); |
172 | for (size_t i = 0; i < outLen; i++) { |
173 | s[i] = pszTextutf8[i]; |
174 | } |
175 | s[outLen] = '\0'; |
176 | free_utf8_string(pszTextutf8); |
177 | } |
178 | |
179 | // return utf8 stringbuilder |
180 | extern "C" DLL_EXPORT char* __cdecl StringBuilderParameterReturn(int index) |
181 | { |
182 | char *pszTextutf8 = get_utf8_string(index); |
183 | size_t strLength = strlen(pszTextutf8); |
184 | LPSTR ret = (LPSTR)(CoreClrAlloc(sizeof(char)* (strLength + 1))); |
185 | memcpy(ret, pszTextutf8, strLength); |
186 | ret[strLength] = '\0'; |
187 | free_utf8_string(pszTextutf8); |
188 | return ret; |
189 | } |
190 | |
191 | extern "C" DLL_EXPORT LPSTR __cdecl StringParameterOut(/*[Out]*/ char *s, int index) |
192 | { |
193 | // return a copy |
194 | return build_return_string(s); |
195 | } |
196 | |
197 | // string |
198 | extern "C" DLL_EXPORT LPSTR __cdecl StringParameterInOut(/*[In,Out]*/ char *s, int index) |
199 | { |
200 | // return a copy |
201 | return build_return_string(s); |
202 | } |
203 | |
204 | // Utf8 field |
205 | typedef struct FieldWithUtf8 |
206 | { |
207 | char *pFirst; |
208 | int index; |
209 | }FieldWithUtf8; |
210 | |
211 | //utf8 struct field |
212 | extern "C" DLL_EXPORT void __cdecl TestStructWithUtf8Field(struct FieldWithUtf8 fieldStruct) |
213 | { |
214 | char *pszManagedutf8 = fieldStruct.pFirst; |
215 | int stringIndex = fieldStruct.index; |
216 | char *pszNative = 0; |
217 | size_t outLen = 0; |
218 | |
219 | if (pszManagedutf8 == 0 || *pszManagedutf8 == 0) |
220 | return; |
221 | |
222 | pszNative = get_utf8_string(stringIndex); |
223 | outLen = strlen(pszNative); |
224 | // do byte by byte comparision |
225 | for (size_t i = 0; i < outLen; i++) |
226 | { |
227 | if (pszNative[i] != pszManagedutf8[i]) |
228 | { |
229 | printf("Native and managed string do not match.\n" ); |
230 | throw; |
231 | } |
232 | } |
233 | free_utf8_string(pszNative); |
234 | } |
235 | |
236 | // test c# out keyword |
237 | extern "C" DLL_EXPORT void __cdecl StringParameterRefOut(/*out*/ char **s, int index) |
238 | { |
239 | char *pszTextutf8 = get_utf8_string(index); |
240 | size_t strLength = strlen(pszTextutf8); |
241 | *s = (LPSTR)(CoreClrAlloc(sizeof(char)* (strLength + 1))); |
242 | memcpy(*s, pszTextutf8, strLength); |
243 | (*s)[strLength] = '\0'; |
244 | free_utf8_string(pszTextutf8); |
245 | } |
246 | |
247 | //c# ref |
248 | extern "C" DLL_EXPORT void __cdecl StringParameterRef(/*ref*/ char **s, int index) |
249 | { |
250 | char *pszTextutf8 = get_utf8_string(index); |
251 | size_t strLength = strlen(pszTextutf8); |
252 | // do byte by byte validation of in string |
253 | size_t szLen = strlen(*s); |
254 | for (size_t i = 0; i < szLen; i++) |
255 | { |
256 | if ((*s)[i] != pszTextutf8[i]) |
257 | { |
258 | printf("[in] managed string do not match native string\n" ); |
259 | throw; |
260 | } |
261 | } |
262 | |
263 | if (*s) |
264 | { |
265 | CoreClrFree(*s); |
266 | } |
267 | // overwrite the orginal |
268 | *s = (LPSTR)(CoreClrAlloc(sizeof(char)* (strLength + 1))); |
269 | memcpy(*s, pszTextutf8, strLength); |
270 | (*s)[strLength] = '\0'; |
271 | free_utf8_string(pszTextutf8); |
272 | } |
273 | |
274 | // delegate test |
275 | typedef void (__cdecl * Callback)(char *text, int index); |
276 | extern "C" DLL_EXPORT void __cdecl Utf8DelegateAsParameter(Callback managedCallback) |
277 | { |
278 | for (int i = 0; i < NSTRINGS; ++i) |
279 | { |
280 | char *pszNative = get_utf8_string(i); |
281 | managedCallback(pszNative, i); |
282 | free_utf8_string(pszNative); |
283 | } |
284 | } |