использование libiconv в *nix
От: Палий Олег Украина  
Дата: 04.09.06 08:36
Оценка:
Пишу простой код:

#include <stdio.h>
#include <iconv.h>
#include <errno.h>

int main() {
        char outbuf[512];
        char *inbuf=strdup("SDFуваASDF");
        size_t inbytesleft, outbytesleft;

        char *inptr = inbuf;
        char *outptr = outbuf;

        inbytesleft = strlen(inbuf);
        outbytesleft = sizeof(outbuf) - 1;

        iconv_t iconv_desc = iconv_open ("KOI8-U", "UTF-8");

        printf("inbuf='%s' inbytesleft=%i outbytesleft=%i\n", inbuf, inbytesleft, outbytesleft);
        if (iconv(iconv_desc, (const char **) &inptr, &inbytesleft, &outptr, &outbytesleft) == (size_t)(-1)) {
           printf("errno= %i\n", errno);
        };

        *outptr = 0;
        printf("converted='%s' inbytesleft=%i outbytesleft=%i\n", outbuf, inbytesleft, outbytesleft);
        free(inbuf);
        iconv_close(iconv_desc);
        return errno;
}


Выдает:
inbuf='SDFываASDF' inbytesleft=10 outbytesleft=511
errno= 86
converted='SDF' inbytesleft=7 outbytesleft=508

86 — это EILSEQ An invalid multibyte sequence has been encountered in the input.
что ему может не нравится?
строка с англ символами конвертится нормально.
Спасибо!
Re: использование libiconv в *nix
От: Палий Олег Украина  
Дата: 04.09.06 09:06
Оценка:
Забыл добавить.
проверялось на gnu libiconv-1.9.2 на FreeBSD 6.1.
и на встроенной в libc iconv на Debian Sarge.
Re: использование libiconv в *nix
От: zaufi Земля  
Дата: 04.09.06 09:23
Оценка:
Здравствуйте, Палий Олег, Вы писали:

ПО>Пишу простой код:


ПО>
#include <stdio.h>
ПО>#include <iconv.h>
ПО>#include <errno.h>
#include <locale.h>

ПО>int main() {
           if (setlocale(LC_ALL, "") == 0) return -1; // Return if unable to set locale
ПО>        char outbuf[512];
ПО>        char *inbuf=strdup("SDFуваASDF");
ПО>        size_t inbytesleft, outbytesleft;

ПО>        char *inptr = inbuf;
ПО>        char *outptr = outbuf;

ПО>        inbytesleft = strlen(inbuf);
ПО>        outbytesleft = sizeof(outbuf) - 1;

ПО>        iconv_t iconv_desc = iconv_open ("KOI8-U", "UTF-8");

ПО>        printf("inbuf='%s' inbytesleft=%i outbytesleft=%i\n", inbuf, inbytesleft, outbytesleft);
ПО>        if (iconv(iconv_desc, (const char **) &inptr, &inbytesleft, &outptr, &outbytesleft) == (size_t)(-1)) {
ПО>           printf("errno= %i\n", errno);
ПО>        };

ПО>        *outptr = 0;
ПО>        printf("converted='%s' inbytesleft=%i outbytesleft=%i\n", outbuf, inbytesleft, outbytesleft);
ПО>        free(inbuf);
ПО>        iconv_close(iconv_desc);
ПО>        return errno;
ПО>}


попробуй выставить локаль сначала
Re[2]: использование libiconv в *nix
От: Палий Олег Украина  
Дата: 04.09.06 10:43
Оценка:
Здравствуйте, zaufi, Вы писали:

Z> if (setlocale(LC_ALL, "") == 0) return -1; // Return if unable to set locale

Z>попробуй выставить локаль сначала
не помогает,

на консоли стоит
$ locale
LANG=uk_UA.KOI8-U
LC_CTYPE="uk_UA.KOI8-U"
LC_COLLATE="uk_UA.KOI8-U"
LC_TIME="uk_UA.KOI8-U"
LC_NUMERIC="uk_UA.KOI8-U"
LC_MONETARY="uk_UA.KOI8-U"
LC_MESSAGES="uk_UA.KOI8-U"
LC_ALL=
Re: использование libiconv в *nix
От: zaufi Земля  
Дата: 04.09.06 11:27
Оценка:
Вот набросал примерчег:
#  include <iconv.h>
#  include <cassert>
#  include <cerrno>
#  include <string>
#  include <stdexcept>
#  include <iostream>

class charset_converter
{
    iconv_t m_cd;

public:
    charset_converter(const std::string& from, const std::string& to)
      : m_cd(iconv_open(to.c_str(), from.c_str()))
    {
        if (m_cd == reinterpret_cast<iconv_t>(-1))
            throw std::runtime_error("iconv init failure");
    }
    ~charset_converter()
    {
        int r = iconv_close(m_cd);
        assert(r != -1);
    }
    std::string convert(const std::string&);
};

class convert
{
    std::string m_str;
    std::string m_from;
    std::string m_to;

public:
    convert(const std::string& str) : m_str(str) {}
    convert& from(const std::string& from_enc)
    {
        m_from = from_enc;
        return *this;
    }
    convert& to(const std::string& to_enc)
    {
        m_to = to_enc;
        return *this;
    }
    operator std::string() const
    {
        if (m_from.empty() || m_to.empty())
            throw std::runtime_error("Bad use of conversion helper class");
        return charset_converter(m_from, m_to).convert(m_str);
    }
};

std::string charset_converter::convert(const std::string& str)
{
    using namespace std;
    const size_t MAX_BUFFER_SIZE = 4096;
    /// \warning iconv wants to have `char**` to input buffer -- WHY? Is it can be modified?
    char* in_buffer = const_cast<char*>(str.data());
    size_t in_bytes_left = str.size();

    string result;
    size_t out_bytes_left;
    char out_buffer[MAX_BUFFER_SIZE];
    char* out_buffer_ptr;
    for (bool exit = false; !exit && in_bytes_left; )
    {
        out_buffer_ptr = out_buffer;
        out_bytes_left = MAX_BUFFER_SIZE;
        size_t sz = iconv(m_cd, &in_buffer, &in_bytes_left, &out_buffer_ptr, &out_bytes_left);
        if (static_cast<int>(sz) == -1)
        {
            switch (errno)
            {
                case E2BIG:
                    result += string(out_buffer, MAX_BUFFER_SIZE - out_bytes_left);
                    break;
                case EILSEQ:
                    throw runtime_error("invalid byte sequence");
                case EINVAL:
                    throw runtime_error("incomplete byte sequence");
                case EBADF:
                default:
                    throw runtime_error("Bad use");
            }
        }
    }
    size_t sz = iconv(m_cd, 0, 0, &out_buffer_ptr, &out_bytes_left);
    assert(sz >= 0 && "No errors possible here!");
    result += string(out_buffer, MAX_BUFFER_SIZE - out_bytes_left);
    //reset convert descriptor
    iconv(m_cd, 0, 0, 0, 0);
    return result;
}

int main(int argc, char* argv[])
{
    if (setlocale(LC_ALL, "") == 0)
    {
        std::cerr << "Unable to setup default locale.\n";
        return -1;
    }
    if (argc >= 2)
    {
        for (int i = 1; i < argc; ++i)
        {
            std::string result_1251 = convert(argv[i]).from("UTF-8").to("CP1251");
            std::cout << "arg[" << i << "] = \"" << result_1251 << "\"\n";
        }
    }
    return 0;
}


у меня вроде нормально работает:
zaufi tests # ./iconv_test "Превед" | hexdump
0000000 7261 5b67 5d31 3d20 2220 f0cf e2e5 e4e5
0000010 0a22
0000012
zaufi tests # locale
LANG=en_US.UTF-8
LC_CTYPE=ru_RU.UTF-8
LC_NUMERIC=POSIX
LC_TIME=en_US.UTF-8
LC_COLLATE=ru_RU.UTF-8
LC_MONETARY=ru_RU.UTF-8
LC_MESSAGES=en_US.UTF-8
LC_PAPER=ru_RU.UTF-8
LC_NAME=ru_RU.UTF-8
LC_ADDRESS=ru_RU.UTF-8
LC_TELEPHONE=ru_RU.UTF-8
LC_MEASUREMENT=ru_RU.UTF-8
LC_IDENTIFICATION=ru_RU.UTF-8
LC_ALL=
Re[2]: использование libiconv в *nix
От: Палий Олег Украина  
Дата: 04.09.06 14:25
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Вот набросал примерчег:

:-O Вы меня просто ошеломили .
Все оказалось проще — я перепутал откуда и куда в вызове iconv_open
Но, все равно спасибо, пока я разобрался с Вашим примером я понял в чем ошибка.
Re[2]: использование libiconv в *nix
От: Аноним  
Дата: 15.02.08 07:51
Оценка:
Здравствуйте, zaufi, Вы писали:


char* in_buffer = const_cast<char*>(str.data());
// ...
size_t sz = iconv(m_cd, &in_buffer, &in_bytes_left, &out_buffer_ptr, &out_bytes_left);



error C2664: 'libiconv' : cannot convert parameter 2 from 'char **__w64 ' to 'const char ** '


что бы это значило? не догоню, чесслово
Re[3]: использование libiconv в *nix
От: Аноним  
Дата: 15.02.08 14:56
Оценка:
Все заработало, когда const поставил
const char* in_buffer = const_cast<char*>(str.data());



теперь возник другой вопрос, может и глупый, но не пойму: где можно посмотреть формат записи строковых констант, которые передаются как параметры перекодирования (типа "CP1251").

спасибо.
Re[2]: использование libiconv в *nix
От: Roman Odaisky Украина  
Дата: 15.02.08 21:18
Оценка: +1 -1
Здравствуйте, zaufi, Вы писали:

Z>Вот набросал примерчег:

Z>zaufi tests # ./iconv_test "Превед" | hexdump

Но-но!
До последнего не верил в пирамиду Лебедева.
Re[2]: от модератора
От: Кодт Россия  
Дата: 19.02.08 22:32
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Вот набросал примерчег:

Z>zaufi tests # ./iconv_test "Превед" | hexdump

Падонческая лексика противоречит правилам форума.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.