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
7const int NSTRINGS = 6;
8#ifdef _WIN32
9const wchar_t *utf8strings[] = { L"Managed",
10L"S\x00EEne kl\x00E2wen durh die wolken sint geslagen" ,
11L"\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",
12L"\x6211\x80FD\x541E\x4E0B\x73BB\x7483\x800C\x4E0D\x4F24\x8EAB\x4F53",
13L"\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,",
14L"\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",
15L"\0"
16};
17
18
19
20char* 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
53wchar_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
91char *get_utf8_string(int index) {
92 char *pszTextutf8 = utf16_to_utf8(utf8strings[index]);
93 return pszTextutf8;
94}
95
96void free_utf8_string(char *str)
97{
98 CoreClrFree(str);
99}
100
101#else //Not WIndows
102
103//test strings
104const char *utf8strings[] = { "Managed",
105"Sîne klâwen durh die wolken sint geslagen",
106"काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्",
107"我能吞下玻璃而不伤身体",
108"ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე,",
109"Τη γλώσσα μου έδωσαν ελληνική",
110"\0"
111};
112
113char *get_utf8_string(int index) {
114 return (char*)utf8strings[index];
115}
116
117void free_utf8_string(char *str)
118{
119 // do nothing , we never allocated the temp buffer on non-windows
120}
121
122#endif
123
124LPSTR 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.
138extern "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
167extern "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
180extern "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
191extern "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
198extern "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
205typedef struct FieldWithUtf8
206{
207 char *pFirst;
208 int index;
209}FieldWithUtf8;
210
211//utf8 struct field
212extern "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
237extern "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
248extern "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
275typedef void (__cdecl * Callback)(char *text, int index);
276extern "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}