Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[C] ucs2 to utf8

40K
16 января 2010 года
himas
31 / / 13.11.2009
Есть исходный код, который из байтовой последовательности собирает строку WCHAR (ucs2 в windows), а затем конвертирует ее в utf8.
Код:
#include <stdio.h>
#include <windows.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;

typedef wchar_t WCHAR;
//typedef short WCHAR;

#define _ASSERTE(x)

void unpackWideString(BYTE **buf, WCHAR *string, WORD len)
{
    BYTE *tmp = *buf;

    while (len > 1)
    {
        *string = (*tmp++ << 8);
        *string |= *tmp++;

        string++;
        len -= 2;
    }

    // We have a stray byte at the end, this means that the buffer had an odd length
    // which indicates an error.
    _ASSERTE(len == 0);
    if (len != 0)
    {
        // We dont copy the last byte but we still need to increase the buffer pointer
        // (we assume that 'len' was correct) since the calling function expects
        // that it is increased 'len' bytes.
        *tmp += len;
    }

    *buf = tmp;
}

char* make_utf8_string_static(const WCHAR *unicode, char *utf8, size_t utf_size)
{
    int index = 0;
    unsigned int out_index = 0;
    unsigned short c;

    c = unicode[index++];
    while (c)
    {
        if (c < 0x080)
        {
            if (out_index + 1 >= utf_size) break;
            utf8[out_index++] = (unsigned char)c;
        }
        else if (c < 0x800)
        {
            if (out_index + 2 >= utf_size) break;
            utf8[out_index++] = 0xc0 | (c >> 6);
            utf8[out_index++] = 0x80 | (c & 0x3f);
        }
        else
        {
            if (out_index + 3 >= utf_size) break;
            utf8[out_index++] = 0xe0 | (c >> 12);
            utf8[out_index++] = 0x80 | ((c >> 6) & 0x3f);
            utf8[out_index++] = 0x80 | (c & 0x3f);
        }

        c = unicode[index++];
    }
    utf8[out_index] = 0x00;

    return utf8;
}

char* make_utf8_string(const WCHAR *unicode)
{
    int size = 0;
    int index = 0;
    char *out;
    unsigned short c;

    if (!unicode) return NULL;

    /* first calculate the size of the target string */
    c = unicode[index++];
    while (c)
    {
        printf("%04x\n", c);

        if (c < 0x0080)
            size += 1;
        else if (c < 0x0800)
            size += 2;
        else
            size += 3;

        c = unicode[index++];
    }
    printf("\n");

    out = (char*)malloc(size + 1);
    if(out) memset(out, '\0', size + 1);
    if (!out) return NULL;

    return make_utf8_string_static(unicode, out, size + 1);
}

main()
{
    WORD buflen;
    char *text_utf8 = NULL;
    BYTE *buf;

    // "тест"
    BYTE raw[] = {0x04, 0x42, 0x04, 0x35, 0x04, 0x41, 0x04, 0x42, 0x00, 0x00};
    buf = raw;

    int i = 0;
    for(i = 0; i <= strlen((char*)buf) - 1; i++)
        printf("%02x\n", buf);
    printf("\n");

    WCHAR* text_ucs2 = (WCHAR*)malloc(buflen + 2);
    if (text_ucs2) memset(text_ucs2, '\0', buflen + 2);

    unpackWideString(&buf, text_ucs2, buflen);
    text_ucs2[buflen/sizeof(WCHAR)] = 0;

    for(i = 0; i <= strlen((char*)text_ucs2)/2 - 1; i++)
        printf("%04x\n", text_ucs2);
    printf("\n");

    text_utf8 = make_utf8_string(text_ucs2);

    for(i = 0; i <= strlen((char*)text_utf8) - 1; i++)
        printf("%02x\n", text_utf8);
    printf("\n");

    free(text_ucs2);

    printf("Message = %s\n", text_utf8);
}

Результатом выполнения будет:
Цитата:

04
42
04
35
04
41
04
42

0442
0435
0441
0442

0442
0435
0441
0442

ffffffd1
ffffff82
ffffffd0
ffffffb5
ffffffd1
ffffff81
ffffffd1
ffffff82

Message = &#9572;В&#9576;&#9569;&#9572;Б&#9572;В



Просьба помочь разобраться, где ошибка, потому как "&#9572;В&#9576;&#9569;&#9572;Б&#9572;В" явно не похоже на "тест" + число символов в 2 раза превышает необходимое, хотя в предпоследнем блоке явно прослеживаются коды utf8 (d1 82 - hex-код "т" в utf8).

таблица
http://www.utf8-chartable.de/unicode-utf8-table.pl?start=1024&number=1024

43K
19 января 2010 года
loki231
76 / / 27.09.2009
Предпоследний блок имеет такой вид,
Цитата:
ffffffd1
ffffff82
ffffffd0
ffffffb5
ffffffd1
ffffff81
ffffffd1
ffffff82


потому что в операторе printf()

 
Код:
for(i = 0; i <= strlen((char*)text_utf8) - 1; i++)
        printf("%02x\n", text_utf8);

происходит преобразование из signed char в signed int и 0xd1, становится 0xffffffd1.

А кракозябры в последнем блоке, скорее всего являются результатом того, что printf не догадывается, что её аргумент имеет кодировку utf8, а использует системную кодировку, отличающуюся от utf8.
16K
03 февраля 2010 года
asmforce
186 / / 05.01.2010
Я уже опубликовал ответ на подобный вопрос в теме ascii to utf8 - Ваш случай похож, - взгляните!
16K
03 февраля 2010 года
asmforce
186 / / 05.01.2010
Цитата: loki231

for(i = 0; i <= strlen((char*)text_utf8) - 1; i++)
printf("%02x\n", text_utf8);



Так делать нельзя - на каждой итерации цикла будет вызвана функция strlen - производительность на минус, - сохраните в переменной и юзайте на здоровье! НЕ ЛЕНИТЕСЬ!!!

 
Код:
u32 text_len = std::strlen( (char*)text_utf8 );

for( u32 i = 0; i != text_len; ++i )
    printf("%02x\n", text_utf8);
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог