New automated test for ZlibDecompressorIStreambuf::xsgetn(). xsgetn() is
called by sgetn() from the base class std::streambuf. In our case,
xsgetn() is actually defined in the base class ZlibAbstractIStreambuf
(subclass of std::streambuf), therefore this new test also applies to
ZlibCompressorIStreambuf and the two other related classes,
ZlibCompressorIStream and ZlibDecompressorIStream.
This test asks [x]sgetn() the largest possible amount of chars every
time it is called, i.e., the largest value that can be represented by
std::streamsize. This exercises the code in interesting ways due to the
various types involved (zlib's uInt, std::size_t and std::streamsize,
which have various sizes depending on the platform).
Compilation of these files was disabled in commit
e21ad4b5c1.
Fix build errors and warnings:
- Ambiguous template parameters for std::min();
- No appropriate default constructor available for
std::basic_istream<char,std::char_traits<char>> (the std::istream
subclasses didn't explicitly call the std::istream constructor,
which requires an argument). This is presumably exactly the reason
why sg_gzifstream is declared like this:
class sg_gzifstream : private gzifstream_base, public std::istream
where gzifstream_base is an empty shell for a stream buffer object:
struct gzifstream_base
{
gzifstream_base() {}
gzfilebuf gzbuf;
};
This ensures that the stream buffer object (gzbuf) is initialized
before std::istream's constructor is called. I solved this problem
in a different way, hopefully easier to understand, and requiring
neither an additional class nor multiple inheritance: first, we
initialize the std::istream base with a nullptr as the
std::streambuf * argument (this is valid C++11), then in the
constructor bodies for ZlibCompressorIStream and
ZlibDecompressorIStream, we call std::istream::rdbuf() to attach the
std::istream instance to the now-initialized stream buffer object.
- Possible truncation of constant value on 32 bits systems (this was
in zlibMaxChunkSize() which is now removed, see below).
Type-related improvements:
- Remove zlibMaxChunkSize() and zlibMaxChunk: in C++, one can simply
use std::numeric_limits<uInt>::max()---most of the code in
zlibMaxChunkSize() was there only to find this value via a zlib
function call.
- Add helper function templates zlibChunk() and clipCast().
- Split preparation of the putback area out of
ZlibAbstractIStreambuf::xsgetn() to a new utility method:
xsgetn_preparePutbackArea().
- More rigorous type handling in zlibstream_test.cxx.
Some precautions are necessary because the IOStreams API uses
std::streamsize in many places (e.g., the return value of
std::istream::gcount()), but functions such as the following
std::string constructor:
std::string(const char* s, std::size_t n);
work with std::size_t instead. Since these types are different and
opaque, this requires some care!
Add:
- two stream buffer classes (ZlibCompressorIStreambuf and
ZlibDecompressorIStreambuf), both based on the same abstract class:
ZlibAbstractIStreambuf;
- two std::istream subclasses (ZlibCompressorIStream and
ZlibDecompressorIStream), each creating and using the corresponding
stream buffer class from the previous item.
All these allow one to work with RFC 1950 and RFC 1952 compression
formats, respectively known as the zlib and gzip formats.
These classes are *input* streaming classes, which means they can
efficiently handle arbitrary amounts of data without using any disk
space nor increasing amounts of memory, and allow "client code" to pull
exactly as much data as it wants at any given time, resuming later when
it is ready to handle the next chunk.
See comments in simgear/io/iostreams/zlibstream.hxx for more details.
- Rename zfstream.cxx (resp. zfstream.hxx) to gzfstream.cxx (resp.
gzfstream.hxx)
This is because these files only deal with the gzip format (RFC 1952),
while zlib can actually read and write two slightly different formats:
this one and the "ZLIB Compressed Data Format" (RFC 1950). Since I am
going to add std::streambuf and std::istream subclasses able to deal
with both formats (and supporting data sources that are general
std::istream instances, not just files), this renaming will make
things a bit clearer, I hope.
- Add new folder simgear/io/iostreams and move the following files to
this folder:
simgear/misc/gzcontainerfile.cxx
simgear/misc/gzcontainerfile.hxx
simgear/misc/gzfstream.cxx
simgear/misc/gzfstream.hxx
simgear/misc/sgstream.cxx
simgear/misc/sgstream.hxx
simgear/misc/sgstream_test.cxx
- Adapt other files accordingly (mainly #includes and CMakeLists.txt
files).
HTTP/1.0 and HTTP/1.1 allow the reason string to be empty.
Some servers produce empty reason strings on success,
e.g. "HTTP/1.1 200 ", which throws a "bad HTTP response"
exception.
From the specification:
"Reason-Phrase = *<TEXT, excluding CR, LF>"
From notational conventions:
"*(element) allows any number, including zero"
References:
www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
www.w3.org/Protocols/HTTP/1.0/spec.html
www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
- Create "testfile" in a temporary directory (and make sure the temp dir
and the file it contains are both removed when the test program exits).
- Use test macros such as SG_CHECK_EQUAL() instead of by-hand checks and
"return EXIT_FAILURE" statements.
- Use sg_ofstream instead of plain std::ostream. This simplifies things
a tiny bit, because one SGPath instance is enough to create both the
sg_ofstream instance and the sg_gzifstream instance used afterwards to
reread the created file.
- Don't call (sg_)ofstream::close() at the end of the block the instance
is declared in: this is entirely unnecessary, since sg_ofstream
derives from std::ofstream, which is automatically close()d when
destroyed (RAII behavior).
- Add method simgear::Dir::isNull(), analogous to SGPath::isNull().
- Make sure that simgear::Dir::tempDir() returns a null simgear::Dir
instance when creation of the directory failed (so far, this was only
the case on systems where HAVE_MKDTEMP is defined).
- Use simgear::strutils::error_string() instead of strerror() (the
latter is not guaranteed to be thread-safe).
- Make sure <cerrno> is #included, regardless of the platform.
- Add automated tests for isNull(), setRemoveOnDestroy() and tempDir().
This was triggered by the TU154B; probably related to the console error
* "Image loading failed:Warning: reading "fgdata\AI\Aircraft\tu154b\Model" not supported.
This avoids an XML naming clash, and allows both systems to exist in
parallel peacefully. Update the tests to check both the thumbnails
and preview system in parallel with each other.