Как заставить мой `std::string url_encode_wstring(const std::wstring &input)` работать в Linux?
Итак, у нас есть такая функция:
std::string url_encode_wstring(const std::wstring &input)
{
std::string output;
int cbNeeded = WideCharToMultiByte(CP_UTF8, 0, input.c_str(), -1, NULL, 0, NULL, NULL);
if (cbNeeded > 0) {
char *utf8 = new char[cbNeeded];
if (WideCharToMultiByte(CP_UTF8, 0, input.c_str(), -1, utf8, cbNeeded, NULL, NULL) != 0) {
for (char *p = utf8; *p; *p++) {
char onehex[5];
_snprintf(onehex, sizeof(onehex), "%%%02.2X", (unsigned char)*p);
output.append(onehex);
}
}
delete[] utf8;
}
return output;
}
Это решетка для Windows, но мне интересно, как (и возможно ли) заставить его работать под Linux?
1 ответ
Решение
ИМХО, вы должны использовать переносимую библиотеку кодеков символов. Вот пример минимального переносимого кода с использованием iconv, которого должно быть более чем достаточно. Он должен работать в Windows (если это так, вы можете полностью избавиться от кода, специфичного для Windows). Я следую указаниям GNU не использовать функции wcstombs & co ( https://www.gnu.org/s/hello/manual/libc/iconv-Examples.html). В зависимости от варианта использования, обрабатывайте ошибки соответствующим образом... и для повышения производительности вы можете создать из него класс.
#include <iostream>
#include <iconv.h>
#include <cerrno>
#include <cstring>
#include <stdexcept>
std::string wstring_to_utf8_string(const std::wstring &input)
{
size_t in_size = input.length() * sizeof(wchar_t);
char * in_buf = (char*)input.data();
size_t buf_size = input.length() * 6; // pessimistic: max UTF-8 char size
char * buf = new char[buf_size];
memset(buf, 0, buf_size);
char * out_buf(buf);
size_t out_size(buf_size);
iconv_t conv_desc = iconv_open("UTF-8", "wchar_t");
if (conv_desc == iconv_t(-1))
throw std::runtime_error(std::string("Could not open iconv: ") + strerror(errno));
size_t iconv_value = iconv(conv_desc, &in_buf, &in_size, &out_buf, &out_size);
if (iconv_value == -1)
throw std::runtime_error(std::string("When converting: ") + strerror(errno));
int ret = iconv_close(conv_desc);
if (ret != 0)
throw std::runtime_error(std::string("Could not close iconv: ") + strerror(errno));
std::string s(buf);
delete [] buf;
return s;
}
int main() {
std::wstring in(L"hello world");
std::wcout << L"input: [" << in << L"]" << std::endl;
std::string out(wstring_to_utf8_string(in));
std::cerr << "output: [" << out << "]" << std::endl;
return 0;
}