Search code examples
c++curllibcurlwstring

How to pass wide characters to libcurl API which takes only const char*?


I'm using libcurl to upload some files to my server. I need to handle files whose names are in different languages e.g. Chinese, Hindi, etc. For that, I need to handle files using std::wstring instead of std::string.

libcurl has a function with a prototype like below:

CURLcode curl_mime_filename(curl_mimepart *part, const char *filename);

But I cannot pass std::wstring::c_str() because it will return const wchar_t* instead of const char*.

Edit: I still don't know what encoding scheme is used by the server as it is a third party app so I used std::wstring for handling filenames and the conversion from std::wstring to std::string is done by the below function I found on this forum.

std::string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}

Solution

  • curl_mime_filename is not suitable for

    files whose names are in different languages e.g. Chinese, Hindi, etc.

    It is suitable for ASCII and UTF-8 file name encodings only.

    The job of curl_mime_filename is:

    1. Detect the data content type, for example file.jpgimage/jpeg.
    2. Add the multipart header Content-Disposition, for example Content-Disposition: attachment; name="data"; filename="file.jpg". The encoding to filename= is not set.

    • If you know the server encoding, then encode the chars 0x80 .. 0xff in filename to %80 .. %ff:

      1. Example for UTF8: Naïve file.txtNa%C3%AFve%20file.txt.
      2. Example for UCS2: file.txt%00f%00i%00l%00e%00.%00t%00x%00t.

      Pass the encoded file name to curl_mime_filename.

    • If you do not know the server encoding used or whish to use another encoding, then do not use curl_mime_filename.

      1. Use the desired char encoding for the filename.
      2. Encode the chars over 0x7f like above.
      3. Use curl_mime_headers and set the headers mentioned above, use filename*= instead of filename=.
        struct curl_slist *headers = nullptr;
        headers = curl_slist_append(headers, "Content-Type: image/jpeg");
        headers = curl_slist_append(headers, "Content-Disposition: attachment; name=\"data\"; filename*=UTF-8''Na%C3%AFve%20file.txt");
        curl_mime_headers(part, headers, true);