FreeRDP
Loading...
Searching...
No Matches
unicode_android.c
1
21#include <winpr/config.h>
22#include <winpr/assert.h>
23#include <winpr/string.h>
24
25#include "../utils/android.h"
26#include "unicode.h"
27
28#ifndef MIN
29#define MIN(a, b) (a) < (b) ? (a) : (b)
30#endif
31
32#include "../log.h"
33#define TAG WINPR_TAG("unicode")
34
35static int convert_int(JNIEnv* env, const void* data, size_t size, void* buffer, size_t buffersize,
36 BOOL toUTF16)
37{
38 WINPR_ASSERT(env);
39 WINPR_ASSERT(data || (size == 0));
40 WINPR_ASSERT(buffer || (buffersize == 0));
41
42 jstring utf8 = (*env)->NewStringUTF(env, "UTF-8");
43 jstring utf16 = (*env)->NewStringUTF(env, "UTF-16LE");
44 jclass stringClass = (*env)->FindClass(env, "java/lang/String");
45
46 if (!utf8 || !utf16 || !stringClass)
47 {
48 WLog_ERR(TAG, "utf8-%p, utf16=%p, stringClass=%p", utf8, utf16, stringClass);
49 return -1;
50 }
51
52 jmethodID constructorID =
53 (*env)->GetMethodID(env, stringClass, "<init>", "([BLjava/lang/String;)V");
54 jmethodID getBytesID =
55 (*env)->GetMethodID(env, stringClass, "getBytes", "(Ljava/lang/String;)[B");
56 if (!constructorID || !getBytesID)
57 {
58 WLog_ERR(TAG, "constructorID=%p, getBytesID=%p", constructorID, getBytesID);
59 return -2;
60 }
61
62 jbyteArray ret = (*env)->NewByteArray(env, size);
63 if (!ret)
64 {
65 WLog_ERR(TAG, "NewByteArray(%" PRIuz ") failed", size);
66 return -3;
67 }
68
69 (*env)->SetByteArrayRegion(env, ret, 0, size, data);
70
71 jobject obj = (*env)->NewObject(env, stringClass, constructorID, ret, toUTF16 ? utf8 : utf16);
72 if (!obj)
73 {
74 WLog_ERR(TAG, "NewObject(String, byteArray, UTF-%d) failed", toUTF16 ? 16 : 8);
75 return -4;
76 }
77
78 jbyteArray res = (*env)->CallObjectMethod(env, obj, getBytesID, toUTF16 ? utf16 : utf8);
79 if (!res)
80 {
81 WLog_ERR(TAG, "CallObjectMethod(String, getBytes, UTF-%d) failed", toUTF16 ? 16 : 8);
82 return -4;
83 }
84
85 jsize rlen = (*env)->GetArrayLength(env, res);
86 if (buffersize > 0)
87 {
88 if (rlen > buffersize)
89 {
90 SetLastError(ERROR_INSUFFICIENT_BUFFER);
91 return 0;
92 }
93 rlen = MIN(rlen, buffersize);
94 (*env)->GetByteArrayRegion(env, res, 0, rlen, buffer);
95 }
96
97 if (toUTF16)
98 rlen /= sizeof(WCHAR);
99
100 return rlen;
101}
102
103static int convert(const void* data, size_t size, void* buffer, size_t buffersize, BOOL toUTF16)
104{
105 int rc;
106 JNIEnv* env = NULL;
107 jboolean attached = winpr_jni_attach_thread(&env);
108 rc = convert_int(env, data, size, buffer, buffersize, toUTF16);
109 if (attached)
110 winpr_jni_detach_thread();
111 return rc;
112}
113
114int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
115 LPWSTR lpWideCharStr, int cchWideChar)
116{
117 size_t cbCharLen = (size_t)cbMultiByte;
118
119 WINPR_UNUSED(dwFlags);
120
121 /* If cbMultiByte is 0, the function fails */
122 if ((cbMultiByte == 0) || (cbMultiByte < -1))
123 return 0;
124
125 if (cchWideChar < 0)
126 return -1;
127
128 if (cbMultiByte < 0)
129 {
130 const size_t len = strlen(lpMultiByteStr);
131 if (len >= INT32_MAX)
132 return 0;
133 cbCharLen = (int)len + 1;
134 }
135 else
136 cbCharLen = cbMultiByte;
137
138 WINPR_ASSERT(lpMultiByteStr);
139 switch (CodePage)
140 {
141 case CP_ACP:
142 case CP_UTF8:
143 break;
144
145 default:
146 WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
147 return 0;
148 }
149
150 return convert(lpMultiByteStr, cbCharLen, lpWideCharStr, cchWideChar * sizeof(WCHAR), TRUE);
151}
152
153int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
154 LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
155 LPBOOL lpUsedDefaultChar)
156{
157 size_t cbCharLen = (size_t)cchWideChar;
158
159 WINPR_UNUSED(dwFlags);
160 /* If cchWideChar is 0, the function fails */
161 if ((cchWideChar == 0) || (cchWideChar < -1))
162 return 0;
163
164 if (cbMultiByte < 0)
165 return -1;
166
167 WINPR_ASSERT(lpWideCharStr);
168 /* If cchWideChar is -1, the string is null-terminated */
169 if (cchWideChar == -1)
170 {
171 const size_t len = _wcslen(lpWideCharStr);
172 if (len >= INT32_MAX)
173 return 0;
174 cbCharLen = (int)len + 1;
175 }
176 else
177 cbCharLen = cchWideChar;
178
179 /*
180 * if cbMultiByte is 0, the function returns the required buffer size
181 * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
182 */
183 return convert(lpWideCharStr, cbCharLen * sizeof(WCHAR), lpMultiByteStr, cbMultiByte, FALSE);
184}