Использование ICU для реализации моего собственного фасета codecvt

Я хочу реализовать codecvt использовать ICU для преобразования из любой кодировки символов (которую поддерживает ICU) в UTF-8 внутри. Я знаю что codecvt_byname существует и что его можно использовать для выполнения части того, что я хочу, как показано в этом примере. Проблемы с этим примером состоят в том, что он (1) использует широкие символьные потоки (я хочу использовать "обычные", ориентированные на байты потоки) и (2) требует 2 потока для выполнения преобразования. Вместо этого я хочу один поток, как:

locale loc( locale(), new icu_codecvt( "ISO-8859-1" ) );
ifstream ifs;
ifs.imbue( loc );
ifs.open( "/path/to/some/file.txt" );
// data read from ifs here will have been converted from ISO-8859-1 to UTF-8

Следовательно, я хочу сделать реализацию, как это, но с использованием ICU, а не iconv, Учитывая это, моя реализация do_in() является:

icu_codecvt::result icu_codecvt::do_in( state_type &state,
                                        extern_type const *from, extern_type const *from_end,
                                        extern_type const *&from_next, intern_type *to,
                                        intern_type *to_end, intern_type *&to_next ) const {
  from_next = from;
  to_next = to;
  if ( always_noconv_ )
    return noconv;

  our_state *const s = state_store_.get( state );
  UErrorCode err = U_ZERO_ERROR;
  ucnv_convertEx(
    s->utf8_conv_, s->extern_conv_, &to_next, to_end, &from_next, from_end,
    nullptr, nullptr, nullptr, nullptr, false, false, &err
  );
  if ( err == U_TRUNCATED_CHAR_FOUND )
    return partial;
  return U_SUCCESS( err ) ? ok : error;
}

our_state объект поддерживает два UConverter* указатели, один для "внешней" кодировки (в этом примере ISO-8859-1) и один для кодировки UTF-8.

Мои вопросы:

  1. Должен ли я указать nullptr для буфера "pivot", как указано выше, или поставьте мой собственный?
  2. Я не уверен, когда, если когда-либо, я должен установить reset аргумент (в настоящее время первый false выше) до true,
  3. Не понятно, как я узнаю, когда устанавливать flush аргумент (в настоящее время второй false выше) до trueто есть, как я знаю, когда был достигнут конец ввода.

Небольшая помощь?

1 ответ

Фасет codecvt не предназначен для преобразования между различными кодировками. Вместо этого он преобразуется из внешнего кодирования, где один символ, возможно, кодируется с использованием нескольких внешних слов (обычно байтов), во внутреннее представление, где каждый символ представлен ровно одним словом (например, char, wchar_t, char16_t и т. Д.).

С этой точки зрения не имеет смысла "заканчивать" внутреннюю последовательность символов. Если больше нет доступных внешних слов, преобразование выполняется, и если последний символ остался неполным, это ошибка в переводе. Таким образом, нет необходимости указывать, что преобразование завершено и, соответственно, нет интерфейса. Это должно прояснить, что аргумент "flush" действительно всегда должен быть "false".

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

Параметр "reset", вероятно, предназначен для поиска в потоке. Я думаю, что filebuf должен предоставлять свежий объект state_type при поиске. Это, вероятно, будет указанием на то, что внутренние компоненты отделения интенсивной терапии хотят быть сброшены. Тем не менее, я не знаю об интерфейсе ICU. Таким образом, я также не знаю, хотите ли вы предоставить сводный буфер.

Другие вопросы по тегам