2010-07-12 2 views
2

Я пишу слой обертки для использования с mingw, который обеспечивает приложение виртуальной средой UTF-8. Функции, которые имеют дело с именами файлов, - это обертки, которые конвертируют из UTF-8 и вызывают соответствующие функции «_w» и т. Д. Большая проблема, с которой я столкнулся, заключается в том, что Windows wchar_t - это 16-разрядная версия.Как лучше всего справляться с 16-битным wchar_t Windows?

Для операций с файловой системой это не имеет большого значения. Я могу просто конвертировать туда и обратно между UTF-8 и UTF-16, и все будет работать. Но стандартный API-интерфейс преобразования многобайтовых/широкоформатных символов не позволяет использовать символы multi-wchar_t.

Возможные решения:

  1. Обеспечить среду CESU-8 вместо UTF-8. Мне это действительно не нравится.
  2. Простой выход и поддержка только BMP. Обработать последовательности UTF-8 длиной 4 как недействительные.
  3. Расширение обертки для замены mingw's wchar_t с typedef int32_t wchar_t; и дело с WCHAR и wchar_t отличается. Это боль, но это может быть идеальным для переноса приложений, ожидающих чистой среды типа POSIX, и не использовать wchar_t для любых целей Windows-API.
  4. Ниже обходной:

mbrtowc выводит wchar_t, соответствующий высокий суррогат после прочтения первого 3 байта 4 байта UTF-8 символа а, и сохраняет оставшееся состояние в mbstate_t объекте. После получения следующего байта он объединяет его с сохраненным состоянием для вывода низкого суррогата. Если последний байт заканчивается недействительным, он возвращает -1 (с EILSEQ), а одиночный суррогат заканчивается в выходном потоке (плохой ...).

wcrtomb выводит первые 2 байта UTF-8 при обработке высокого суррогата и сохраняет оставшееся состояние в своем объекте mbstate_t. Когда он впоследствии обрабатывает низкий суррогат, он объединяет это с сохраненным состоянием для вывода последних 2 байтов UTF-8. Если действительный низкий суррогат не получен, он возвращает -1 (с EILSEQ), а неполная последовательность UTF-8 заканчивается в выходном потоке (плохая ...).

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

Недостатки в том, что он строго не соответствует строкам ISO C (wchar_t), и что он задерживает обнаружение некорректных символов до тех пор, пока не будет записан неправильный частичный вывод.

Я ищу информацию о различных вариантах, и особенно о предлагаемом вами взломе: разумно ли, могут ли противники вызвать серьезные ошибки, и есть ли какие-либо другие недостатки, которые я еще не рассматривал, чтобы система полностью работала. Я также был бы рад услышать любые другие возможные решения, о которых я не думал.

ответ

1

Я бы сделал что-то вроде # 4, но не генерирую никакого вывода, пока вы не убедитесь, что вход действителен.

  • mbrtowc должен декодировать весь персонаж. Если он находится вне BMP, тогда выведите высокий суррогат и сохраните низкий суррогат в mbstate_t.
  • wcrtomb должен хранить высокие суррогаты в mbstate_t, а затем выводить все 4 байта UTF-8, если символ действителен.
+0

Звучит неплохо, но я не уверен, что это возможно. Если 'mbrtowc' хранит низкий суррогат в' mbstate_t', тогда ему придется выводить 'wchar_t' на следующий вызов, не потребляя никакого ввода. Но возвращаемое значение 0 зарезервировано для преобразования нулевого байта/конца строки. Я предполагаю, что он мог бы потреблять дополнительный байт от следующего символа, но если это был однобайтовый символ, странная буферизация продолжилась. Как вы думаете? –

+0

Это сложно, потому что стандарт C предполагает, что 'wchar_t' может представлять любой символ, и Microsoft нарушила его. Я не думаю, что можно написать соответствующий «mbrtowc» с UTF-16. – dan04

+0

Возвращаемое значение 0 не может быть проблемой, если вызывающий код проверяет значение 'wch' вместо предположения U + 0000 на основе возвращаемого значения. Я сам не использую 'mbrtowc' (вместо этого встроенная функция преобразования, которая работает на целые строки), поэтому я не уверен, какая проблема будет на практике. – dan04

0

Если вы находитесь в окнах, вы конвертируете между UTF-16 и UTF-8 целую строку за раз, используя MultiByteToWideChar и WideCharToMultiByte.

В то время как режим по умолчанию в GCC представляет собой 32-битный wchar_t, есть компиляционные переключатели, которые изменяют это, и, более общо, c C++ specs не определяют размер wchar_t - на самом деле wchar_t может быть того же размера, что и char.

Если вы хотите избежать использования Windows API (в вашем коде оболочки Windows !?), используйте mbstowcs для преобразования всей строки за раз.

+0

Я думаю, вы неправильно поняли вопрос. Одна вещь, которую должна предоставить оболочка, - это функции C 'mbrtowc' и' wcrtomb' (и остальные функции преобразования многобайтовых/широких, которые в принципе просто называют эти основные функции), поскольку приложение может использовать их для обработки строк как символы. Предоставление этих функций является трудным из-за 16-битного 'wchar_t'. Конечно, легко обеспечить любую функцию, в которой вы можете обрабатывать целые строки за раз. –