Конвертация из произвольной CP в UTF-16

Тема в разделе "WASM.WIN32", создана пользователем SadKo, 27 дек 2018.

  1. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Всем привет!
    Курю тут MSDN по работе с юникодом, и что-то не пойму, как завести функции транлсяции кодировок для работы в потоковом режиме.
    Наваял вот такой кодес:
    Код (C):
    1.  
    2. #include <stdint.h>
    3. #include <malloc.h>
    4. #include <stdio.h>
    5. #include <errno.h>
    6. #include <string.h>
    7.  
    8. #include <winnls.h>
    9. #include <windows.h>
    10.  
    11.     enum status_codes
    12.     {
    13.         STATUS_OK,
    14.         STATUS_UNSPECIFIED,
    15.         STATUS_LOADING,
    16.         STATUS_UNKNOWN_ERR,
    17.         STATUS_NO_MEM,
    18.         STATUS_NOT_FOUND,
    19.         STATUS_BAD_FORMAT,
    20.         STATUS_UNSUPPORTED_FORMAT,
    21.         STATUS_CORRUPTED_FILE,
    22.         STATUS_NO_DATA,
    23.         STATUS_INVALID_UID,
    24.         STATUS_DISCONNECTED,
    25.         STATUS_BAD_ARGUMENTS,
    26.         STATUS_NOT_BOUND,
    27.         STATUS_BAD_STATE,
    28.         STATUS_NOT_IMPLEMENTED,
    29.         STATUS_ALREADY_EXISTS,
    30.         STATUS_OVERFLOW,
    31.         STATUS_BAD_HIERARCHY,
    32.         STATUS_DUPLICATED,
    33.         STATUS_TOO_BIG,
    34.         STATUS_PERMISSION_DENIED,
    35.         STATUS_IO_ERROR,
    36.         STATUS_NO_FILE,
    37.         STATUS_EOF,
    38.         STATUS_CLOSED,
    39.         STATUS_NOT_SUPPORTED,
    40.         STATUS_INVALID_VALUE,
    41.         STATUS_BAD_LOCALE,
    42.         STATUS_NO_DEVICE,
    43.         STATUS_OPENED,
    44.         STATUS_BAD_TYPE,
    45.  
    46.         STATUS_TOTAL,
    47.         STATUS_MAX = STATUS_TOTAL - 1,
    48.         STATUS_SUCCESS = STATUS_OK
    49.     };
    50.  
    51.     typedef int     status_t;
    52.  
    53. #define CBUF_SIZE   0x20
    54. #define WBUF_SIZE   0x20
    55.  
    56. status_t convert_to_utf16(const char *out, const char *in, UINT cp)
    57. {
    58.     FILE *inf, *outf;
    59.  
    60.     if ((inf = fopen(in, "r")) == NULL)
    61.         return STATUS_NOT_FOUND;
    62.     if ((outf = fopen(out, "wb")) == NULL)
    63.     {
    64.         fclose(inf);
    65.         return STATUS_PERMISSION_DENIED;
    66.     }
    67.  
    68.     WCHAR *wbuf = reinterpret_cast<WCHAR *>(malloc(WBUF_SIZE * sizeof(WCHAR)));
    69.     if (wbuf == NULL)
    70.     {
    71.         fclose(outf);
    72.         fclose(inf);
    73.         return STATUS_NO_MEM;
    74.     }
    75.  
    76.     CHAR *cbuf = reinterpret_cast<CHAR *>(malloc(CBUF_SIZE * sizeof(CHAR)));
    77.     if (cbuf == NULL)
    78.     {
    79.         free(wbuf);
    80.         fclose(outf);
    81.         fclose(inf);
    82.         return STATUS_NO_MEM;
    83.     }
    84.  
    85.     // Main cycle
    86.     int isize = 0;
    87.     status_t res = STATUS_OK;
    88.  
    89.     while (res == STATUS_OK)
    90.     {
    91.         // Read data
    92.         size_t nbytes = fread(&cbuf[isize], sizeof(CHAR), CBUF_SIZE - isize, inf);
    93.         if (nbytes == 0)
    94.         {
    95.             res = (feof(inf)) ? STATUS_OK : STATUS_IO_ERROR;
    96.             break;
    97.         }
    98.         isize += nbytes;
    99.  
    100.         // Convert characters
    101.         int n = MultiByteToWideChar(cp, 0, cbuf, isize, wbuf, WBUF_SIZE);
    102.         if (n == 0)
    103.         {
    104.             switch (GetLastError())
    105.             {
    106.                 case ERROR_INSUFFICIENT_BUFFER:
    107.                     res = STATUS_NO_MEM;
    108.                     break;
    109.                 case ERROR_INVALID_FLAGS:
    110.                 case ERROR_INVALID_PARAMETER:
    111.                     res = STATUS_BAD_STATE;
    112.                     break;
    113.  
    114.                 case ERROR_NO_UNICODE_TRANSLATION:
    115.                     res = STATUS_BAD_LOCALE;
    116.                     break;
    117.                 default:
    118.                     res = STATUS_UNKNOWN_ERR;
    119.                     break;
    120.             }
    121.         }
    122.         else
    123.         {
    124.             // Write data
    125.             nbytes = fwrite(wbuf, sizeof(WCHAR), n, outf);
    126.             if (nbytes != size_t(n))
    127.             {
    128.                 res = STATUS_IO_ERROR;
    129.                 break;
    130.             }
    131.  
    132.             // Move pointer (yes, this is dumb)
    133.             CHAR *ebuf = cbuf;
    134.             for (size_t i=n; i>0; --i)
    135.                 ebuf = CharNextExA(cp, ebuf, 0);
    136.  
    137.             nbytes = ebuf - cbuf;
    138.             isize -= nbytes;
    139.             if (isize > 0)
    140.                 memmove(cbuf, ebuf, isize);
    141.         }
    142.     }
    143.  
    144.     if ((res == STATUS_OK) && (isize != 0))
    145.         res = STATUS_CORRUPTED_FILE;
    146.  
    147.     free(cbuf);
    148.     free(wbuf);
    149.     fclose(outf);
    150.     fclose(inf);
    151.     return res;
    152. }
    Ну и вызываю функцию:
    Код (C):
    1. int main()
    2. {
    3.     convert_to_utf16("out2-utf16.txt", "in2-utf8-ru.txt", CP_UTF8);
    4.     return 0;
    5. }
    На выходе получается какое-то говно, в основном проблема из-за неправильного позиционирования тут:
    Код (C):
    1.             // Move pointer (yes, this is dumb)
    2.             CHAR *ebuf = cbuf;
    3.             for (size_t i=n; i>0; --i)
    4.                 ebuf = CharNextExA(cp, ebuf, 0);
    Похоже, оно не понимает UTF-8 или как-то неправильно работает.

    Собственно, вопрос: как правильно находить место в cbuf, на котором функция MultiByteToWideChar прервала свою работу? А то в говнолинухе есть замечательная функция iconv, которая всё это учитывает и возвращает все необходимые для дальнейшей потоковой обработки значения, а вот в WinAPI что-то не могу найти.
     
  2. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    то есть она просто падает с ошибкой и не возвращает, сколько символов были корректно переведены? можно посмотреть как mbstowcs реализована в венде, ну или просто ее заюзать... по идее она должна возвращать количество корректно переведенных символов до первой ошибки...
    --- Сообщение объединено, 27 дек 2018 ---
    почитай msdn про флаг MB_ERR_INVALID_CHARS...
    --- Сообщение объединено, 27 дек 2018 ---
    да и вообще, ты можешь эту функцию вызывать для каждого отдельного код пойнта... сначала вызываешь с нулл в роли буффера, чтобы определить длину утф-8 код пойнта, потом его конвертируешь... передвигаешь указатели в двух буфферах в зависимости от длины код пойнта...
     
  3. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Нет, она не падает. На выходе получаются "заеды" из-за того, что мы неправильно находим позицию в буфере cbuf, где остановилось. Получается вот такой текст на выходе:
    На однобайтных кодировках работает хорошо, а вот при скармливании UTF-8 получается такая хрень.

    Да это большой оверхед на вызов, хотелось как-то пачками данные обрабатывать.
     
  4. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    и вообще, что мешает юзать либиконв на венде?
     
  5. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Чем меньше депенденсей от сторонних библиотек - тем лучше для меня.
     
  6. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    В общем, решил пока через такой костыль:
    Код (C):
    1. status_t convert_to_utf16(const char *out, const char *in, UINT cp)
    2. {
    3.     FILE *inf, *outf;
    4.  
    5.     if ((inf = fopen(in, "rb")) == NULL)
    6.         return STATUS_NOT_FOUND;
    7.     if ((outf = fopen(out, "wb")) == NULL)
    8.     {
    9.         fclose(inf);
    10.         return STATUS_PERMISSION_DENIED;
    11.     }
    12.  
    13.     WCHAR *wbuf = reinterpret_cast<WCHAR *>(malloc(WBUF_SIZE * sizeof(WCHAR)));
    14.     if (wbuf == NULL)
    15.     {
    16.         fclose(outf);
    17.         fclose(inf);
    18.         return STATUS_NO_MEM;
    19.     }
    20.  
    21.     CHAR *cbuf = reinterpret_cast<CHAR *>(malloc(CBUF_SIZE * sizeof(CHAR)));
    22.     if (cbuf == NULL)
    23.     {
    24.         free(wbuf);
    25.         fclose(outf);
    26.         fclose(inf);
    27.         return STATUS_NO_MEM;
    28.     }
    29.  
    30.     // Main cycle
    31.     ssize_t isize = 0;
    32.     status_t res = STATUS_OK;
    33.  
    34.     while (res == STATUS_OK)
    35.     {
    36.         // Read data
    37.         size_t nbytes = fread(&cbuf[isize], sizeof(CHAR), CBUF_SIZE - isize, inf);
    38.         if (nbytes == 0)
    39.         {
    40.             res = (feof(inf)) ? STATUS_OK : STATUS_IO_ERROR;
    41.             break;
    42.         }
    43.         isize += nbytes;
    44.  
    45.         // Convert characters
    46.         ssize_t n = MultiByteToWideChar(cp, 0, cbuf, isize, wbuf, WBUF_SIZE);
    47.         if (n == 0)
    48.         {
    49.             switch (GetLastError())
    50.             {
    51.                 case ERROR_INSUFFICIENT_BUFFER:
    52.                     res = STATUS_NO_MEM;
    53.                     break;
    54.                 case ERROR_INVALID_FLAGS:
    55.                 case ERROR_INVALID_PARAMETER:
    56.                     res = STATUS_BAD_STATE;
    57.                     break;
    58.  
    59.                 case ERROR_NO_UNICODE_TRANSLATION:
    60.                     res = STATUS_BAD_LOCALE;
    61.                     break;
    62.                 default:
    63.                     res = STATUS_UNKNOWN_ERR;
    64.                     break;
    65.             }
    66.         }
    67.         else
    68.         {
    69.             // If function meets invalid sequence, it replaces the codepoint with such magic value
    70.             // We should know if function has failed
    71.             if (wbuf[n-1] == 0xfffd)
    72.                 n--;
    73.  
    74.             // Write data
    75.             nbytes = fwrite(wbuf, sizeof(WCHAR), n, outf);
    76.             if (nbytes != size_t(n))
    77.             {
    78.                 res = STATUS_IO_ERROR;
    79.                 break;
    80.             }
    81.  
    82.             // Estimate number of bytes decoded (yep, this is dumb but no way...)
    83.             n = WideCharToMultiByte(cp, 0, wbuf, n, NULL, 0, 0, 0); // terminating 0
    84.             if ((n <= 0) || (n > isize))
    85.             {
    86.                 res = STATUS_IO_ERROR;
    87.                 break;
    88.             }
    89.  
    90.             isize -= n;
    91.             if (isize > 0)
    92.                 memmove(cbuf, &cbuf[n], isize);
    93.         }
    94.     }
    95.  
    96.     if ((res == STATUS_OK) && (isize != 0))
    97.         res = STATUS_CORRUPTED_FILE;
    98.  
    99.     free(cbuf);
    100.     free(wbuf);
    101.     fclose(outf);
    102.     fclose(inf);
    103.     return res;
    104. }
    Говно, конечно, но лучше варианта через нативные функции пока не наблюдаю.
     
    M0rg0t нравится это.
  7. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    меня канеш забавят такие вещи, когда вся функция написана по сути на сишечке без каких-либо намеков на плюсы, и вдруг по какой-то неведомой причине возникает реинтерпрет каст...
     
  8. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Ну да, я программирую на Си с классами.
     
  9. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    SadKo, ты читаешь и кодируешь блоками по 32 байта. А размер UTF-8 символа не фиксирован. Значит символ из 2+ байт может оказаться наполовину в одном блоке, наполовину - в другом. На выходе в таком случае как раз и будут такие зарубки.
     
    Rel нравится это.
  10. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    603
    Намедни тоже надо было сделать преобразовать форматов текста.
    Код (ASM):
    1. ;Таблица для преобразования ANSI CP1251 в UTF8
    2. .const
    3. align 4
    4. sCP1251_UTF8   db   "Р‚",0,0,   "Рѓ",0,0,   "‚",0,   "С“",0,0,   "„",0,   "…",0,   "†",0,   "‡",0
    5.          db   "€",0,   "‰",0,   "Р‰",0,0,   "‹",0,   "РЉ",0,0,   "РЊ",0,0,   "Р‹",0,0,   "РЏ",0,0
    6.          db   "С’",0,0,   "‘",0,   "’",0,   "“",0,   "”",0,   "•",0,   "–",0,   "—",0
    7.          db   "˜",0,0,   "в„ў",0,   "С™",0,0,   "›",0,   "Сљ",0,0,   "Сњ",0,0,   "С›",0,0,   "Сџ",0,0
    8.          db   "В ",0,0,   "РЋ",0,0,   "Сћ",0,0,   "Р€",0,0,   "В¤",0,0,   "Тђ",0,0,   "В¦",0,0,   "В§",0,0
    9.          db   "РЃ",0,0,   "В©",0,0,   "Р„",0,0,   "В«",0,0,   "В¬",0,0,   "В",0,0,   "В®",0,0,   "Р‡",0,0
    10.          db   "В°",0,0,   "В±",0,0,   "Р†",0,0,   "С–",0,0,   "Т‘",0,0,   "Вµ",0,0,   "В¶",0,0,   "В·",0,0
    11.          db   "С‘",0,0,   "в„–",0,   "С”",0,0,   "В»",0,0,   "ј",0,0,   "Р…",0,0,   "С•",0,0,   "С—",0,0
    12.          db   "Рђ",0,0,   "Р‘",0,0,   "Р’",0,0,   "Р“",0,0,   "Р”",0,0,   "Р•",0,0,   "Р–",0,0,   "Р—",0,0
    13.          db   "И",0,0,   "Р™",0,0,   "Рљ",0,0,   "Р›",0,0,   "Рњ",0,0,   "Рќ",0,0,   "Рћ",0,0,   "Рџ",0,0
    14.          db   "Р ",0,0,   "РЎ",0,0,   "Рў",0,0,   "РЈ",0,0,   "Р¤",0,0,   "РҐ",0,0,   "Р¦",0,0,   "Р§",0,0
    15.          db   "РЁ",0,0,   "Р©",0,0,   "РЄ",0,0,   "Р«",0,0,   "Р¬",0,0,   "Р",0,0,   "Р®",0,0,   "РЇ",0,0
    16.          db   "Р°",0,0,   "Р±",0,0,   "РІ",0,0,   "Рі",0,0,   "Рґ",0,0,   "Рµ",0,0,   "Р¶",0,0,   "Р·",0,0
    17.          db   "Рё",0,0,   "Р№",0,0,   "Рє",0,0,   "Р»",0,0,   "Рј",0,0,   "РЅ",0,0,   "Рѕ",0,0,   "Рї",0,0
    18.          db   "СЂ",0,0,   "СЃ",0,0,   "С‚",0,0,   "Сѓ",0,0,   "С„",0,0,   "С…",0,0,   "С†",0,0,   "С‡",0,0
    19.          db   "С€",0,0,   "С‰",0,0,   "СЉ",0,0,   "С‹",0,0,   "СЊ",0,0,   "СЌ",0,0,   "СЋ",0,0,   "СЏ",0,0
    20. .code
    21.  
    22. align_proc
    23. TXT2HTML proc (dword) uses esi edi ebx pTxtUTF8:ptr, pTxtANSI:ptr
    24.    mov     esi, pTxtUTF8
    25.    mov     edi, pTxtANSI
    26.    ASSUME   esi:ptr byte, edi:ptr byte
    27.    .while (true)
    28.      mov     al, [edi]   ;ANSI
    29.      .if (al==10 || al==13)
    30.        sprintf$(esi, &aBR)
    31.        dec     esi
    32.        mov     al, [edi+1]   ;ANSI
    33.        .if(al==10 || al==13)
    34.          inc     edi
    35.        .endif
    36.      .elseif (al>127)   ;преобразовать ANSI CP1251 в UTF8
    37.        sub     al, 128
    38.        movzx   eax, al
    39.        lea     edx, sCP1251_UTF8[eax*4]
    40.        .while (true)
    41.          mov     al, [edx]
    42.          .break .if (al==0)
    43.          mov     [esi], al
    44.          inc     edx
    45.          inc     esi
    46.        .endw
    47.        inc     edi
    48.        .continue
    49.      .else
    50.        mov     [esi], al
    51.        .break .if (al==0)
    52.      .endif
    53.      inc     edi
    54.      inc     esi
    55.    .endw
    56.    ASSUME   esi:nothing, edi:nothing
    57.    mov     eax, esi
    58.    ret
    59. TXT2HTML endp
    Функция предназначена для преобразования текста в HTML код и возвращает указатель на конец строки. Для UASM. Можно выкинуть не нужный код и оставить только преобразовать CP1251 в UTF8.
    Пример вызова.
    Код (ASM):
    1. mov     pHTMLend, TXT2HTML(pHTMLend, &aBodyHTML_begin)
     
    Последнее редактирование: 30 дек 2018
  11. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Проверено на русской и японской кодировках. Вы упустили, как раз, вот этот костыль:
    Код (C):
    1.             // If function meets invalid sequence, it replaces the codepoint with such magic value
    2.             // We should know if function has failed
    3.             if (wbuf[n-1] == 0xfffd)
    4.                 n--;
    5.             // Write data
    6.             nbytes = fwrite(wbuf, sizeof(WCHAR), n, outf);
    7.             if (nbytes != size_t(n))
    8.             {
    9.                 res = STATUS_IO_ERROR;
    10.                 break;
    11.             }
    12.             // Estimate number of bytes decoded (yep, this is dumb but no way...)
    13.             n = WideCharToMultiByte(cp, 0, wbuf, n, NULL, 0, 0, 0); // terminating 0
    14.             if ((n <= 0) || (n > isize))
    15.             {
    16.                 res = STATUS_IO_ERROR;
    17.                 break;
    18.             }
    19.             isize -= n;
    20.             if (isize > 0)
    21.                 memmove(cbuf, &cbuf[n], isize);
    Если последний символ не содержит полный валидный UTF8-код, то при декодировании он будет заменён на 0xfffd, мы детектим это и считаем, что декодировали на символ меньше, а недекодированный хвост помещаем в начало буфера, после чего дочитываем новые данные в конец.
     
  12. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    SadKo, ну кароч, к потоковому конвертору UTF-8 должен прилагаться парсер со стейтом.
     
  13. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Если вам больше нечего написать, то лучше не пишите, не засоряйте топик.
    Я кинул уже рабочий пример, протестированный на однобайтных кодировках, а также UTF-8 с двухбайтной и трёхбайтной длиной кодпоинта.
     
  14. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    на самом деле можно просто по первым байтам определять длины utf8 символов и высчитывать, сколько символов полностью уложилось в буффер, переводить только полностью считанные кодпойнты...
    --- Сообщение объединено, 1 янв 2019 ---
    нашел пример на просторах интернета:
    Код (C):
    1. int32_t utf8_is_single_byte(char * c) {
    2.   return (c[0] & 0x80) == 0x0;
    3. }
    4.  
    5. int32_t utf8_is_double_byte(char * c) {
    6.   return (c[0] & 0xe0) == 0xc0 && utf8_is_continuation(c[1]);
    7. }
    8.  
    9. int32_t utf8_is_triple_byte(char * c) {
    10.   return (c[0] & 0xf0) == 0xe0 && utf8_is_continuation(c[1]) && utf8_is_continuation(c[2]);
    11. }
    12.  
    13. int32_t utf8_is_quadruple_byte(char * c) {
    14.   return (c[0] & 0xf8) == 0xf0 && utf8_is_continuation(c[1]) && utf8_is_continuation(c[2]) && utf8_is_continuation(c[3]);
    15. }
    16.  
    17. int32_t utf8_is_continuation(char c) {
    18.   return (c & 0xc0) == 0x80;
    19. }
    20.  
    21. size_t utf8_strlen(char * s) {
    22.   size_t i = 0, len = 0;
    23.   while(s[I]) [/I]{
    24.   if ( ! utf8_is_continuation(s)) ++len;
    25.   ++i;
    26.   }
    27.   return len;
    28. }
     
  15. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Это верно, но задача состоит немного в другом: "Конвертация из произвольной CP в UTF-16", UTF-8 - всего-лишь частный случай.
    А для чисто UTF-8 есть вообще интересные решения на конечных автоматах:
    https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
     
  16. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    это верно, но тут надо знать один момент... функция MultiByteToWideChar не решает этой задачи, тк конвертирует только те кодовые страницы, которые установлены в системе... это минимум ACP, OEMCP и UTF-8, но остальные могут быть не установлены...
     
  17. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    В принципе, согласен. Но вот этого перечня кодировок более чем достаточно:
    https://docs.microsoft.com/ru-ru/windows/desktop/Intl/code-page-identifiers

    В целом, этого достаточно. Моя задача - сконвертить из локальной кодировки (кодировка на целевой системе) в UTF-16 и назад, заведомо задетектив эту локальную кодировку. Поэтому всё будет работать так, как ожидается.
     
  18. gazlan

    gazlan Member

    Публикаций:
    0
    Регистрация:
    22 май 2005
    Сообщения:
    414
  19. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Фу какой ты грубиян.

    Вот на STLных стримах (безо всяких обработок ошибок и прочего):

    Код (C++):
    1. #include <fstream>
    2. #include <codecvt>
    3.  
    4. void convert(char const* in, char const* out)
    5. {
    6.     std::wifstream input(in, std::ios::binary);
    7.     std::wofstream output(out, std::ios::binary);
    8.     input.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
    9.     output.imbue(std::locale(std::locale::empty(), new std::codecvt_utf16<wchar_t>));
    10.     while(!input.eof())
    11.     {
    12.         output << static_cast<wchar_t>(input.get());
    13.     }
    14. }
    15.  
    16. int main()
    17. {
    18.     convert("C:/in.txt", "C:/out.txt");
    19. }
    --- Сообщение объединено, 2 янв 2019 ---
    Тут еще момент в том, что wide char - не обязательно 2 байта, может быть и больше. Это тоже относится к "и прочего".
     
  20. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    ну суррогатные пары MultiByteToWideChar вроде учитывает и не считает их одним символом... хотя я не сталкивался с какими-то проблемами с ними связанными...