Преобразование C ++ std :: string в строку в кодировке UTF-16-LE - PullRequest
0 голосов
/ 08 октября 2018

Я искал часы сегодня и просто не могу найти ничего, что мне подходит.Тот, на что я только что посмотрел, не повезло, это " Как преобразовать std :: string в кодировке UTF-8 в UDF-16 std :: string ".

Мой вопрос с кратким объяснением:

Я хочу создать действительный хэш NTLM в стандарте C ++, и я использую библиотеку OpenSSL для создания хеша, используя его подпрограммы MD4.Я знаю, как это сделать, поэтому кто-нибудь знает, как преобразовать std::string в строку в кодировке UTF-16 LE, которую я могу передать функциям MD4 для получения правильного дайджеста?

Итак, могу ли яиметь std::string, который содержит тип char, и преобразовать его в кодируемую UTF16-LE переменную длину std :: string_type?Будь то std::u16string, или std::wstring?

И я бы использовал s.c_str() или s.data(), и функция length() сообщала бы правильно в обоих случаях?

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Я думаю, что-то вроде этого должно сработать:

std::string utf16_to_utf8(std::u16string const& s)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t, 0x10ffff,
        std::codecvt_mode::little_endian>, char16_t> cnv;
    std::string utf8 = cnv.to_bytes(s);
    if(cnv.converted() < s.size())
        throw std::runtime_error("incomplete conversion");
    return utf8;
}

std::u16string utf8_to_utf16(std::string const& utf8)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t, 0x10ffff,
        std::codecvt_mode::little_endian>, char16_t> cnv;
    std::u16string s = cnv.from_bytes(utf8);
    if(cnv.converted() < utf8.size())
        throw std::runtime_error("incomplete conversion");
    return s;
}

Примечание: , что std :: wstring_convert равно устарело в C++17, но я все же предпочитаю использовать ее, а не нестандартную библиотеку, учитывая, что она переносима, не имеет зависимостей и, несомненно, останется до замены.

И, если все остальноене удается, вы можете переопределить эти же функции с помощью альтернативного кода без изменения какой-либо другой части приложения.

0 голосов
/ 08 октября 2018

Извините, не понаслышке ... это будет ужасный ответ с длинным кодом.В итоге я использовал следующую функцию, в то время как эффективно компилировал iconv в файл приложения Windows по файлу:)

Надеюсь, это поможет.

char* conver(const char* in, size_t in_len, size_t* used_len)
{
    const int CC_MUL = 2; // 16 bit
    setlocale(LC_ALL, "");
    char* t1 = setlocale(LC_CTYPE, "");
    char* locn = (char*)calloc(strlen(t1) + 1, sizeof(char));
    if(locn == NULL)
    {
        return 0;
    }

    strcpy(locn, t1);
    const char* enc = strchr(locn, '.') + 1;

#if _WINDOWS
    std::string win = "WINDOWS-";
    win += enc;
    enc = win.c_str();
#endif

    iconv_t foo = iconv_open("UTF-16LE", enc);

    if(foo == (void*)-1)
    {
        if (errno == EINVAL)
        {
            fprintf(stderr, "Conversion from %s is not supported\n", enc);
        }
        else
        {
            fprintf(stderr, "Initialization failure:\n");
        }
        free(locn);
        return 0;
    }

    size_t out_len = CC_MUL * in_len;
    size_t saved_in_len = in_len;
    iconv(foo, NULL, NULL, NULL, NULL);
    char* converted = (char*)calloc(out_len, sizeof(char));
    char *converted_start = converted;
    char* t = const_cast<char*>(in);
    int ret = iconv(foo,
                    &t,
                    &in_len,
                    &converted,
                    &out_len);
    iconv_close(foo);
    *used_len = CC_MUL * saved_in_len - out_len;

    if(ret == -1)
    {
        switch(errno)
        {
        case EILSEQ:
            fprintf(stderr,  "EILSEQ\n");
            break;
        case EINVAL:
            fprintf(stderr,  "EINVAL\n");
            break;
        }

        perror("iconv");
        free(locn);
        return 0;
    }
    else
    {
        free(locn);
        return converted_start;
    }
}
...