Browse Source

[2572] added InputSource::getSize() to know the total size of the source.

JINMEI Tatuya 12 years ago
parent
commit
b32cd0ea87

+ 46 - 12
src/lib/dns/master_lexer_inputsource.cc

@@ -15,6 +15,9 @@
 #include <dns/master_lexer_inputsource.h>
 #include <dns/master_lexer.h>
 
+#include <istream>
+#include <iostream>
+#include <cassert>
 #include <cerrno>
 #include <cstring>
 
@@ -31,6 +34,26 @@ createStreamName(const std::istream& input_stream) {
      return (ss.str());
 }
 
+size_t
+getStreamSize(std::istream& is) {
+    is.seekg(0, std::ios_base::end);
+    if (is.fail() || is.bad()) {
+        isc_throw(InputSource::OpenError,
+                  "failed to seek end of input source");
+    }
+    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()) {
+        isc_throw(InputSource::OpenError,
+                  "failed to seek beginning of input source");
+    }
+    assert(len >= 0);
+    return (len);
+}
+
 } // end of unnamed namespace
 
 // Explicit definition of class static constant.  The value is given in the
@@ -43,30 +66,41 @@ InputSource::InputSource(std::istream& input_stream) :
     saved_line_(line_),
     buffer_pos_(0),
     name_(createStreamName(input_stream)),
-    input_(input_stream)
+    input_(input_stream),
+    input_size_(getStreamSize(input_))
 {}
 
-InputSource::InputSource(const char* filename) :
-    at_eof_(false),
-    line_(1),
-    saved_line_(line_),
-    buffer_pos_(0),
-    name_(filename),
-    input_(file_stream_)
-{
+namespace {
+// A helper to initialize InputSource::input_ in the member initialization
+// list.
+std::istream&
+openFileStream(std::ifstream& file_stream, const char* filename) {
     errno = 0;
-    file_stream_.open(filename);
-    if (file_stream_.fail()) {
+    file_stream.open(filename);
+    if (file_stream.fail()) {
         std::string error_txt("Error opening the input source file: ");
         error_txt += filename;
         if (errno != 0) {
             error_txt += "; possible cause: ";
             error_txt += std::strerror(errno);
         }
-        isc_throw(OpenError, error_txt);
+        isc_throw(InputSource::OpenError, error_txt);
     }
+
+    return (file_stream);
+}
 }
 
+InputSource::InputSource(const char* filename) :
+    at_eof_(false),
+    line_(1),
+    saved_line_(line_),
+    buffer_pos_(0),
+    name_(filename),
+    input_(openFileStream(file_stream_, filename)),
+    input_size_(getStreamSize(input_))
+{}
+
 InputSource::~InputSource()
 {
     if (file_stream_.is_open()) {

+ 12 - 0
src/lib/dns/master_lexer_inputsource.h

@@ -83,6 +83,17 @@ public:
         return (name_);
     }
 
+    /// \brief Returns the size of the input source in bytes.
+    ///
+    /// If the input source is a normal file, the return value should be
+    /// equal to the file size at the time of the source is created.
+    /// If the input source is other type of input stream, its the size of
+    /// the data available in the stream at the time of the construction of
+    /// the source.
+    ///
+    /// \throw None.
+    size_t getSize() const { return (input_size_); }
+
     /// \brief Returns if the input source is at end of file.
     bool atEOF() const {
         return (at_eof_);
@@ -146,6 +157,7 @@ private:
     const std::string name_;
     std::ifstream file_stream_;
     std::istream& input_;
+    const size_t input_size_;
 };
 
 } // namespace master_lexer_internal

+ 22 - 1
src/lib/dns/tests/master_lexer_inputsource_unittest.cc

@@ -29,10 +29,13 @@ using namespace isc::dns::master_lexer_internal;
 
 namespace {
 
+const char* const test_input =
+    "Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n";
+
 class InputSourceTest : public ::testing::Test {
 protected:
     InputSourceTest() :
-        str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"),
+        str_(test_input),
         str_length_(strlen(str_)),
         iss_(str_),
         source_(iss_)
@@ -322,4 +325,22 @@ TEST_F(InputSourceTest, saveLine) {
     EXPECT_FALSE(source_.atEOF());
 }
 
+TEST_F(InputSourceTest, getSize) {
+    // A simple case using string stream
+    EXPECT_EQ(strlen(test_input), source_.getSize());
+
+    // Check it works with an empty input
+    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.
+    iss.setstate(std::ios_base::failbit);
+    EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError);
+
+    // Check with input source from file name.  We hardcode the file size
+    // for simplicity.  It won't change too often.
+    EXPECT_EQ(143, InputSource(TEST_DATA_SRCDIR "/masterload.txt").getSize());
+}
+
 } // end namespace