#include <bitset>
#include <cassert>
+#include <limits>
#include <string>
#include <vector>
namespace isc {
namespace dns {
+// The definition of SOURCE_SIZE_UNKNOWN. Note that we initialize it using
+// a method of another library. Technically, this could trigger a static
+// initialization fiasco. But in this particular usage it's very unlikely
+// to happen because this value is expected to be used only as a return
+// value of a MasterLexer's method, and its constructor needs definitions
+// here.
+const size_t MasterLexer::SOURCE_SIZE_UNKNOWN =
+ std::numeric_limits<size_t>::max();
+
namespace {
typedef boost::shared_ptr<master_lexer_internal::InputSource> InputSourcePtr;
} // end unnamed namespace
const MasterToken token_;
};
+ /// \brief Special value for input source size meaning "unknown".
+ ///
+ /// This constant value will be used as a return value of
+ /// \c getTotalSourceSize() when the size of one of the pushed sources
+ /// is unknown. Note that this value itself is a valid integer in the
+ /// range of the type, so there's still a small possibility of
+ /// ambiguity. In practice, however, the value should be sufficiently
+ /// large that should eliminate the possibility.
+ static const size_t SOURCE_SIZE_UNKNOWN;
+
/// \brief Options for getNextToken.
///
/// A compound option, indicating multiple options are set, can be
/// the size of the data available in the stream at the time of the
/// source is pushed.
///
+ /// In some special cases, it's possible that the size of the file or
+ /// stream is unknown. It happens, for example, if the standard input
+ /// is associated with a pipe from the output of another process and it's
+ /// specified as an input source. If the size of some of the pushed
+ /// pushed source is unknown, this method returns SOURCE_SIZE_UNKNOWN.
+ ///
/// If there is no source pushed in the lexer, it returns 0.
///
/// \throw None
size_t
getStreamSize(std::istream& is) {
is.seekg(0, std::ios_base::end);
- if (is.fail() || is.bad()) {
+ if (is.bad()) {
+ // This means the istream has an integrity error. It doesn't make
+ // sense to continue from this point, so we treat it as a fatal error.
isc_throw(InputSource::OpenError,
"failed to seek end of input source");
+ } else if (is.fail()) {
+ // This is an error specific to seekg(). There can be several
+ // reasons, but the most likely cause in this context is that the
+ // stream is associated with a special type of file such as a pipe.
+ // In this case, it's more likely that other main operations of
+ // the input source work fine, so we continue with just setting
+ // the stream size to "unknown".
+ is.clear(); // clear this error not to confuse later ops.
+ return (MasterLexer::SOURCE_SIZE_UNKNOWN);
}
const std::streampos len = is.tellg();
if (len == -1) {
isc_throw(InputSource::OpenError, "failed to get input size");
}
is.seekg(0, std::ios::beg);
- if (is.fail() || is.bad()) {
+ if (is.fail()) {
isc_throw(InputSource::OpenError,
"failed to seek beginning of input source");
}
/// \brief Returns the size of the input source in bytes.
///
+ /// If the size is unknown, it returns \c MasterLexer::SOURCE_SIZE_UNKNOWN.
+ ///
/// See \c MasterLexer::getTotalSourceSize() for the definition of
- /// the size of sources.
+ /// the size of sources and for when the size can be unknown.
///
/// \throw None
size_t getSize() const { return (input_size_); }
// PERFORMANCE OF THIS SOFTWARE.
#include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer.h>
#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
istringstream iss("");
EXPECT_EQ(0, InputSource(iss).getSize());
- // Pretend there's an error in the stream. The constructor will throw
- // in the attempt of getting the input size.
+ // Pretend there's an error in seeking in the stream. It will be
+ // considered a seek specific error, and getSize() returns "unknown".
iss.setstate(std::ios_base::failbit);
+ EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, InputSource(iss).getSize());
+ // The fail bit should have been cleared.
+ EXPECT_FALSE(iss.fail());
+
+ // Pretend there's a *critical* error in the stream. The constructor will
+ // throw in the attempt of getting the input size.
+ iss.setstate(std::ios_base::badbit);
EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError);
// Check with input source from file name. We hardcode the file size