我有一个通过JNI使用C ++ DLL的Java应用程序。一些DLL的方法接受字符串参数,其中一些返回包含字符串的对象。
目前DLL不支持Unicode,因此字符串处理相当简单:
我现在正在修改DLL以支持Unicode,切换到使用TCHAR类型(当定义UNICODE时使用Windows的WCHAR数据类型)。修改DLL进展顺利,但我不知道如何修改代码的JNI部分。
我现在唯一能想到的是:
这个方法唯一的问题是我不确定要使用什么字符集名称。 WCHAR是2个字节长,所以我很确定它是UTF-16,但是在java方面有3个可能性。 UTF-16,UTF-16BE和UTF-16LE。我没有找到任何文档告诉我字节顺序是什么,但我可以从一些快速测试中找到它。
有更好的方法吗?如果可能的话,我想继续在DLL中构造jstring对象,因为这样我就不必修改那些方法的任何用法。但是,NewString JNI方法不采用字符集标识符。
答案 0 :(得分:7)
This answer表明不保证WCHARS的字节顺序......
由于您使用的是Windows,因此可以尝试WideCharToMultiByte
将WCHAR转换为UTF-8,然后使用现有的JNI代码。
由于lpMultiByteStr
参数可能存在缓冲区溢出,因此您需要谨慎使用WideCharToMultiByte。为了解决此问题,您应该调用该函数两次,首先将lpMultiByteStr
设置为NULL
并将cbMultiByte
设置为零 - 这将返回所需的lpMultiByteStr
缓冲区的长度试图写信给它。获得长度后,您可以分配所需大小的缓冲区并再次调用该函数。
示例代码:
int utf8_length;
wchar_t* utf16 = ...;
utf8_length = WideCharToMultiByte(
CP_UTF8, // Convert to UTF-8
0, // No special character conversions required
// (UTF-16 and UTF-8 support the same characters)
utf16, // UTF-16 string to convert
-1, // utf16 is NULL terminated (if not, use length)
NULL, // Determining correct output buffer size
0, // Determining correct output buffer size
NULL, // Must be NULL for CP_UTF8
NULL); // Must be NULL for CP_UTF8
if (utf8_length == 0) {
// Error - call GetLastError for details
}
char* utf8 = ...; // Allocate space for UTF-8 string
utf8_length = WideCharToMultiByte(
CP_UTF8, // Convert to UTF-8
0, // No special character conversions required
// (UTF-16 and UTF-8 support the same characters)
utf16, // UTF-16 string to convert
-1, // utf16 is NULL terminated (if not, use length)
utf8, // UTF-8 output buffer
utf8_length, // UTF-8 output buffer size
NULL, // Must be NULL for CP_UTF8
NULL); // Must be NULL for CP_UTF8
if (utf8_length == 0) {
// Error - call GetLastError for details
}
答案 1 :(得分:2)
我找到了关于字节顺序标记的a little faq。 同样来自FAQ:
UTF-16和UTF-32分别使用两个和四个字节长的代码单元。对于这些UTF,有三种子风格:BE,LE和未标记。 BE形式使用大端字节序列化(最重要的字节优先),LE形式使用小端字节序列化(最低有效字节优先),未标记形式默认使用大端字节序列化,但可能包含字节顺序在开头标记以指示使用的实际字节序列化。
我假设在java方面,UTF-16将尝试找到此BOM并正确处理编码。我们都知道假设有多危险......
因评论而编辑:
Microsoft使用UTF16小端。 Java UTF-16尝试解释BOM。缺少BOM时,默认为UTF-16BE。 BE和LE变体忽略了BOM。