Unicode字符未正确显示

时间:2012-08-10 18:07:42

标签: email curl unicode wchar

我正在制作支持多种语言的C程序。程序使用WCHAR类型而不是char发送电子邮件。问题是,当我收到电子邮件并阅读它时,某些字符显示不正确,甚至一些英文字符如e,m,...这是一个例子:

<!-- language: lang-c -->
curl_easy_setopt(hnd, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(hnd, CURLOPT_READDATA, &upload_ctx);

static const WCHAR *payload_text[]={
    L"To: <me@mail.com>\n",
    L"From: <me@mail.com>(Example User)\n",
    L"Subject: Hello!\n",
    L"\n",
    L"Message sent\n",
    NULL
};

struct upload_status {
    int lines_read;
};

static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp){
    struct upload_status *upload_ctx = (struct upload_status *)userp;
    const WCHAR *data;

    if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
        return 0;
    }

    data = payload_text[upload_ctx->lines_read];
    if (data) {
        size_t len = wcslen(data);
        memcpy(ptr, data, len);
        upload_ctx->lines_read ++;
        return len;
    }
    return 0;
}

1 个答案:

答案 0 :(得分:0)

memcpy()对字节进行操作,而不对字符进行操作。您没有考虑sizeof(wchar_t) > 1。某些系统上有2个字节,其他系统上有4个字节。在编写可移植代码时,这种不确定性使wchar_t成为一个糟糕的选择。您应该使用Unicode库,例如icu或iconv)。

调用sizeof(wchar_t)时,您需要考虑memcpy()。您还需要考虑目标缓冲区可能小于您尝试复制的文本字节的大小。单独跟踪lines_read是不够的,您还必须跟踪当前行复制的字节数,以便在当前文本行跨越多个目标缓冲区时处理案例。 / p>

尝试更像这样的东西:

static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
    struct upload_status *upload_ctx = (struct upload_status *) userp;
    unsigned char *buf = (unsignd char *) ptr;
    size_t available = (size * nmemb);
    size_t total = 0;

    while (available > 0)
    {
        wchar_t *data = payload_text[upload_ctx->lines_read];
        if (!data) break;

        unsigned char *rawdata = (unsigned char *) data;

        size_t remaining = (wcslen(data) * sizeof(wchar_t)) - upload_ctx->line_bytes_read;
        while ((remaining > 0) && (available > 0))
        {
            size_t bytes_to_copy = min(remaining, available);
            memcpy(buf, rawdata, bytes_to_copy);

            buf += bytes_to_copy;
            available -= bytes_to_copy;
            total = bytes_to_copy;

            rawdata += bytes_to_copy;
            remaining -= bytes_to_copy;

            upload_ctx->line_bytes_read += bytes_to_copy;
        }

        if (remaining < 1)
        {
            upload_ctx->lines_read ++;
            upload_ctx->line_bytes_read = 0;
        }
    }

    return total;
}