| 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 | } |