Windows C API для UTF8 до 1252

Я знаком с преобразованиями WideCharToMultiByte и MultiByteToWideChar и мог бы использовать их, чтобы сделать что-то вроде:

UTF8 -> UTF16 -> 1252

Я знаю, что iconv сделает то, что мне нужно, но кто-нибудь знает какие-либо библиотеки MS, которые позволят это сделать за один вызов?

Я, вероятно, должен просто загрузить библиотеку iconv, но я чувствую себя ленивым.

Спасибо


person Paul    schedule 17.02.2010    source источник


Ответы (1)


Windows 1252 в основном эквивалентна latin-1, также известной как ISO-8859-1: Windows-1252 просто имеет несколько дополнительных символов, выделенных в зарезервированном диапазоне latin-1 128-159. Если вы готовы игнорировать эти лишние символы и придерживаться латиницы-1, то преобразование будет довольно простым. Попробуй это:

#include <stddef.h>

/*  
 * Convert from UTF-8 to latin-1. Invalid encodings, and encodings of
 * code points beyond 255, are replaced by question marks. No more than
 * dst_max_len bytes are stored in the destination array. Returned value
 * is the length that the latin-1 string would have had, assuming a big
 * enough destination buffer.
 */
size_t
utf8_to_latin1(char *src, size_t src_len,
    char *dst, size_t dst_max_len)
{   
    unsigned char *sb;
    size_t u, v;

    u = v = 0;
    sb = (unsigned char *)src;
    while (u < src_len) {
        int c = sb[u ++];
        if (c >= 0x80) {
            if (c >= 0xC0 && c < 0xE0) {
                if (u == src_len) {
                    c = '?';
                } else {
                    int w = sb[u];
                    if (w >= 0x80 && w < 0xC0) {
                        u ++;
                        c = ((c & 0x1F) << 6)
                            + (w & 0x3F);
                    } else {
                        c = '?';
                    }   
                }   
            } else {
                int i;

                for (i = 6; i >= 0; i --)
                    if (!(c & (1 << i)))
                        break;
                c = '?';
                u += i;
            }   
        }   
        if (v < dst_max_len)
            dst[v] = (char)c;
        v ++;
    }   
    return v;
}   

/*  
 * Convert from latin-1 to UTF-8. No more than dst_max_len bytes are
 * stored in the destination array. Returned value is the length that
 * the UTF-8 string would have had, assuming a big enough destination
 * buffer.
 */
size_t
latin1_to_utf8(char *src, size_t src_len,
    char *dst, size_t dst_max_len)
{   
    unsigned char *sb;
    size_t u, v;

    u = v = 0;
    sb = (unsigned char *)src;
    while (u < src_len) {
        int c = sb[u ++];
        if (c < 0x80) {
            if (v < dst_max_len)
                dst[v] = (char)c;
            v ++;
        } else {
            int h = 0xC0 + (c >> 6);
            int l = 0x80 + (c & 0x3F);
            if (v < dst_max_len) {
                dst[v] = (char)h;
                if ((v + 1) < dst_max_len)
                    dst[v + 1] = (char)l;
            }   
            v += 2;
        }   
    }   
    return v;
}   

Обратите внимание, что я не даю никаких гарантий в отношении этого кода. Это совершенно не проверено.

person Thomas Pornin    schedule 17.02.2010
comment
И чем это лучше, чем простое использование проверенного API путем вызова MultiByteToWideChar с последующим вызовом WideCharToMultiByte? - person Sofahamster; 17.02.2010
comment
Лучше ? Какое спорное мнение. Вопрос заключался в том, чтобы сделать это в одном вызове функции вместо двух, особенно если это два MultiByteToWideChar() и WideCharToMultiByte(). Мой код делает это. Я не утверждаю, что мудро избегать MultiByteToWideChar(). Придирчиво можно отметить, что мои функции избегают выделения временного буфера. - person Thomas Pornin; 17.02.2010