boost::iostreams
От: kan_izh Великобритания  
Дата: 18.08.06 12:01
Оценка:
Кто юзает?
Мне нужно следующее:
file_source fs(url, ios_base::in | ios_base::binary);
if(!fs.is_open())
{
  ... error, just quit.
}
auto_ptr<filtering_istream> fis(new filtering_istream);
fis->push(gzip_decompressor());
fis->push(fs);
try
{// хочу проверить, действительно ли входной файл запакован.
    fis->rdbuf()->sgetc();// Хакерство всё это. Но как сделать правильно?
}
catch(std::ios::failure &)
{// неа, не запакован, значит просто файл, читаем без gzip фильтра.
    fis.reset(new filtering_istream);
    fis->push(fs);
}
// ну и, типа, можно читать:
fis->read(...);

Оно работает, но неправильно — если файл большой, то вроде ок, но если маленький, то не работает, как я понял, fs
прочитывается весь в буфер и потом не read не работает, т.к. eof выставляется. В общем бардак. Как правильно?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: boost::iostreams
От: MaximE Великобритания  
Дата: 18.08.06 12:22
Оценка:
kan_izh wrote:

> Кто юзает?

> Мне нужно следующее:
>
> file_source fs(url, ios_base::in | ios_base::binary);
> if(!fs.is_open())
> {
> ... error, just quit.
> }
> auto_ptr<filtering_istream> fis(new filtering_istream);
> fis->push(gzip_decompressor());
> fis->push(fs);
> try
> {// хочу проверить, действительно ли входной файл запакован.
> fis->rdbuf()->sgetc();// Хакерство всё это. Но как сделать правильно?
> }
> catch(std::ios::failure &)
> {// неа, не запакован, значит просто файл, читаем без gzip фильтра.
> fis.reset(new filtering_istream);
> fis->push(fs);
> }
> // ну и, типа, можно читать:
> fis->read(...);
>
>
> Оно работает, но неправильно — если файл большой, то вроде ок, но если
> маленький, то не работает, как я понял, fs
> прочитывается весь в буфер и потом не read не работает, т.к. eof
> выставляется. В общем бардак. Как правильно?

Что ты собираешься делать с данными? Если ты не собираешься использовать
operator>>, то может быть не стоит использовать iostreams вообще.

--
Maxim Yegorushkin

No Microsoft product was used in any way to write or send this text.
If you use a Microsoft product to read it, you're doing so at your own risk
Posted via RSDN NNTP Server 2.0
Re[2]: boost::iostreams
От: kan_izh Великобритания  
Дата: 18.08.06 12:33
Оценка:
MaximE wrote:

> Что ты собираешься делать с данными? Если ты не собираешься использовать

> operator>>, то может быть не стоит использовать iostreams вообще.
А что? Всё так плохо? А то оно, вообще говоря, работает. Но я просто извращаюсь, используя один и тот же файл дважды...
оно и глючит. Можно, вообще-то файл открывать второй раз, но это мне кажется некрасивым...
Просто более-менее удобной в использовании библиотеки gzip я не нашел... Притом тут легко можно на bzip2 поменять при
желании. И ещё я прикручиваю шифрование, т.е. на самом деле у меня такой код:
    fis->push(gzip_decompressor());
    fis->push(decryptor());
    fis->push(fs);

что без вменяемой библиотеки потоков делается довольно жутко.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: boost::iostreams
От: MaximE Великобритания  
Дата: 18.08.06 12:46
Оценка:
kan_izh wrote:

> MaximE wrote:

>
>> Что ты собираешься делать с данными? Если ты не собираешься использовать
>> operator>>, то может быть не стоит использовать iostreams вообще.
> А что? Всё так плохо?

На мой взгляд нет особого смысла использовать потоки, если не используешь <<,
>>. Если все, что нужно, это абстрагироваться от read/write, то может быть
достаточно интерфейса на подобие такого:

struct source
{
     virtual ~source() {}
     virtual ssize_t read(void*, size_t) = 0;
};


С таким интерфейсом легко построить стэк (f)read->decrypt->uncompress, или любой
другой, не ломая голову над тонкостями реализации streambuf.

> А то оно, вообще говоря, работает. Но я просто

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

Может попробовать когда открываешь поток второй раз сделать ему .clear() ?

--
Maxim Yegorushkin

No Microsoft product was used in any way to write or send this text.
If you use a Microsoft product to read it, you're doing so at your own risk
Posted via RSDN NNTP Server 2.0
Re[4]: boost::iostreams
От: kan_izh Великобритания  
Дата: 18.08.06 13:42
Оценка:
MaximE wrote:

>> > Что ты собираешься делать с данными? Если ты не собираешься использовать

>> > operator>>, то может быть не стоит использовать iostreams вообще.
>> А что? Всё так плохо?
> На мой взгляд нет особого смысла использовать потоки, если не
> используешь <<,
>> >. Если все, что нужно, это абстрагироваться от read/write, то может быть
> достаточно интерфейса на подобие такого:
Нужно возможность несколько обработчиков в цепочку выстроить.

> struct source

> {
> virtual ~source() {}
> virtual ssize_t read(void*, size_t) = 0;
> };
>
>
>
> С таким интерфейсом легко построить стэк (f)read->decrypt->uncompress,
> или любой
> другой, не ломая голову над тонкостями реализации streambuf.
Тоже самое ещё для write, плюс найти gzip вменяемый, плюс согласовать с шифровальщиком...
В общем, сделать тоже самое, только с нуля.
на boost::iostreams уж больно всё красиво и удобно... но пара грабель...

>> А то оно, вообще говоря, работает. Но я просто

>> извращаюсь, используя один и тот же файл дважды...
>> оно и глючит. Можно, вообще-то файл открывать второй раз, но это мне
>> кажется некрасивым...
>
> Может попробовать когда открываешь поток второй раз сделать ему .clear() ?
Не помогло. Вот такое пока оставил, вроде работает:
    file_source fs(url, ios_base::in | ios_base::binary);
    if(!fs.is_open())
    {
        return NULL;
    }
    auto_ptr<filtering_istream> fis(new filtering_istream);
    fis->push(gzip_decompressor());
    fis->push(decryptor());
    fis->push(fs);
    try
    {
        fis->rdbuf()->sgetc();// explicitly open stream and check it.
    }
    catch(std::ios::failure &)
    {
        fis->set_auto_close(false);
        fis->pop();
        fis->set_auto_close(true);
        fis.reset(new filtering_istream);
        fs.seek(0, BOOST_IOS::beg);
        fis->push(fs);
    }
    fis->read(...);
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: boost::iostreams
От: MaximE Великобритания  
Дата: 18.08.06 14:22
Оценка:
kan_izh wrote:

> MaximE wrote:

>
>> > > Что ты собираешься делать с данными? Если ты не собираешься
> использовать
>> > > operator>>, то может быть не стоит использовать iostreams вообще.
>> > А что? Всё так плохо?
>> На мой взгляд нет особого смысла использовать потоки, если не
>> используешь <<,
>> > >. Если все, что нужно, это абстрагироваться от read/write, то может быть
>> достаточно интерфейса на подобие такого:
> Нужно возможность несколько обработчиков в цепочку выстроить.

Цепочка:

$ cat exp.cpp
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <exception>
#include <boost/function.hpp>

struct source
{
     virtual ~source() {}
     virtual ssize_t read(void*, size_t) throw() = 0;
};

struct error : std::exception
{
     char s[0x100];

     error(char const* fmt, ...) __attribute__((format(printf,2,3)))
     {
         va_list ap; va_start(ap, fmt);
         vsnprintf(s, sizeof s, fmt, ap);
         va_end(ap);
     }

     char const* what() const throw() { return s; }
};

struct file_source : source
{
     int fd;

     file_source(char const* file)
         : fd(open(file, O_RDONLY))
     {
         if(-1 == fd)
             throw error("%s: %s", file, strerror(errno));
     }

     ssize_t read(void* b, size_t n) throw() { return ::read(fd, b, n); }
};

struct transformer : source
{
     source* src;
     boost::function<int(int)> f;

     transformer(source* src, boost::function<char(char)> const& f)
         : src(src), f(f)
     {}

     ssize_t read(void* b, size_t n) throw()
     {
         ssize_t m = src->read(b, n);
         if(m > 0)
         {
             char* p = static_cast<char*>(b);
             std::transform(p, p + m, p, f);
         }
         return m;
     }
};

int main(int ac, char** av)
{
     file_source a("exp.cpp");
     transformer b(&a, toupper);

     char buf[0x100];
     ssize_t n;
     while(0 < (n = b.read(buf, sizeof buf)))
         printf("%.*s", static_cast<int>(n), buf);

}

$ make
g++ -I../ -fmessage-length=0 -ggdb -Wall  -c exp.cpp -o exp.o
g++ -o exp exp.o
$ ./exp
#INCLUDE <UNISTD.H>
#INCLUDE <FCNTL.H>
#INCLUDE <ERRNO.H>
#INCLUDE <STRING.H>
#INCLUDE <STDARG.H>
#INCLUDE <STDIO.H>
#INCLUDE <EXCEPTION>
#INCLUDE <BOOST/FUNCTION.HPP>

STRUCT SOURCE
{
     VIRTUAL ~SOURCE() {}
     VIRTUAL SSIZE_T READ(VOID*, SIZE_T) THROW() = 0;
};

STRUCT ERROR : STD::EXCEPTION
{
     CHAR S[0X100];

     ERROR(CHAR CONST* FMT, ...) __ATTRIBUTE__((FORMAT(PRINTF,2,3)))
     {
         VA_LIST AP; VA_START(AP, FMT);
         VSNPRINTF(S, SIZEOF S, FMT, AP);
         VA_END(AP);
     }

     CHAR CONST* WHAT() CONST THROW() { RETURN S; }
};

STRUCT FILE_SOURCE : SOURCE
{
     INT FD;

     FILE_SOURCE(CHAR CONST* FILE)
         : FD(OPEN(FILE, O_RDONLY))
     {
         IF(-1 == FD)
             THROW ERROR("%S: %S", FILE, STRERROR(ERRNO));
     }

     SSIZE_T READ(VOID* B, SIZE_T N) THROW() { RETURN ::READ(FD, B, N); }
};

STRUCT TRANSFORMER : SOURCE
{
     SOURCE* SRC;
     BOOST::FUNCTION<INT(INT)> F;

     TRANSFORMER(SOURCE* SRC, BOOST::FUNCTION<CHAR(CHAR)> CONST& F)
         : SRC(SRC), F(F)
     {}

     SSIZE_T READ(VOID* B, SIZE_T N) THROW()
     {
         SSIZE_T M = SRC->READ(B, N);
         IF(M > 0)
         {
             CHAR* P = STATIC_CAST<CHAR*>(B);
             STD::TRANSFORM(P, P + M, P, F);
         }
         RETURN M;
     }
};

INT MAIN(INT AC, CHAR** AV)
{
     FILE_SOURCE A("EXP.CPP");
     TRANSFORMER B(&A, TOUPPER);

     CHAR BUF[0X100];
     SSIZE_T N;
     WHILE(0 < (N = B.READ(BUF, SIZEOF BUF)))
         PRINTF("%.*S", STATIC_CAST<INT>(N), BUF);

}


> Тоже самое ещё для write, плюс найти gzip вменяемый, плюс согласовать с

> шифровальщиком...
> В общем, сделать тоже самое, только с нуля.
> на boost::iostreams уж больно всё красиво и удобно... но пара грабель...

Согласен, выглядит красиво.

--
Maxim Yegorushkin

No Microsoft product was used in any way to write or send this text.
If you use a Microsoft product to read it, you're doing so at your own risk
Posted via RSDN NNTP Server 2.0
Re[6]: boost::iostreams
От: gok Россия  
Дата: 19.08.06 01:43
Оценка:
Учу boost, решил завернуть этот пример в windows-ДЛЛ. Не знаю как сделать boost::function длл-совместимой

Библиотечная часть:
ioTestDll.h:
#ifndef __IOTEST__
#define _IOTESTLIB __declspec(dllimport)
#else
#define _IOTESTLIB __declspec(dllexport)
#endif    // __IOTEST__
<...>
class _IOTESTLIB transformer : public source
{
public:
    source* src;
    boost::function<char(char)> f;

    transformer(source* src, boost::function<char(char)> const& f)
        : src(src), f(f)
    {}

    bool read(std::string& b, size_t n) 
    {
        if ( src->read(b, n) )
        {
            std::transform(b.begin(), b.end(), b.begin(), f);
        }
        return true;
    }
};

ioTestDll.cpp:
#define __IOTEST__
#include "ioTestDll.h"

При компиляции получил:
Warning 1 warning C4251: 'transformer::f' : class 'boost::function<Signature>' needs to have dll-interface to be used by clients of class 'transformer' c:\my_projects\src\boosttest\iotest\iotest\iotestdll.h 67

Как "открыть" функцию f для клиента?
gok
Re[7]: boost::iostreams
От: MaximE Великобритания  
Дата: 19.08.06 11:32
Оценка: 1 (1)
gok wrote:

> Учу boost, решил завернуть этот пример в windows-ДЛЛ. Не знаю как

> сделать boost::function длл-совместимой
>
> /Библиотечная часть:/
> ioTestDll.h:
>
> #ifndef __IOTEST__
> #define _IOTESTLIB __declspec(dllimport)
> #else
> #define _IOTESTLIB __declspec(dllexport)
> #endif // __IOTEST__
> <...>
> class _IOTESTLIB transformer : public source
> {
> public:
> source* src;
> boost::function<char(char)> f;
>
> transformer(source* src, boost::function<char(char)> const& f)
> : src(src), f(f)
> {}
>
> bool read(std::string& b, size_t n)
> {
> if ( src->read(b, n) )
> {
> std::transform(b.begin(), b.end(), b.begin(), f);
> }
> return true;
> }
> };
>
>
> ioTestDll.cpp:
>
> #define __IOTEST__
> #include "ioTestDll.h"
>
>
> При компиляции получил:
> Warning 1 warning C4251: 'transformer::f' : class
> 'boost::function<Signature>' needs to have dll-interface to be used by
> clients of class 'transformer'
> c:\my_projects\src\boosttest\iotest\iotest\iotestdll.h 67
>
> Как "открыть" функцию f для клиента?

Не отвечу, может в гугле что найдешь.
http://groups.google.co.uk/group/microsoft.public.vc.language/search?group=microsoft.public.vc.language&amp;q=needs+to+have+dll-interface+to+be+used+by+clients+of+class&amp;qt_g=1&amp;searchnow=Search+this+group

p.s. у тебя read возвращает bool. Как узнать сколько байт было прочитано?

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 2.0
Re[7]: boost::iostreams
От: Cyberax Марс  
Дата: 19.08.06 15:28
Оценка: 1 (1)
gok wrote:
> При компиляции получил:
> Warning 1 warning C4251: 'transformer::f' : class
> 'boost::function<Signature>' needs to have dll-interface to be used by
> clients of class 'transformer'
> c:\my_projects\src\boosttest\iotest\iotest\iotestdll.h 67
> Как "открыть" функцию f для клиента?
Это достаточно сложный вопрос, кстати.

В данном случае можно игнорировать это предупреждение (и подавить его с
помощью "#pragma warning(disable:4251)" ).

Все члены класса boost::function — inline'овые, так что если DLL и
клиент совместимы по layout'у классов, то все будет работать нормально.

Проблемы возникнут если у клиента и DLL, например, разные параметры
дефолтного выравнивания членов структур. От этого можно в некоторой
мере
защититься таким образом:
//В самом начале h-файла
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
#  include BOOST_ABI_PREFIX
#endif

#include <boost/function.hpp>
#include ...
...
class _IOTESTLIB transformer : public source
{
public:
     source* src;
     boost::function<char(char)> f;
...

//В конце h-файла
#ifdef BOOST_HAS_ABI_HEADERS
#  include BOOST_ABI_SUFFIX
#endif


Однако, это не поможет если function.hpp включили до твоего файла. Так
что единственный надежный способ — следить за совместимостью ABI.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[8]: boost::iostreams
От: gok Россия  
Дата: 21.08.06 18:31
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Не отвечу, может в гугле что найдешь.

Спасибо, нашел. Все в голос советуют плюнуть. Очень древний вопрос.


ME>p.s. у тебя read возвращает bool. Как узнать сколько байт было прочитано?

Это "переходный" вариант, в конечном вернулся к N
std::ifstream    _input;
<...>
int read(std::string& b)
{         
    b.erase();
    if ( _input.eof() )
        return -1;        
    char buf[1024];
    if ( 0 != _input.getline( buf, 1024) )
        b = buf;
    return b.size();
}
gok
Re[9]: boost::iostreams
От: kan_izh Великобритания  
Дата: 22.08.06 08:15
Оценка: 2 (1)
gok wrote:

> std::ifstream _input;

> <...>
> int read(std::string& b)
> {
> b.erase();
> if ( _input.eof() )
> return -1;
> char buf[1024];
> if ( 0 != _input.getline( buf, 1024) )
> b = buf;
> return b.size();
> }
А чем просто std::getline не устраивает?
std::string b;
std::getline(_input, b);
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: boost::iostreams
От: gok Россия  
Дата: 23.08.06 19:04
Оценка:
Здравствуйте, kan_izh, Вы писали:

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