#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);
}
[C] ucs2 to 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 = ╤В╨╡╤Б╤В
Просьба помочь разобраться, где ошибка, потому как "╤В╨╡╤Б╤В" явно не похоже на "тест" + число символов в 2 раза превышает необходимое, хотя в предпоследнем блоке явно прослеживаются коды utf8 (d1 82 - hex-код "т" в utf8).
таблица
http://www.utf8-chartable.de/unicode-utf8-table.pl?start=1024&number=1024
Цитата:
ffffffd1
ffffff82
ffffffd0
ffffffb5
ffffffd1
ffffff81
ffffffd1
ffffff82
ffffff82
ffffffd0
ffffffb5
ffffffd1
ffffff81
ffffffd1
ffffff82
потому что в операторе printf()
Код:
for(i = 0; i <= strlen((char*)text_utf8) - 1; i++)
printf("%02x\n", text_utf8);
printf("%02x\n", text_utf8);
происходит преобразование из signed char в signed int и 0xd1, становится 0xffffffd1.
А кракозябры в последнем блоке, скорее всего являются результатом того, что printf не догадывается, что её аргумент имеет кодировку utf8, а использует системную кодировку, отличающуюся от utf8.
Я уже опубликовал ответ на подобный вопрос в теме ascii to utf8 - Ваш случай похож, - взгляните!
Цитата: 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);
for( u32 i = 0; i != text_len; ++i )
printf("%02x\n", text_utf8);