I'm using boost iostreams (1.64.0) in order to decompress zlib data. I want to do streaming decompression. That means the compressed data are unpredictable size. I wrote the following code example.
#include <sstream>
#include <string>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>
int main() {
// Compress
std::stringstream sender;
boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
out.push(boost::iostreams::zlib_compressor());
out.push(sender);
sender << "Hello World";
std::stringstream compressed;
boost::iostreams::copy(out, compressed);
// Decompress
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor());
in.push(compressed);
std::istream is(&in);
std::size_t const buf_size = 256;
char buf[buf_size] = { '\0' };
#if 0
is.getline(buf, buf_size); // works fine
#else
std::size_t read_size = is.readsome(buf, buf_size);
std::cout << "read_size:" << read_size << std::endl;
#endif
// http://www.cplusplus.com/reference/ios/ios/rdstate/
std::cout << "rdstate:" << is.rdstate() << std::endl;
std::cout << buf << std::endl;
}
I use readsome()
because the size of data is unpredictable.
I got the following output:
read_size:0
rdstate:0
It was unexpected for me.
If I use getline()
instead of readsome()
, I got the following output:
rdstate:2
Hello World
It was expected output.
I think that when I use readsome()
, the out put should be the same.
I can't use getline()
my in actual code because the original data is binary format.
Is there any way to use readsome()
with filtering_streambuf
or any good way to streaming decompress unpredictable length binary data?
Thanks to sehe's comment, the problem is solved.
I wrote the response for the comment but it is difficult to read because codes are not well formatted. So I answer by myself. I hope it will help for other people who have similar problem.
I replaced
std::size_t read_size = is.readsome(buf, buf_size);
with
is.read(buf, buf_size);
std::size_t read_size = is.gcount();
, then problem is solved.
I had misunderstood that std::istream::read
blocks until reading buf_size
length data. It is not true. Even if the actual read size is less than buf_size, the function returns. See http://www.cplusplus.com/reference/istream/istream/read/. In order to get read_size
, I call std::istream::gcount()
. See http://www.cplusplus.com/reference/istream/istream/gcount/.
NOTE: I had gotten confused with boost::asio::read
and boost::asio::ip::tcp::socket::read_some
. But their behavior are different from std::istream
's one.
Here is the complete code of the fixed version:
#include <sstream>
#include <string>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>
int main() {
// Compress
std::stringstream sender;
boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
out.push(boost::iostreams::zlib_compressor());
out.push(sender);
sender << "Hello World";
std::stringstream compressed;
boost::iostreams::copy(out, compressed);
// Decompress
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor());
in.push(compressed);
std::istream is(&in);
std::size_t const buf_size = 256;
char buf[buf_size] = { '\0' };
is.read(buf, buf_size);
std::size_t read_size = is.gcount();
std::cout << "read_size:" << read_size << std::endl;
// http://www.cplusplus.com/reference/ios/ios/rdstate/
std::cout << "rdstate:" << is.rdstate() << std::endl;
std::cout << buf << std::endl;
}