FreeRDP
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 
35 static 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 
103 static 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 
114 int 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 
153 int 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 }