custom stream/streambuf issue

D

Derek

Greetings,

I'm trying to create a generic multi-purpose istream class that is
capable of working in different ways based on different file paths.

For example, say an istream-based class that can take a URL as an open
() parameter, and then use a filebuf to open a "file://" path, a
socketbuf to open an "http://" or "telnet://" path, and an ftpbuf to
open an "ftp://" path.

I already have some existing working specific purpose istream-based
classes, but I cannot seem to find a way to build a generic one that
can then interface with one of the existing ones based upon the open
path/url.

Part of the problem I am having is that an istream class must contain
a streambuf that is initialized with the constructor, but I cannot
seem to figure out how to build an istream class that contains (or can
contain) multiple different types of streambufs, and be able to switch
between them, but perhaps this is the wrong approach.

Is there a way to make this work without having to cannibalize all the
existing istream-based classes?

Thanks :)
 
V

Victor Bazarov

Derek said:
Greetings,

I'm trying to create a generic multi-purpose istream class that is
capable of working in different ways based on different file paths.

For example, say an istream-based class that can take a URL as an open
() parameter, and then use a filebuf to open a "file://" path, a
socketbuf to open an "http://" or "telnet://" path, and an ftpbuf to
open an "ftp://" path.

I already have some existing working specific purpose istream-based
classes, but I cannot seem to find a way to build a generic one that
can then interface with one of the existing ones based upon the open
path/url.

Part of the problem I am having is that an istream class must contain
a streambuf that is initialized with the constructor, but I cannot
seem to figure out how to build an istream class that contains (or can
contain) multiple different types of streambufs, and be able to switch
between them, but perhaps this is the wrong approach.

Is there a way to make this work without having to cannibalize all the
existing istream-based classes?

The istream object inside your derived class has to contain a pointer to
the *active* buffer. Nothing prevents your *derived* object to contain
all pointers/buffers you want and supply them to the base object in the
derived class c-tor (after the base has been constructed). Or did I
miss something?

V
 
R

Ron

Part of the problem I am having is that an istream class must contain
a streambuf that is initialized with the constructor, but I cannot
seem to figure out how to build an istream class that contains (or can
contain) multiple different types of streambufs, and be able to switch
between them, but perhaps this is the wrong approach.
Make a streambuf that does the switching.
 
D

Derek

The istream object inside your derived class has to contain a pointer to
the *active* buffer.   Nothing prevents your *derived* object to contain
all pointers/buffers you want and supply them to the base object in the
derived class c-tor (after the base has been constructed).  Or did I
miss something?

The istream object must contain a (static) streambuf member, and the
istream-derived object calls the parent istream constructor passing a
reference to the streambuf. There does not appear to be (correct me
if I am wrong) a way to dynamically swap in a different buffer on the
fly.

Let me elaborate the issue with some rough (incomplete) code:

class isockstream: public istream
{
protected:
sockstreambuf sb;
public:
isockstream() : istream(&sb) {}
bool open(const char *host, int port, const char *method, const
char *url);
};

class iftpstream: public istream
{
protected:
ftpstreambuf sb;
public:
iftpstream() : istream(&sb) {}
bool open(const char *host, const char *user, const char *pwd,
const char *file);
};

class URL
{
public:
const char *file;
const char *host;
const char *user;
const char *pwd;
int port;
URL(const char *); // parse the url into component pieces
}

class urlstream: public istream
{
protected:
__filebuf_type ifb;
sockstreambuf isb;
ftpstreambuf ipb;
public:
urlstream() : istream(&ifb) {} // (use ifstream by default)
void open(const char *urlstr)
{
URL url(urlstr);

switch(url.type)
{
case utFILE:
ifb.open(url.file, ios::in);
// now need to make the ifs buf is being used
break;
case utHTTP:
isb.open(url.host, url.port, "GET", url.file);
// now need to make the isb buf is being used
break;
case utFTP:
ipb.open(url.host, url.user, url.pwd, url.file);
// now need to make the ipb buf is being used
break;
}
}
void close();
};

Is this the correct approach? How do I swap which streambuf is
active?
 
D

Derek

Make a streambuf that does the switching.

With this approach (say we call this urlstreambuf), does then my
urlstreambuf then contain the other streambuf types as members, and
access them based on an internal setting?

I tried this, but the problem is that my urlstreambuf does not have
permission to call for example sockstreambuf, filebuf or
ftpstreambuf's protected methods (i.e. sync(), underflow(), overflow
(), width(), fill(), etc). How do I properly connect the
urlstreambuf's stream control methods to the currently active
streambuf's control methods?
 
V

Victor Bazarov

Derek said:
The istream object must contain a (static) streambuf member, and the
istream-derived object calls the parent istream constructor passing a
reference to the streambuf. There does not appear to be (correct me
if I am wrong) a way to dynamically swap in a different buffer on the
fly.

No? Uh... what's the 'rdbuf' member is for, then?
Let me elaborate the issue with some rough (incomplete) code:

class isockstream: public istream
{
protected:
sockstreambuf sb;
public:
isockstream() : istream(&sb) {}
bool open(const char *host, int port, const char *method, const
char *url);
};

class iftpstream: public istream
{
protected:
ftpstreambuf sb;
public:
iftpstream() : istream(&sb) {}
bool open(const char *host, const char *user, const char *pwd,
const char *file);
};

class URL
{
public:
const char *file;
const char *host;
const char *user;
const char *pwd;
int port;
URL(const char *); // parse the url into component pieces
}

class urlstream: public istream
{
protected:
__filebuf_type ifb;
sockstreambuf isb;
ftpstreambuf ipb;
public:
urlstream() : istream(&ifb) {} // (use ifstream by default)
void open(const char *urlstr)
{
URL url(urlstr);

switch(url.type)
{
case utFILE:
ifb.open(url.file, ios::in);
// now need to make the ifs buf is being used

this->rdbuf(&ifb); // I think you mean 'ifb', not 'ifs'...
break;
case utHTTP:
isb.open(url.host, url.port, "GET", url.file);
// now need to make the isb buf is being used

this->rdbuf(&isb);
break;
case utFTP:
ipb.open(url.host, url.user, url.pwd, url.file);
// now need to make the ipb buf is being used

this->rdbuf(&ipb);
break;
}
}
void close();
};

Is this the correct approach? How do I swap which streambuf is
active?

See above. But I am an amateur AFA streams are concerned.

V
 
D

Derek

No?  Uh... what's the 'rdbuf' member is for, then?

Ah... rdbuf... never touched it before. It sounds like it "should"
work... I'll give that a try and let you know if it works.

Thanks :)
 
J

James Kanze

I'm trying to create a generic multi-purpose istream class
that is capable of working in different ways based on
different file paths.
For example, say an istream-based class that can take a URL as
an open () parameter, and then use a filebuf to open a
"file://" path, a socketbuf to open an "http://" or
"telnet://" path, and an ftpbuf to open an "ftp://" path.
I already have some existing working specific purpose
istream-based classes, but I cannot seem to find a way to
build a generic one that can then interface with one of the
existing ones based upon the open path/url.
Part of the problem I am having is that an istream class must
contain a streambuf that is initialized with the constructor,

Where did you get this misinformation?
but I cannot seem to figure out how to build an istream class
that contains (or can contain) multiple different types of
streambufs, and be able to switch between them, but perhaps
this is the wrong approach.
Is there a way to make this work without having to cannibalize
all the existing istream-based classes?

There are several simple solutions. Perhaps the easiest is to
use a static member function to new the correct type of
streambuf, which is then passed to the base [io]stream.
Something like:

IUrlStream::IUrlStream(
std::string const& url )
: std::istream( createStreambuf( url ) )
{
}

(And don't forget to delete the streambuf in the destructor.)

Alternatively, you can use a filtering streambuf. You'll
probably want to in the end anyway, in order to easily insert a
filter to transcode whatever to and from UTF-8. Although in
this case, I'd probably only insert the filter when I finally
knew the encoding---don't forget that you can change the
streambuf on the fly, if you need to.
 
J

James Kanze

With this approach (say we call this urlstreambuf), does then
my urlstreambuf then contain the other streambuf types as
members, and access them based on an internal setting?

Not contain. It forwards to another streambuf. It contains a
pointer to this streambuf, which it may or may not own.

Look up filtering streambufs on the net. For starters:
http://kanze.james.neuf.fr/articles/fltrsbf1.html.
I tried this, but the problem is that my urlstreambuf does not
have permission to call for example sockstreambuf, filebuf or
ftpstreambuf's protected methods (i.e. sync(), underflow(),
overflow (), width(), fill(), etc).

Which is normal. It shouldn't.
How do I properly connect the urlstreambuf's stream control
methods to the currently active streambuf's control methods?

By calling the public functions, what else. The underflow
function of the filtering streambuf calls sgetc of the streambuf
it refers to, and so on.

(But in this case, I'm not sure that this is the best solution.
Just allocating the streambuf dynamically seems sufficient.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top