JNI: преобразование строки Java в кодовую страницу 1252 - PullRequest
1 голос
/ 29 марта 2012

Я использую JNI для взаимодействия между Java-программой и функцией C ++. Функция C ++ работает с многобайтовыми строками (CP 1252). Я использую этот код C ++ для преобразования строки Java в символ *:

char *arg=(char*) jEnv->GetStringUTFChars(jArg2,0);

Это прекрасно работает, если у меня нет высокоуровневых персонажей. Например, если мой ввод:

Алан (UTF: c2 6c 61 6e 20 4a 6f 6e 65 7e)

Я вижу, что результирующий аргумент:

c3 82 6c 61 6e

Но я бы ожидал увидеть:

c0 6c 61 6e

Видя, что GetStringUTFChars () должен возвращать строки UTF, я попытался получить строку Unicode с помощью GetStringChars () и преобразовать ее через WideCharToMultiByte ():

const jchar *str=jEnv->GetStringChars(jArg2,0);
WideCharToMultiByte(CP_UTF8,0,(LPCWSTR) str,jEnv->GetStringLength(jArg2),str,szStr,0,0);

(можно предположить, что я выделил str и правильно установил szStr). В этой ситуации я вижу это в результирующей стр:

c3 82 6c 61 6e

Я пробовал другие значения CP_ для первого параметра для WideCharToMultiByte, но ни одно из них не дает полезных результатов (они либо возвращают вышеуказанное, либо заменяют '?' На 'À'.

Я ожидаю, что каким-то образом я смогу получить эту результирующую стр:

c0 6c 61 6e

Но пока мне не повезло.

Ответы [ 2 ]

3 голосов
/ 30 марта 2012

Java использует модифицированную версию UTF-8. Вот цитата из документации Java:

Модифицированный UTF-8 не нов для платформы Java, но это что-то что разработчики приложений должны быть более осведомлены при конвертации текст, который может содержать дополнительные символы в и из UTF-8. Главное помнить, что некоторые интерфейсы J2SE используют кодировка, похожая на UTF-8, но несовместимая с ней. это кодирование в прошлом иногда называлось «модифицированный Java UTF-8» или (неправильно) просто "UTF-8". Для J2SE 5.0 документация обновляется, чтобы единообразно назвать его «измененным UTF-8».

Несовместимость между модифицированным UTF-8 и стандартным стеблем UTF-8. из двух отличий. Во-первых, модифицированный UTF-8 представляет символ U + 0000 в качестве двухбайтовой последовательности 0xC0 0x80, тогда как стандарт UTF-8 использует однобайтовое значение 0x0. Во-вторых, модифицированный UTF-8 представляет дополнительные символы путем раздельного кодирования двух суррогатных кодов единицы их представления UTF-16. Каждый из суррогатных кодовых единиц представлен тремя байтами, всего шесть байтов. стандарт UTF-8, с другой стороны, использует одну четырехбайтовую последовательность для полный характер.

Модифицированный UTF-8 используется виртуальной машиной Java и интерфейсами прикрепленный к нему (такой как Java Native Interface, различные инструменты интерфейсы, или файлы классов Java), в java.io.DataInput и Интерфейсы и классы DataOutput, реализующие или использующие их, и для сериализации. Собственный интерфейс Java предоставляет процедуры, которые конвертировать в и из модифицированного UTF-8. Стандарт UTF-8, с другой стороны, поддерживается классом String, java.io.InputStreamReader и Классы OutputStreamWriter, средства java.nio.charset и многие другие API-интерфейсы, расположенные поверх них.

Поскольку модифицированный UTF-8 несовместим со стандартом UTF-8, он важно не использовать один, где другой нужен. Модифицированная банка UTF-8 использоваться только с интерфейсами Java, описанными выше. Во всех остальных случаи, в частности, для потоков данных, которые могут приходить или могут быть интерпретируется программным обеспечением, которое не основано на платформе Java, должен использоваться стандарт UTF-8. Процедуры нативного интерфейса Java, которые Преобразование в и из модифицированных UTF-8 не может использоваться, когда стандарт UTF-8 требуется.

Последовательность байтов c2 6c 61 6e 20 4a 6f 6e 65 7e недопустима в соответствии со стандартом UTF-8. В cp1252 той же самой последовательностью байтов будет строка Âlan Jone~ (обратите внимание Â вместо À).

В соответствии со стандартом UTF-8 строка Àlan Jone~ будет представлять собой последовательность байтов c3 80 6c 61 6e 20 4a 6f 6e 65 7e (уведомление c3 80 6c вместо c2 6c).

Все строки Java изначально имеют формат UTF-16, поэтому вам не нужно извлекать строку как UTF-8. Используйте GetStringChars(), чтобы получить оригинальные символы в кодировке UTF-16 и передать их как есть WideCharToMultiByte(), указав 1252 в качестве кодовой страницы (обратите внимание, в вашем примере вы используете str для обоих входных буферов UTF-16 и выходной буфер cp1252 - не путайте ваши переменные!), например:

const jchar *str = jEnv->GetStringChars(jArg2,0); 
char *cp1252 = NULL;
int len = WideCharToMultiByte(1252, 0, (LPCWSTR)str, jEnv->GetStringLength(jArg2), NULL, 0, 0, 0);
if (len > 0)
{
    cp1252 = new char[len + 1];
    WideCharToMultiByte(1252, 0, (LPCWSTR)str, jEnv->GetStringLength(jArg2), cp1252, len, 0, 0); 
    cp1252[len] = 0;
}
0 голосов
/ 29 марта 2012

Кодовая страница 1252, Windows ANSI Western, является надмножеством ISO Latin 1. Это подмножество Unicode. Таким образом, если вы можете жить без знака евро и некоторых других добавленных символов Microsoft, просто отбросьте любую кодовую точку Unicode выше 255, и у вас есть действительная строка в кодировке cp 1252.

Для правильного использования WideCharToMultiByte (более общее преобразование, например, поддержка знака евро), прочитайте документацию и обратите внимание, например, на. значения флага.

Или, как мы обычно говорили на Usenet о тех, кто хотел бы, чтобы другие читали для них документацию и рассказывали им, что важно, а что нет, RTFM, пожалуйста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...