469,616 Members | 1,806 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,616 developers. It's quick & easy.

Problem with user-defined IO streambuf for encoding purposes

Hi everyone,

I'm having some difficulty with the following piece of code. I have
stripped it to it's bare minimum to demonstrate the problem at hand.

Compiler: MS Visual C++ 2005 Express Edition (similar problem arises
with 2008)

Runtime Library: All multi-threaded variants have been seen to fail
[DLL/Static] | [Debug|Release]

Purpose: define a user defined stream buffer that processes each
incoming character and translates it to an encoded value. Place the
encoded character into a local buffer for output. The most simple case
would be an encoder that translates each character to upper case. A
more complicated case would be an encoder that encodes plain-text to
base64 encoding (this is not a one-to-one character encoding, it's a 3
character to 4character encoding, this is why an internal buffer is
needed)

Problem: The code throws an "Unhandled exception at 0x00529bcc in
hsl_d.exe: 0xC0000005: Access violation reading location 0x00000000."
after the "encoderbuf::underflow c = 51" character '3' has been read.
This basically tells me that deep down in the internals of the IO
library something is being dereferenced that is not allocated.

Question(s):
1) Does this occur with other compilers? (requires testing)
2) Is this a problem with the IO library? (unlikely I think)
3) Am I doing something stupid? (more than likely) And if so what?

References:
C++ Standard Library - A Tutorial and Reference (13.13.3 User-Defined
Stream Buffers)
Code:

#include <iostream>
#include <sstream>

class encoderbuf : public std::streambuf {

char mCharBuf[128];
int mBufLen;
int mBufPos;
public:
//--------------------------------------------------------------
/** default constructor */
encoderbuf()
: std::streambuf()
, mBufLen(0)
, mBufPos(0)
{
}

//--------------------------------------------------------------
/** outgoing data */
virtual int_type underflow () {
int_type c = EOF;
if (mBufPos < mBufLen) {
c = mCharBuf[mBufPos++];
}
std::cout << "encoderbuf::underflow c = " << c << std::endl;

return c;
}

//--------------------------------------------------------------
/** incoming data */
virtual int_type overflow (int_type c) {
std::cout << "encoderbuf::overflow c = " << c << std::endl;
//TODO: do encoding here
mCharBuf[mBufLen++] = c;
return c;
}
};

//--------------------------------------------------------------
int main (int argc, char ** argv) {
encoderbuf buf;
std::iostream iostr(&buf);
iostr << 12345 << std::endl;
std::stringstream sstr;
iostr >sstr.rdbuf(); // EXCEPTION AT PROCESSING CHARACTER '3'

std::string str = sstr.str();
std::cout << "main str = " << str << std::endl;
}
Output:
encoderbuf::overflow c = 49
encoderbuf::overflow c = 50
encoderbuf::overflow c = 51
encoderbuf::overflow c = 52
encoderbuf::overflow c = 53
encoderbuf::overflow c = 10
encoderbuf::underflow c = 49
encoderbuf::underflow c = 50
encoderbuf::underflow c = 51
popup: Unhandled exception at 0x00529bcc in hsl_d.exe: 0xC0000005:
Access violation reading location 0x00000000.
Dec 12 '07 #1
10 3074
hs********@gmail.com wrote:
Hi everyone,

I'm having some difficulty with the following piece of code. I have
stripped it to it's bare minimum to demonstrate the problem at hand.

Compiler: MS Visual C++ 2005 Express Edition (similar problem arises
with 2008)

Runtime Library: All multi-threaded variants have been seen to fail
[DLL/Static] | [Debug|Release]

Purpose: define a user defined stream buffer that processes each
incoming character and translates it to an encoded value. Place the
encoded character into a local buffer for output. The most simple case
would be an encoder that translates each character to upper case. A
more complicated case would be an encoder that encodes plain-text to
base64 encoding (this is not a one-to-one character encoding, it's a 3
character to 4character encoding, this is why an internal buffer is
needed)

Problem: The code throws an "Unhandled exception at 0x00529bcc in
hsl_d.exe: 0xC0000005: Access violation reading location 0x00000000."
after the "encoderbuf::underflow c = 51" character '3' has been read.
This basically tells me that deep down in the internals of the IO
library something is being dereferenced that is not allocated.

Question(s):
1) Does this occur with other compilers? (requires testing)
2) Is this a problem with the IO library? (unlikely I think)
3) Am I doing something stupid? (more than likely) And if so what?

References:
C++ Standard Library - A Tutorial and Reference (13.13.3 User-Defined
Stream Buffers)
Code:

#include <iostream>
#include <sstream>

class encoderbuf : public std::streambuf {

char mCharBuf[128];
int mBufLen;
int mBufPos;
public:
//--------------------------------------------------------------
/** default constructor */
encoderbuf()
: std::streambuf()
, mBufLen(0)
, mBufPos(0)
{
}

//--------------------------------------------------------------
/** outgoing data */
virtual int_type underflow () {
int_type c = EOF;
if (mBufPos < mBufLen) {
c = mCharBuf[mBufPos++];
}
std::cout << "encoderbuf::underflow c = " << c << std::endl;

return c;
}

//--------------------------------------------------------------
/** incoming data */
virtual int_type overflow (int_type c) {
std::cout << "encoderbuf::overflow c = " << c << std::endl;
//TODO: do encoding here
mCharBuf[mBufLen++] = c;
Most likely you meant
mCharBuf[mBufPos++] = c;
here. mBufPos, not mBufLen.
return c;
}
};

//--------------------------------------------------------------
int main (int argc, char ** argv) {
encoderbuf buf;
std::iostream iostr(&buf);
iostr << 12345 << std::endl;
std::stringstream sstr;
iostr >sstr.rdbuf(); // EXCEPTION AT PROCESSING CHARACTER '3'

std::string str = sstr.str();
std::cout << "main str = " << str << std::endl;
}
Output:
encoderbuf::overflow c = 49
encoderbuf::overflow c = 50
encoderbuf::overflow c = 51
encoderbuf::overflow c = 52
encoderbuf::overflow c = 53
encoderbuf::overflow c = 10
encoderbuf::underflow c = 49
encoderbuf::underflow c = 50
encoderbuf::underflow c = 51
popup: Unhandled exception at 0x00529bcc in hsl_d.exe: 0xC0000005:
Access violation reading location 0x00000000.


--
Jim Langston
ta*******@rocketmail.com
Dec 12 '07 #2
hs********@gmail.com wrote:
>
Has anyone tried running this code under Linux? I don't have a Linux
machine handy at the moment, but I would be curious to know if this is
strictly a MS issue.
It crashes.
Dec 12 '07 #3
On Dec 12, 9:34 am, hsmit.h...@gmail.com wrote:
I'm having some difficulty with the following piece of code. I have
stripped it to it's bare minimum to demonstrate the problem at hand.

Compiler: MS Visual C++ 2005 Express Edition (similar problem arises
with 2008)

Runtime Library: All multi-threaded variants have been seen to fail
[DLL/Static] | [Debug|Release]

Purpose: define a user defined stream buffer that processes each
incoming character and translates it to an encoded value. Place the
encoded character into a local buffer for output. The most simple case
would be an encoder that translates each character to upper case. A
more complicated case would be an encoder that encodes plain-text to
base64 encoding (this is not a one-to-one character encoding, it's a 3
character to 4character encoding, this is why an internal buffer is
needed)

Problem: The code throws an "Unhandled exception at 0x00529bcc in
hsl_d.exe: 0xC0000005: Access violation reading location 0x00000000."
after the "encoderbuf::underflow c = 51" character '3' has been read.
This basically tells me that deep down in the internals of the IO
library something is being dereferenced that is not allocated.

Question(s):
1) Does this occur with other compilers? (requires testing)
2) Is this a problem with the IO library? (unlikely I think)
3) Am I doing something stupid? (more than likely) And if so what?

References:
C++ Standard Library - A Tutorial and Reference (13.13.3 User-Defined
Stream Buffers)

Code:

#include <iostream>
#include <sstream>

class encoderbuf : public std::streambuf {

char mCharBuf[128];
int mBufLen;
int mBufPos;
public:
//--------------------------------------------------------------
/** default constructor */
encoderbuf()
: std::streambuf()
, mBufLen(0)
, mBufPos(0)
{
}

//--------------------------------------------------------------
/** outgoing data */
virtual int_type underflow () {
int_type c = EOF;
if (mBufPos < mBufLen) {
c = mCharBuf[mBufPos++];
}
std::cout << "encoderbuf::underflow c = " << c << std::endl;
return c;
}
Attention: this function does not meet the requirements for
underflow. Underflow must return the character, leaving it in
the stream. This normally involves at least a one character
buffer. In your case, of course, you've got a longer buffer,
so you could just use that:

int_type c = EOF ;
if ( mBufPos != mBufLen ) {
setg( mCharBuf, mCharBuf + mBufPos, mCharBuf + mBufLen ) ;
c = mCharBuf[ mBufPos ] ;
mBufPos = mBufLen ;
}
return c ;

. Although the problem being addressed is somewhat different,
you'll find a short discussion concerning the requirements of
underflow and overflow in my articles on filtering streambuf's
(http://kanze.james.neuf.fr/articles-en.html).
//--------------------------------------------------------------
/** incoming data */
virtual int_type overflow (int_type c) {
std::cout << "encoderbuf::overflow c = " << c << std::endl;
//TODO: do encoding here
mCharBuf[mBufLen++] = c;
return c;
}
};
//--------------------------------------------------------------
int main (int argc, char ** argv) {
encoderbuf buf;
std::iostream iostr(&buf);
iostr << 12345 << std::endl;
std::stringstream sstr;
iostr >sstr.rdbuf(); // EXCEPTION AT PROCESSING CHARACTER '3'
std::string str = sstr.str();
std::cout << "main str = " << str << std::endl;
}
Output:
encoderbuf::overflow c = 49
encoderbuf::overflow c = 50
encoderbuf::overflow c = 51
encoderbuf::overflow c = 52
encoderbuf::overflow c = 53
encoderbuf::overflow c = 10
encoderbuf::underflow c = 49
encoderbuf::underflow c = 50
encoderbuf::underflow c = 51
popup: Unhandled exception at 0x00529bcc in hsl_d.exe: 0xC0000005:
Access violation reading location 0x00000000.
I get the correct results with my version of underflow. Both
with g++ (under Linux) and VC++ (under Windows).

What's probably happening is that the implementation, having
read the character with underflow, increments the get pointer
(gptr()). Which is null, since you've never set it. The next
time around, it compares this pointer with egptr(), finds that
they aren't equal, and accesses through it directly. (This is,
at least, what happens with g++ under Solaris. At least, if the
input routing is using sgetn, this is what happens.)

The normal way of implementing input in a streambuf is to
override underflow, using a buffer of at least one character.
(The reason for this is to allow simple and direct support for
putback.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 12 '07 #4
Thank you James for all the useful info. Looks like I've got some
serious reading tonight.

Before I read your response I got my code to do what I wanted. It was
along the lines of what you described. It's still a work in progress.
Here is the result (comments/refinements/improvements of this code are
welcome, in fact they would very much be appreciatted).

Expand|Select|Wrap|Line Numbers
  1.  
  2. #include <iostream>
  3. #include <sstream>
  4.  
  5. //--------------------------------------------------------------
  6. /**
  7. General purpose buffered filter / encoder.
  8. @todo: still requires testing and refinement.
  9. */
  10. class encoderbuf : public std::streambuf {
  11.  
  12. std::stringbuf mBuf;
  13. char mIBuf[3]; //TODO: make this dynamic
  14.  
  15. public:
  16. //--------------------------------------------------------------
  17. /** default constructor */
  18. encoderbuf() {
  19. mBuf.pubsetbuf(mIBuf, sizeof(mIBuf));
  20. setg(mIBuf, mIBuf, mIBuf+sizeof(mIBuf));
  21. }
  22.  
  23. private:
  24. //--------------------------------------------------------------
  25. /** default encoder routine - does nothing */
  26. virtual void                  encode (int_type c) {
  27. *gptr() = c;
  28. gbump(1);
  29. }
  30.  
  31. //--------------------------------------------------------------
  32. /** flushes the buffered data to the final destination */
  33. int                            flush () {
  34. int_type c = mBuf.sbumpc();
  35. if (c == EOF) {
  36. return EOF;
  37. }
  38. while (c != EOF) {
  39. encode(c);
  40. if (gptr() >= egptr()) {
  41. break;
  42. }
  43. c = mBuf.sbumpc();
  44. }
  45. setg(mIBuf, mIBuf, gptr());
  46.  
  47. return 0;
  48. }
  49.  
  50. //--------------------------------------------------------------
  51. /** flush the buffered data to output */
  52. virtual int                   sync () {
  53. return flush();
  54. }
  55.  
  56.  
  57. //--------------------------------------------------------------
  58. /** buffer the incoming data */
  59. virtual int_type              overflow (int_type c) {
  60. return mBuf.sputc(c);
  61. }
  62.  
  63. //--------------------------------------------------------------
  64. /** reset the internal input buffers and flush the buffered
  65. data to output
  66. */
  67. virtual int_type              underflow () {
  68.  
  69. memset(mIBuf, 'x', sizeof(mIBuf));
  70. setg(mIBuf, mIBuf, mIBuf+sizeof(mIBuf));
  71.  
  72. if (flush() == EOF) {
  73. return EOF;
  74. }
  75.  
  76. return ((unsigned char)(*gptr()));
  77. }
  78. };
  79.  
  80. //--------------------------------------------------------------
  81. /**
  82. Example encoder
  83. */
  84. class uppercasebuf : public encoderbuf {
  85.  
  86. public:
  87. //--------------------------------------------------------------
  88. /** upper case encoder */
  89. virtual void                  encode (int_type c) {
  90. *gptr() = toupper(c);
  91. gbump(1);
  92. }
  93. };
  94.  
  95. //--------------------------------------------------------------
  96. int main (int argc, char ** argv) {
  97. uppercasebuf buf;
  98. std::iostream iostr(&buf);
  99. iostr << "abcdef";
  100. iostr << "123HIG";
  101. iostr << "aabb" << std::endl;
  102. std::string str;
  103. iostr >str;
  104. std::cout << "test_encoderbuf str = " << str << std::endl;
  105. }
  106.  
  107.  
  108.  
Cheers,

Hans Smit
Dec 12 '07 #5
On Dec 12, 9:55 am, "Alf P. Steinbach" <al...@start.nowrote:
* Jim Langston:
[...]
std::stringstream sstr;
iostr >sstr.rdbuf(); // EXCEPTION AT PROCESSING CHARACTER '3'
The call to rdbuf() looks suspicious. Since I try to avoid
the unclean iostreams as much as possible I don't know. But
at least it sort of sounds wrong.
It's the usual way of testing new, user-defined streams. It's
true that it's somewhat surprising, since it's a >operator
that doesn't parse anything, but since it's designed mainly for
debugging.

Writing your own streambuf isn't very difficult, but you do have
to respect the contract for the virtual functions you implement.
In the case of underflow(), the standard says very clearly that
unless it returns EOF, it must return "the first character of
the pending sequence, without moving the input sequence position
past it." It's possible to do so without using a buffer, but
that requires also overriding uflow() (whose default
implementation increments the pointer into the buffer), and
pbackfail() (since the implementation has to support at least
one character pushback). This has been discussed in published
articles---I know because I wrote them.

And of course, if you think that iostream is unclean, you're
free to propose something better. The original iostream, by
Jerry Schwarz, is in impressively elegant solution to the
contraints he had at that time. IMHO, the standards committee
didn't improve it, and of course, if we were designing it from
scratch today, we'd do some things differently, but I've not
seen any concrete alternatives that are better.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 12 '07 #6
On 2007-12-12 12:10:35 -0500, hs********@gmail.com said:
Method names such as
"showmanyc"
are a little unclear when first working with this library, i.e. I kept
seeing
"show many c" for some strange reason.
There's a footnote in the standard that addresses this: "The morphemes
of showmanyc are es-how-many-see", not "show-manic".

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Dec 12 '07 #7
On Dec 12, 7:22 pm, Pete Becker <p...@versatilecoding.comwrote:
On 2007-12-12 12:10:35 -0500, hsmit.h...@gmail.com said:
Method names such as
"showmanyc"
are a little unclear when first working with this library, i.e. I kept
seeing
"show many c" for some strange reason.

There's a footnote in the standard that addresses this: "The morphemes
of showmanyc are es-how-many-see", not "show-manic".

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
That footnote is in quite a few references. The fact that a footnote
had to be issued for this validates my point that some of the naming
conventions in this library are non-intuitive. Nevertheless, the power
and heritage of this library in-validates any comments I have about
it ;-)
Dec 12 '07 #8
On Dec 12, 4:33 pm, hsmit.h...@gmail.com wrote:
Before I read your response I got my code to do what I wanted.
It was along the lines of what you described. It's still a
work in progress. Here is the result
(comments/refinements/improvements of this code are welcome,
in fact they would very much be appreciatted).
Just some quick comments:
[code]
#include <iostream>
#include <sstream>
//--------------------------------------------------------------
/**
General purpose buffered filter / encoder.
@todo: still requires testing and refinement.
*/
class encoderbuf : public std::streambuf {
std::stringbuf mBuf;
char mIBuf[3]; //TODO: make this dynamic
You can use std::vector< char >, and skip the stringbuf
entirely.
public:
//--------------------------------------------------------------
/** default constructor */
encoderbuf() {
mBuf.pubsetbuf(mIBuf, sizeof(mIBuf));
Note that the behavior of stringbuf::setbuf is implementation
defined, and that an implementation is not required to respect
it.
setg(mIBuf, mIBuf, mIBuf+sizeof(mIBuf));
And that this statement basically means that you have two
different class instances (the base class and you mBuf member)
sharing the same buffer, in an unspecified manner.
}
private:
//--------------------------------------------------------------
/** default encoder routine - does nothing */
virtual void encode (int_type c) {
*gptr() = c;
gbump(1);
Uses the buffer defined in the base class. I'd use the
std::vector, and then something like:

mBuffer.push_back( c ) ;

Since you don't seem to be supporting buffering on input,
there's no reason to touch the put pointers. And you definitly
shouldn't be messing with the get pointers on output; at the
very most, you might do something like:
setg( &mBuffer[ 0 ],
&mBuffer[ 0 ] + gptr() - eback(),
&mBuffer[ 0 ] + mBuffer.size() ) ;
(but you could just as well do this in underflow()).
}
//--------------------------------------------------------------
/** flushes the buffered data to the final destination */
int flush () {
int_type c = mBuf.sbumpc();
if (c == EOF) {
return EOF;
}
while (c != EOF) {
encode(c);
Note that encode manipulates mIBuf, which you passed to mBuf.
If your code works, it is probably because mBuf is ignoring the
setbuf.
if (gptr() >= egptr()) {
break;
}
c = mBuf.sbumpc();
}
setg(mIBuf, mIBuf, gptr());
return 0;
}
//--------------------------------------------------------------
/** flush the buffered data to output */
virtual int sync () {
return flush();
}
//--------------------------------------------------------------
/** buffer the incoming data */
virtual int_type overflow (int_type c) {
return mBuf.sputc(c);
}
//--------------------------------------------------------------
/** reset the internal input buffers and flush the buffered
data to output
*/
virtual int_type underflow () {
memset(mIBuf, 'x', sizeof(mIBuf));
setg(mIBuf, mIBuf, mIBuf+sizeof(mIBuf));
if (flush() == EOF) {
return EOF;
}
return ((unsigned char)(*gptr()));
}
};
In fact, if I've understood at all, you're really using two
different buffers, mBuf and mIBuf, and transferring between them
in flush. As long as you are calling encode for each individual
character, and not on the complete buffer, I wouldn't bother.
Use an std::vector< char as the buffer: overflow simply calls
encode, which does a push_back on whatever it generates. (I'd
provide a protected function for this, rather than make the
std::vector directly accessible.) Underflow simply updates the
get pointers and returns *gptr() if gptr() != egptr(), e.g.:

int_type
encoderbuf::underflow()
{
setg( &mBuffer[ 0 ],
&mBuffer[ 0 ] + gptr() - eback(),
&mBuffer[ 0 ] + mBuffer.size() ) ;
return gptr() == egptr()
? traits_type::eof()
: traits_type::to_int_type( *gptr() ) ;
}

In this particular case, I'd also ask myself if a streambuf is
really the correct solution. On the whole, for memory to memory
translations, I'd rather go with a custom insertion_iterator,
invoked as the destination of std::copy, e.g.:

std::copy( source.being(), source.end(),
EncodingInserter( dest ) ) ;

(If the encoding is one to one, of course, all you need is a
function and std::transform.)

An insertion iterator is an output iterator (in other words, not
an iterator at all), which means that many of the constraints
normally present on iterators are absent. Just be aware that it
may be (and in fact will be) copied, so if it needs modifiable
internal state, you have to be careful.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 13 '07 #9
James, you have given me so much to chew on, I am deeply indebted.

Before I read your last post, I had finally gotten a reasonably
generic encoderbuf class implemented, there are still a few kinks in
it and I will continue working on this today. I will see if I can
integrate a few of your ideas, since these "kinks" I refered to make
me feel like I am doing something terribly wrong (even though it
works). I need to investigate further before I can properly articulate
this additional problem.

Your insertion iterator idea is something I will be looking into
sometime later (more as an excercies in understanding than anything
else). I am an old newbie to the STL library. Worked with it quite a
bit 7-9 years ago, put it aside for some time, and started working
with it again 6 months ago. I am finally discovering the beautiful
intracies of this remarkable library.

I will post my "semi-final" solution when it's ready.
Dec 14 '07 #10
My apologies for posting this large piece of code, but it is complete.
Who knows, it may actually be useful to someone else.

There are 3 sections:
1) the encoderbuf class
2) the 3 test classes: uppercasebuf, fillbuf, dividerbuf
3) the main entry point with the various test cases.

I have taken James' last post to heart and completely rewrote the
encoderbuf class. It is simpler and more to the point.

Comments and suggestions would be very much appreciatted.

A couple questions for James:
1) Your suggested implementation of using mBuffer.push_back(c) is a
good one, but when does it ever get cleared (flushed)?
For example:
encoderbuf buf;
std::iostream iostr(&buf);
std::string str;
iostr << 12345 << std::endl;
iostr >str ;
iostr << 12345 << std::endl;
iostr >str ;
iostr << 12345 << std::endl;
iostr >str ;
iostr << 12345 << std::endl;
iostr >str ;

The mBuffer.size() is now 20 and growing if I continue in this trend.
The encoderbuf class code below addresses this, but my solution
doesn't feel right. Refer to can_empty() method. Any comments?

2) Back to your previous post: Could you explain the gptr() - eback()
part of this statement:
setg( &mBuffer[ 0 ],
&mBuffer[ 0 ] + gptr() - eback(),
&mBuffer[ 0 ] + mBuffer.size() ) ;

The second argument refers to where the current internal buffer is
currently ready to be written to (IGNext). This I understand. But in
the underflow scenario gptr() should always equal eback(). Or am I
missing something here? My inclination is to write:
setg(&mBuffer[0], &mBuffer[0], &mBuffer[0]+mBuffer.size());

Thanks for all the help,

Hans Smit

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <sstream>
  3. #include <vector>
  4.  
  5. //--------------------------------------------------------------
  6. /**
  7. General purpose buffered filter / encoder.
  8. */
  9. class encoderbuf : public std::streambuf {
  10.  
  11. std::vector<charmEncBuf;
  12.  
  13. public:
  14. //--------------------------------------------------------------
  15. /** default constructor */
  16. encoderbuf()
  17. {
  18. }
  19.  
  20. protected:
  21. //--------------------------------------------------------------
  22. /**
  23. The sub class should call this method after a character is
  24. encoded, or call it multiple times in case of a 1 to N character
  25. encoding scheme, i.e. base64 encoding, url encoding, etc.
  26.  
  27. @param c the encoded character that is to be placed in the
  28. input buffer.
  29.  
  30. @return the number of characters placed in the input buffer
  31. Currently only 1 is returned, but I want to leave room for
  32. future development and overflow errors.
  33. */
  34. virtual int                    encode (int_type c) {
  35.  
  36. if (can_empty()) {
  37. setg(&mEncBuf[0], &mEncBuf[0], &mEncBuf[0]);
  38. mEncBuf.clear();
  39. }
  40.  
  41. mEncBuf.push_back(c);
  42.  
  43. return 1;
  44. }
  45.  
  46. private:
  47. //--------------------------------------------------------------
  48. /**
  49. check to see if the internal buffer has been processed and
  50. is ready to be emptied. This ensures that memory is reused
  51. between << and >shift operations.
  52. */
  53. bool                          can_empty () {
  54. size_t cp = gptr() - eback();
  55. return (cp != 0);
  56. }
  57.  
  58. //--------------------------------------------------------------
  59. /**
  60. Reset the internal input buffers and flush the buffered
  61. data to output
  62. */
  63. virtual int_type              underflow () {
  64.  
  65. size_t cp = gptr() - eback(); //I don't get this.
  66. size_t sz = mEncBuf.size();
  67.  
  68. setg(&mEncBuf[0], &mEncBuf[0] + cp, &mEncBuf[0] + sz);
  69.  
  70. return gptr() == egptr()
  71. ?   traits_type::eof()
  72. :   traits_type::to_int_type( *gptr() ) ;
  73. }
  74.  
  75.  
  76. //--------------------------------------------------------------
  77. /**
  78. Encode the incoming character and place it in internal
  79. buffer
  80. */
  81. virtual int_type              overflow (int_type c) {
  82.  
  83. encode(c);
  84.  
  85. return c;
  86. }
  87. };
  88.  
  89.  
  90. //--------------------------------------------------------------
  91. /**
  92. Example encoder: 1 to N character encoding
  93. */
  94. class fillbuf : public encoderbuf {
  95.  
  96. std::stringbuf mOverflowBuf;
  97. size_t mCount;
  98. public:
  99. fillbuf (size_t count)
  100. : mCount(count)
  101. {
  102. }
  103.  
  104. //--------------------------------------------------------------
  105. /** fill encoder */
  106. virtual int                   encode (int_type c) {
  107.  
  108. int n = 0;
  109. for (size_t i = 0 ; i < mCount ; i++) {
  110. n += encoderbuf::encode(c);
  111. }
  112.  
  113. return n;
  114. }
  115. };
  116.  
  117.  
  118. //--------------------------------------------------------------
  119. /**
  120. Example encoder: an N to 1 character encoding
  121. */
  122. class dividerbuf : public encoderbuf {
  123.  
  124. std::stringbuf mBuf;
  125. size_t mCount;
  126. size_t mLen;
  127. public:
  128. dividerbuf (size_t count)
  129. : mCount(count)
  130. , mLen(0)
  131. {
  132. }
  133. //--------------------------------------------------------------
  134. /** encoder */
  135. virtual int                   encode (int_type c) {
  136.  
  137. if ((mLen+mCount) % mCount == 0) {
  138. encoderbuf::encode(c);
  139. }
  140. mLen++;
  141.  
  142. return 1;
  143. }
  144. };
  145.  
  146. //--------------------------------------------------------------
  147. /**
  148. Example encoder: a 1 to 1 character encoding
  149. */
  150. class uppercasebuf : public encoderbuf {
  151.  
  152. public:
  153. //--------------------------------------------------------------
  154. /** upper case encoder */
  155. virtual int                  encode (int_type c) {
  156. return encoderbuf::encode(toupper(c));
  157. }
  158. };
  159.  
  160. //--------------------------------------------------------------
  161. int main (int argc, char ** argv) {
  162.  
  163. if (true) {
  164. encoderbuf buf;
  165. std::iostream iostr(&buf);
  166. std::stringstream sstr;
  167. std::string str;
  168.  
  169. iostr << 12345 << std::endl;
  170. iostr >str ;
  171. if (str == "12345") {
  172. std::cout << "ok. encoderbuf str = " << str << std::endl;
  173. } else {
  174. std::cout << "err. encoderbuf str = " << str << std::endl;
  175. }
  176. iostr << 6789 << std::endl;
  177. iostr >str ;
  178. if (str == "6789") {
  179. std::cout << "ok. encoderbuf str = " << str << std::endl;
  180. } else {
  181. std::cout << "err. encoderbuf str = " << str << std::endl;
  182. }
  183.  
  184. }
  185. if (true) {
  186. encoderbuf buf;
  187. std::iostream iostr(&buf);
  188. iostr << 12345 << "," << 1.234;// << std::endl;
  189. std::stringstream ostr;
  190. std::string str2;
  191. //iostr >str2;
  192. //iostr.flush();
  193. //iostr.clear();
  194. iostr >ostr.rdbuf();
  195. std::string str = ostr.str();
  196. if (str == "12345,1.234") {
  197. std::cout << "ok. encoderbuf str = " << str << std::endl;
  198. } else {
  199. std::cout << "err. encoderbuf str = " << str << std::endl;
  200. }
  201. }
  202. if (true) {
  203. for (int i = 2 ; i < 32 ; i += 1) {
  204. encoderbuf buf;
  205. std::iostream iostr(&buf);
  206. iostr << "abcdef";
  207. iostr << 12345;
  208. iostr << "123HIG";
  209. iostr << "aabb" << std::endl;
  210. std::string str;
  211. iostr >str;
  212. if (str == "abcdef12345123HIGaabb") {
  213. std::cout << "ok. buf len = " << i << ". encoderbuf str = " <<
  214. str << std::endl;
  215. } else {
  216. std::cout << "err. buf len = " << i << ". encoderbuf str = "
  217. << str << std::endl;
  218. }
  219. }
  220. }
  221.  
  222. if (true) {
  223. uppercasebuf buf;
  224. std::iostream iostr(&buf);
  225. iostr << "abcdef";
  226. iostr << "123HIG";
  227. iostr << "aabb" << std::endl;
  228. std::string str;
  229. iostr >str;
  230. if (str == "ABCDEF123HIGAABB") {
  231. std::cout << "ok. uppercasebuf str = " << str << std::endl;
  232. } else {
  233. std::cout << "err. uppercasebuf str = " << str << std::endl;
  234. }
  235. }
  236. if (true) {
  237. fillbuf buf(3);
  238. std::iostream iostr(&buf);
  239. iostr << "abcde" << std::endl; ;
  240. std::string str;
  241. iostr >str;
  242. if (str == "aaabbbcccdddeee") {
  243. std::cout << "ok. doublerbuf str = " << str << std::endl;
  244. } else {
  245. std::cout << "err. doublerbuf str = " << str << std::endl;
  246. }
  247. }
  248. if (true) {
  249. dividerbuf buf(2);
  250. std::iostream iostr(&buf);
  251. iostr << "xy0123456789" << std::endl;
  252. std::string str;
  253. iostr >str;
  254. if (str == "x02468") {
  255. std::cout << "ok. dividerbuf str = " << str << std::endl;
  256. } else {
  257. std::cout << "err. dividerbuf str = " << str << std::endl;
  258. }
  259. }
  260. return 0;
  261. }
  262.  
  263.  
Dec 14 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by Jim | last post: by
5 posts views Thread by | last post: by
2 posts views Thread by Joseph Geretz | last post: by
6 posts views Thread by Ammar | last post: by
1 post views Thread by Steven M. | last post: by
2 posts views Thread by Mike Collins | last post: by
6 posts views Thread by oooobs | last post: by
reply views Thread by devrayhaan | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.