BIND 10 master, updated. 13674dda1cf3f4f16964c7d5fc72559e3d90b8c2 [master] Merge branch 'trac2498'

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Jan 15 10:04:50 UTC 2013


The branch, master has been updated
       via  13674dda1cf3f4f16964c7d5fc72559e3d90b8c2 (commit)
       via  9a0d024c97ba896c577d59db04a0337d3c70221a (commit)
       via  7cbed6378d88f921cf33b12d18d78e56400b4702 (commit)
       via  a3e0f04e9f735501a2ef08b7d3c0de3f22849fcc (commit)
       via  360a5bb6cb72862edbbe9a4cb0074360f1385e21 (commit)
       via  6478f4a1f3d3fb66a7fc25887135bdf3403538bd (commit)
       via  924221ee423612e1389ff98a88ddc127e283aa02 (commit)
       via  7a8402a585b391394949582c14ffb9182c757979 (commit)
       via  82a1d5c34e951687d67a6313fb42d9e75768adbc (commit)
       via  ead15091870f4dbd5a87640be3493e36d9e9da73 (commit)
      from  715a6f61177570c411f2e63f82ae1b2269a654cf (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 13674dda1cf3f4f16964c7d5fc72559e3d90b8c2
Merge: 715a6f6 9a0d024
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Jan 15 10:47:45 2013 +0100

    [master] Merge branch 'trac2498'
    
    Conflicts:
    	src/lib/dns/gen-rdatacode.py.in

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/Makefile.am                         |    1 -
 src/lib/dns/character_string.cc                 |  145 ------------
 src/lib/dns/character_string.h                  |   60 -----
 src/lib/dns/gen-rdatacode.py.in                 |    9 +-
 src/lib/dns/rdata/generic/detail/char_string.cc |   56 +++++
 src/lib/dns/rdata/generic/detail/char_string.h  |   33 +++
 src/lib/dns/rdata/generic/hinfo_13.cc           |  150 +++++++------
 src/lib/dns/rdata/generic/hinfo_13.h            |   38 ++--
 src/lib/dns/rdata/generic/naptr_35.cc           |  273 +++++++++++++----------
 src/lib/dns/rdata/generic/naptr_35.h            |   35 ++-
 src/lib/dns/tests/Makefile.am                   |    1 -
 src/lib/dns/tests/character_string_unittest.cc  |   97 --------
 src/lib/dns/tests/rdata_char_string_unittest.cc |   78 +++++++
 src/lib/dns/tests/rdata_hinfo_unittest.cc       |   25 ++-
 src/lib/dns/tests/rdata_naptr_unittest.cc       |   76 ++++++-
 15 files changed, 527 insertions(+), 550 deletions(-)
 delete mode 100644 src/lib/dns/character_string.cc
 delete mode 100644 src/lib/dns/character_string.h
 delete mode 100644 src/lib/dns/tests/character_string_unittest.cc

-----------------------------------------------------------------------
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 7466b64..286bd8c 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -126,7 +126,6 @@ libb10_dns___la_SOURCES += tsig.h tsig.cc
 libb10_dns___la_SOURCES += tsigerror.h tsigerror.cc
 libb10_dns___la_SOURCES += tsigkey.h tsigkey.cc
 libb10_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
-libb10_dns___la_SOURCES += character_string.h character_string.cc
 libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
 libb10_dns___la_SOURCES += master_loader.h
 libb10_dns___la_SOURCES += rrset_collection_base.h
diff --git a/src/lib/dns/character_string.cc b/src/lib/dns/character_string.cc
deleted file mode 100644
index 8b31948..0000000
--- a/src/lib/dns/character_string.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include "character_string.h"
-#include "rdata.h"
-
-using namespace std;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace dns {
-
-namespace {
-bool isDigit(char c) {
-    return (('0' <= c) && (c <= '9'));
-}
-}
-
-std::string
-characterstr::getNextCharacterString(const std::string& input_str,
-                              std::string::const_iterator& input_iterator,
-                              bool* quoted)
-{
-    string result;
-
-    // If the input string only contains white-spaces, it is an invalid
-    // <character-string>
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText, "Invalid text format, \
-                  <character-string> field is missing.");
-    }
-
-    // Whether the <character-string> is separated with double quotes (")
-    bool quotes_separated = (*input_iterator == '"');
-    // Whether the quotes are pared if the string is quotes separated
-    bool quotes_paired = false;
-
-    if (quotes_separated) {
-        ++input_iterator;
-    }
-
-    while(input_iterator < input_str.end()){
-        // Escaped characters processing
-        if (*input_iterator == '\\') {
-            if (input_iterator + 1 == input_str.end()) {
-                isc_throw(InvalidRdataText, "<character-string> ended \
-                          prematurely.");
-            } else {
-                if (isDigit(*(input_iterator + 1))) {
-                    // \DDD where each D is a digit. It its the octet
-                    // corresponding to the decimal number described by DDD
-                    if (input_iterator + 3 >= input_str.end()) {
-                        isc_throw(InvalidRdataText, "<character-string> ended \
-                                  prematurely.");
-                    } else {
-                        int n = 0;
-                        ++input_iterator;
-                        for (int i = 0; i < 3; ++i) {
-                            if (isDigit(*input_iterator)) {
-                                n = n*10 + (*input_iterator - '0');
-                                ++input_iterator;
-                            } else {
-                                isc_throw(InvalidRdataText, "Illegal decimal \
-                                          escaping series");
-                            }
-                        }
-                        if (n > 255) {
-                            isc_throw(InvalidRdataText, "Illegal octet \
-                                      number");
-                        }
-                        result.push_back(n);
-                        continue;
-                    }
-                } else {
-                    ++input_iterator;
-                    result.push_back(*input_iterator);
-                    ++input_iterator;
-                    continue;
-                }
-            }
-        }
-
-        if (quotes_separated) {
-            // If the <character-string> is seperated with quotes symbol and
-            // another quotes symbol is encountered, it is the end of the
-            // <character-string>
-            if (*input_iterator == '"') {
-                quotes_paired = true;
-                ++input_iterator;
-                // Reach the end of character string
-                break;
-            }
-        } else if (*input_iterator == ' ') {
-            // If the <character-string> is not seperated with quotes symbol,
-            // it is seperated with <space> char
-            break;
-        }
-
-        result.push_back(*input_iterator);
-
-        ++input_iterator;
-    }
-
-    if (result.size() > MAX_CHARSTRING_LEN) {
-        isc_throw(CharStringTooLong, "<character-string> is too long");
-    }
-
-    if (quotes_separated && !quotes_paired) {
-        isc_throw(InvalidRdataText, "The quotes are not paired");
-    }
-
-    if (quoted != NULL) {
-        *quoted = quotes_separated;
-    }
-
-    return (result);
-}
-
-std::string
-characterstr::getNextCharacterString(util::InputBuffer& buffer, size_t len) {
-    uint8_t str_len = buffer.readUint8();
-
-    size_t pos = buffer.getPosition();
-    if (len - pos < str_len) {
-        isc_throw(InvalidRdataLength, "Invalid string length");
-    }
-
-    uint8_t buf[MAX_CHARSTRING_LEN];
-    buffer.readData(buf, str_len);
-    return (string(buf, buf + str_len));
-}
-
-} // end of namespace dns
-} // end of namespace isc
diff --git a/src/lib/dns/character_string.h b/src/lib/dns/character_string.h
deleted file mode 100644
index 0bfa38b..0000000
--- a/src/lib/dns/character_string.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef CHARACTER_STRING_H
-#define CHARACTER_STRING_H
-
-#include <string>
-#include <exceptions/exceptions.h>
-#include <util/buffer.h>
-
-namespace isc {
-namespace dns {
-
-// \brief Some utility functions to extract <character-string> from string
-// or InputBuffer
-//
-// <character-string> is expressed in one or two ways: as a contiguous set
-// of characters without interior spaces, or as a string beginning with a "
-// and ending with a ".  Inside a " delimited string any character can
-// occur, except for a " itself, which must be quoted using \ (back slash).
-// Ref. RFC1035
-
-
-namespace characterstr {
-    /// Get a <character-string> from a string
-    ///
-    /// \param input_str The input string
-    /// \param input_iterator The iterator from which to start extracting,
-    ///        the iterator will be updated to new position after the function
-    ///        is returned
-    /// \param quoted If not \c NULL, returns \c true at this address if
-    ///        the string is quoted, \cfalse otherwise
-    /// \return A std::string that contains the extracted <character-string>
-    std::string getNextCharacterString(const std::string& input_str,
-                                       std::string::const_iterator& input_iterator,
-                                       bool* quoted = NULL);
-
-    /// Get a <character-string> from a input buffer
-    ///
-    /// \param buffer The input buffer
-    /// \param len The input buffer total length
-    /// \return A std::string that contains the extracted <character-string>
-    std::string getNextCharacterString(util::InputBuffer& buffer, size_t len);
-
-} // namespace characterstr
-} // namespace dns
-} // namespace isc
-
-#endif // CHARACTER_STRING_H
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index 88bff6c..fc63d73 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -32,8 +32,13 @@ import sys
 #
 # Example:
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = [('soa', 'generic'), ('txt', 'generic'),
-                           ('aaaa', 'in'), ('spf', 'generic')]
+new_rdata_factory_users = [('aaaa', 'in'),
+                           ('hinfo', 'generic'),
+                           ('naptr', 'generic'),
+                           ('soa', 'generic'),
+                           ('spf', 'generic'),
+                           ('txt', 'generic')
+                          ]
 
 re_typecode = re.compile('([\da-z]+)_(\d+)')
 classcode2txt = {}
diff --git a/src/lib/dns/rdata/generic/detail/char_string.cc b/src/lib/dns/rdata/generic/detail/char_string.cc
index e2857b3..f04877c 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.cc
+++ b/src/lib/dns/rdata/generic/detail/char_string.cc
@@ -14,9 +14,11 @@
 
 #include <exceptions/exceptions.h>
 
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/master_lexer.h>
 #include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 #include <boost/lexical_cast.hpp>
 
@@ -114,6 +116,60 @@ charStringToString(const CharString& char_string) {
     return (s);
 }
 
+int compareCharStrings(const detail::CharString& self,
+                       const detail::CharString& other) {
+    if (self.size() == 0 && other.size() == 0) {
+        return (0);
+    }
+    if (self.size() == 0) {
+        return (-1);
+    }
+    if (other.size() == 0) {
+        return (1);
+    }
+    const size_t self_len = self[0];
+    const size_t other_len = other[0];
+    const size_t cmp_len = std::min(self_len, other_len);
+    const int cmp = memcmp(&self[1], &other[1], cmp_len);
+    if (cmp < 0) {
+        return (-1);
+    } else if (cmp > 0) {
+        return (1);
+    } else if (self_len < other_len) {
+        return (-1);
+    } else if (self_len > other_len) {
+        return (1);
+    } else {
+        return (0);
+    }
+}
+
+size_t
+bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+                   CharString& target) {
+    if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "insufficient data to read character-string length");
+    }
+    const uint8_t len = buffer.readUint8();
+    if (rdata_len < len + 1) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "character string length is too large: " <<
+                  static_cast<int>(len));
+    }
+    if (buffer.getLength() - buffer.getPosition() < len) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "not enough data in buffer to read character-string of len"
+                  << static_cast<int>(len));
+    }
+
+    target.resize(len + 1);
+    target[0] = len;
+    buffer.readData(&target[0] + 1, len);
+
+    return (len + 1);
+}
+
 } // end of detail
 } // end of generic
 } // end of rdata
diff --git a/src/lib/dns/rdata/generic/detail/char_string.h b/src/lib/dns/rdata/generic/detail/char_string.h
index 4a146db..8e3e294 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.h
+++ b/src/lib/dns/rdata/generic/detail/char_string.h
@@ -19,6 +19,7 @@
 
 #include <string>
 #include <vector>
+#include <algorithm>
 #include <stdint.h>
 
 namespace isc {
@@ -66,6 +67,38 @@ void stringToCharString(const MasterToken::StringRegion& str_region,
 /// \return A string representation of \c char_string.
 std::string charStringToString(const CharString& char_string);
 
+/// \brief Compare two CharString objects
+///
+/// \param self The CharString field to compare
+/// \param other The CharString field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+///          1 if \c self would be sorted after \c other
+///          0 if \c self and \c other are equal
+int compareCharStrings(const CharString& self, const CharString& other);
+
+/// \brief Convert a buffer containing a character-string to CharString
+///
+/// This method reads one character-string from the given buffer (in wire
+/// format) and places the result in the given \c CharString object.
+/// Since this is expected to be used in message parsing, the exception it
+/// raises is of that type.
+///
+/// On success, the buffer position is advanced to the end of the char-string,
+/// and the number of bytes read is returned.
+///
+/// \param buffer The buffer to read from.
+/// \param rdata_len The total size of the rr's rdata currently being read
+/// (used for integrity checks in the wire data)
+/// \param target The \c CharString where the result will be stored. Any
+/// existing data in the target will be overwritten.
+/// \throw DNSMessageFORMERR If the available data is not enough to read
+/// the character-string, or if the character-string length is out of bounds
+/// \return The number of bytes read
+size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+                          CharString& target);
+
+
 } // namespace detail
 } // namespace generic
 } // namespace rdata
diff --git a/src/lib/dns/rdata/generic/hinfo_13.cc b/src/lib/dns/rdata/generic/hinfo_13.cc
index 77bfdfd..319ec7d 100644
--- a/src/lib/dns/rdata/generic/hinfo_13.cc
+++ b/src/lib/dns/rdata/generic/hinfo_13.cc
@@ -14,66 +14,105 @@
 
 #include <config.h>
 
-#include <string>
-
-#include <boost/lexical_cast.hpp>
-
 #include <exceptions/exceptions.h>
-
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
-#include <dns/character_string.h>
-#include <util/strutil.h>
+#include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 using namespace std;
-using boost::lexical_cast;
 using namespace isc::util;
 using namespace isc::dns;
-using namespace isc::dns::characterstr;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+class HINFOImpl {
+public:
+    HINFOImpl(const std::string& hinfo_str) {
+        std::istringstream ss(hinfo_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        try {
+            parseHINFOData(lexer);
+            // Should be at end of data now
+            if (lexer.getNextToken(MasterToken::QSTRING, true).getType() !=
+                MasterToken::END_OF_FILE) {
+                isc_throw(InvalidRdataText,
+                          "Invalid HINFO text format: too many fields.");
+            }
+        } catch (const MasterLexer::LexerError& ex) {
+            isc_throw(InvalidRdataText, "Failed to construct HINFO RDATA from "
+                                        << hinfo_str << "': " << ex.what());
+        }
+    }
 
-HINFO::HINFO(const std::string& hinfo_str) {
-    string::const_iterator input_iterator = hinfo_str.begin();
+    HINFOImpl(InputBuffer& buffer, size_t rdata_len) {
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, cpu);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, os);
+        if (rdata_len != 0) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " <<
+                      "HINFO RDATA: bytes left at end: " <<
+                      static_cast<int>(rdata_len));
+        }
+    }
 
-    bool quoted;
-    cpu_ = getNextCharacterString(hinfo_str, input_iterator, &quoted);
+    HINFOImpl(MasterLexer& lexer)
+    {
+        parseHINFOData(lexer);
+    }
 
-    skipLeftSpaces(hinfo_str, input_iterator, quoted);
+private:
+    void
+    parseHINFOData(MasterLexer& lexer) {
+        MasterToken token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), cpu);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), os);
+    }
 
-    os_ = getNextCharacterString(hinfo_str, input_iterator);
+public:
+    detail::CharString cpu;
+    detail::CharString os;
+};
 
-    // Skip whitespace at the end.
-    while (input_iterator < hinfo_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
-    if (input_iterator < hinfo_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid HINFO text format: too many fields.");
-    }
-}
+HINFO::HINFO(const std::string& hinfo_str) : impl_(new HINFOImpl(hinfo_str))
+{}
 
-HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) {
-    cpu_ = getNextCharacterString(buffer, rdata_len);
-    os_ = getNextCharacterString(buffer, rdata_len);
-}
+
+HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) :
+    impl_(new HINFOImpl(buffer, rdata_len))
+{}
 
 HINFO::HINFO(const HINFO& source):
-    Rdata(), cpu_(source.cpu_), os_(source.os_)
+    Rdata(), impl_(new HINFOImpl(*source.impl_))
+{
+}
+
+HINFO::HINFO(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(new HINFOImpl(lexer))
+{}
+
+HINFO&
+HINFO::operator=(const HINFO& source)
 {
+    impl_.reset(new HINFOImpl(*source.impl_));
+    return (*this);
+}
+
+HINFO::~HINFO() {
 }
 
 std::string
 HINFO::toText() const {
     string result;
     result += "\"";
-    result += cpu_;
+    result += detail::charStringToString(impl_->cpu);
     result += "\" \"";
-    result += os_;
+    result += detail::charStringToString(impl_->os);
     result += "\"";
     return (result);
 }
@@ -92,49 +131,28 @@ int
 HINFO::compare(const Rdata& other) const {
     const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other);
 
-    if (cpu_ < other_hinfo.cpu_) {
-        return (-1);
-    } else if (cpu_ > other_hinfo.cpu_) {
-        return (1);
-    }
-
-    if (os_ < other_hinfo.os_) {
-        return (-1);
-    } else if (os_ > other_hinfo.os_) {
-        return (1);
+    const int cmp = compareCharStrings(impl_->cpu, other_hinfo.impl_->cpu);
+    if (cmp != 0) {
+        return (cmp);
     }
-
-    return (0);
+    return (compareCharStrings(impl_->os, other_hinfo.impl_->os));
 }
 
-const std::string&
+const std::string
 HINFO::getCPU() const {
-    return (cpu_);
+    return (detail::charStringToString(impl_->cpu));
 }
 
-const std::string&
+const std::string
 HINFO::getOS() const {
-    return (os_);
+    return (detail::charStringToString(impl_->os));
 }
 
+template <typename T>
 void
-HINFO::skipLeftSpaces(const std::string& input_str,
-                      std::string::const_iterator& input_iterator,
-                      bool optional)
-{
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid HINFO text format: field is missing.");
-    }
-
-    if (!isspace(*input_iterator) && !optional) {
-        isc_throw(InvalidRdataText,
-            "Invalid HINFO text format: fields are not separated by space.");
-    }
-    // Skip white spaces
-    while (input_iterator < input_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
+HINFO::toWireHelper(T& outputer) const {
+    outputer.writeData(&impl_->cpu[0], impl_->cpu.size());
+    outputer.writeData(&impl_->os[0], impl_->os.size());
 }
 
 // END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/hinfo_13.h b/src/lib/dns/rdata/generic/hinfo_13.h
index 5534a7e..60404c9 100644
--- a/src/lib/dns/rdata/generic/hinfo_13.h
+++ b/src/lib/dns/rdata/generic/hinfo_13.h
@@ -17,6 +17,9 @@
 
 #include <string>
 
+#include <boost/scoped_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <util/buffer.h>
@@ -28,6 +31,8 @@
 
 // BEGIN_RDATA_NAMESPACE
 
+class HINFOImpl;
+
 /// \brief \c HINFO class represents the HINFO rdata defined in
 /// RFC1034, RFC1035
 ///
@@ -40,38 +45,21 @@ public:
     // END_COMMON_MEMBERS
 
     // HINFO specific methods
-    const std::string& getCPU() const;
-    const std::string& getOS() const;
+    ~HINFO();
 
-private:
-    /// Skip the left whitespaces of the input string
-    ///
-    /// If \c optional argument is \c true and no spaces occur at the
-    /// current location, then nothing happens. If \c optional is
-    /// \c false and no spaces occur at the current location, then
-    /// the \c InvalidRdataText exception is thrown.
-    ///
-    /// \param input_str The input string
-    /// \param input_iterator From which the skipping started
-    /// \param optional If true, the spaces are optionally skipped.
-    void skipLeftSpaces(const std::string& input_str,
-                        std::string::const_iterator& input_iterator,
-                        bool optional);
+    HINFO& operator=(const HINFO&);
+
+    const std::string getCPU() const;
+    const std::string getOS() const;
 
+private:
     /// Helper template function for toWire()
     ///
     /// \param outputer Where to write data in
     template <typename T>
-    void toWireHelper(T& outputer) const {
-        outputer.writeUint8(cpu_.size());
-        outputer.writeData(cpu_.c_str(), cpu_.size());
-
-        outputer.writeUint8(os_.size());
-        outputer.writeData(os_.c_str(), os_.size());
-    }
+    void toWireHelper(T& outputer) const;
 
-    std::string cpu_;
-    std::string os_;
+    boost::scoped_ptr<HINFOImpl> impl_;
 };
 
 
diff --git a/src/lib/dns/rdata/generic/naptr_35.cc b/src/lib/dns/rdata/generic/naptr_35.cc
index 0958eff..78bf472 100644
--- a/src/lib/dns/rdata/generic/naptr_35.cc
+++ b/src/lib/dns/rdata/generic/naptr_35.cc
@@ -14,119 +14,147 @@
 
 #include <config.h>
 
-#include <string>
-
-#include <boost/lexical_cast.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/character_string.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/char_string.h>
+#include <exceptions/exceptions.h>
+
+#include <string>
+#include <boost/lexical_cast.hpp>
 
 using namespace std;
 using boost::lexical_cast;
 using namespace isc::util;
 using namespace isc::dns;
-using namespace isc::dns::characterstr;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
-namespace {
-/// Skip the left whitespaces of the input string
-///
-/// \param input_str The input string
-/// \param input_iterator From which the skipping started
-void
-skipLeftSpaces(const std::string& input_str,
-               std::string::const_iterator& input_iterator)
-{
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid NAPTR text format, field is missing.");
+class NAPTRImpl {
+public:
+    NAPTRImpl() : replacement(".") {}
+
+    NAPTRImpl(InputBuffer& buffer, size_t rdata_len) : replacement(".") {
+        if (rdata_len < 4 || buffer.getLength() - buffer.getPosition() < 4) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing "
+                      "NAPTR RDATA wire format: insufficient length ");
+        }
+        order = buffer.readUint16();
+        preference = buffer.readUint16();
+        rdata_len -= 4;
+
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, flags);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, services);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, regexp);
+        replacement = Name(buffer);
+        if (rdata_len < 1) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing "
+                      "NAPTR RDATA wire format: missing replacement name");
+        }
+        rdata_len -= replacement.getLength();
+
+        if (rdata_len != 0) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " <<
+                      "NAPTR RDATA: bytes left at end: " <<
+                      static_cast<int>(rdata_len));
+        }
     }
 
-    if (!isspace(*input_iterator)) {
-        isc_throw(InvalidRdataText,
-            "Invalid NAPTR text format, fields are not separated by space.");
+    NAPTRImpl(const std::string& naptr_str) : replacement(".") {
+        std::istringstream ss(naptr_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        try {
+            parseNAPTRData(lexer);
+            // Should be at end of data now
+            if (lexer.getNextToken(MasterToken::QSTRING, true).getType() !=
+                MasterToken::END_OF_FILE) {
+                isc_throw(InvalidRdataText,
+                          "Invalid NAPTR text format: too many fields.");
+            }
+        } catch (const MasterLexer::LexerError& ex) {
+            isc_throw(InvalidRdataText, "Failed to construct NAPTR RDATA from "
+                                        << naptr_str << "': " << ex.what());
+        }
     }
-    // Skip white spaces
-    while (input_iterator < input_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
-}
 
-} // Anonymous namespace
+    NAPTRImpl(MasterLexer& lexer) : replacement(".")
+    {
+        parseNAPTRData(lexer);
+    }
 
-NAPTR::NAPTR(InputBuffer& buffer, size_t len):
-    replacement_(".")
-{
-    order_ = buffer.readUint16();
-    preference_ = buffer.readUint16();
+private:
+    void
+    parseNAPTRData(MasterLexer& lexer) {
+        MasterToken token = lexer.getNextToken(MasterToken::NUMBER);
+        if (token.getNumber() > 65535) {
+            isc_throw(InvalidRdataText,
+                      "Invalid NAPTR text format: order out of range: "
+                      << token.getNumber());
+        }
+        order = token.getNumber();
+        token = lexer.getNextToken(MasterToken::NUMBER);
+        if (token.getNumber() > 65535) {
+            isc_throw(InvalidRdataText,
+                      "Invalid NAPTR text format: preference out of range: "
+                      << token.getNumber());
+        }
+        preference = token.getNumber();
+
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), flags);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), services);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), regexp);
+
+        token = lexer.getNextToken(MasterToken::STRING);
+        replacement = Name(token.getString());
+    }
 
-    flags_ = getNextCharacterString(buffer, len);
-    services_ = getNextCharacterString(buffer, len);
-    regexp_ = getNextCharacterString(buffer, len);
-    replacement_ = Name(buffer);
-}
 
-NAPTR::NAPTR(const std::string& naptr_str):
-    replacement_(".")
-{
-    istringstream iss(naptr_str);
+public:
     uint16_t order;
     uint16_t preference;
-
-    iss >> order >> preference;
-
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid NAPTR text format");
-    }
-
-    order_ = order;
-    preference_ = preference;
-
-    string::const_iterator input_iterator = naptr_str.begin() + iss.tellg();
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    flags_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    services_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    regexp_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    if (input_iterator < naptr_str.end()) {
-        string replacementStr(input_iterator, naptr_str.end());
-
-        replacement_ = Name(replacementStr);
-    } else {
-        isc_throw(InvalidRdataText,
-                  "Invalid NAPTR text format, replacement field is missing");
-    }
+    detail::CharString flags;
+    detail::CharString services;
+    detail::CharString regexp;
+    Name replacement;
+};
+
+NAPTR::NAPTR(InputBuffer& buffer, size_t rdata_len) :
+    impl_(new NAPTRImpl(buffer, rdata_len))
+{}
+
+NAPTR::NAPTR(const std::string& naptr_str) : impl_(new NAPTRImpl(naptr_str))
+{}
+
+NAPTR::NAPTR(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(new NAPTRImpl(lexer))
+{}
+
+NAPTR::NAPTR(const NAPTR& naptr) :  Rdata(),
+                                    impl_(new NAPTRImpl(*naptr.impl_))
+{}
+
+NAPTR&
+NAPTR::operator=(const NAPTR& source)
+{
+    impl_.reset(new NAPTRImpl(*source.impl_));
+    return (*this);
 }
 
-NAPTR::NAPTR(const NAPTR& naptr):
-    Rdata(), order_(naptr.order_), preference_(naptr.preference_),
-    flags_(naptr.flags_), services_(naptr.services_), regexp_(naptr.regexp_),
-    replacement_(naptr.replacement_)
-{
+NAPTR::~NAPTR() {
 }
 
 void
 NAPTR::toWire(OutputBuffer& buffer) const {
     toWireHelper(buffer);
-    replacement_.toWire(buffer);
-
+    impl_->replacement.toWire(buffer);
 }
 
 void
@@ -134,23 +162,23 @@ NAPTR::toWire(AbstractMessageRenderer& renderer) const {
     toWireHelper(renderer);
     // Type NAPTR is not "well-known", and name compression must be disabled
     // per RFC3597.
-    renderer.writeName(replacement_, false);
+    renderer.writeName(impl_->replacement, false);
 }
 
 string
 NAPTR::toText() const {
     string result;
-    result += lexical_cast<string>(order_);
+    result += lexical_cast<string>(impl_->order);
     result += " ";
-    result += lexical_cast<string>(preference_);
+    result += lexical_cast<string>(impl_->preference);
     result += " \"";
-    result += flags_;
+    result += detail::charStringToString(impl_->flags);
     result += "\" \"";
-    result += services_;
+    result += detail::charStringToString(impl_->services);
     result += "\" \"";
-    result += regexp_;
+    result += detail::charStringToString(impl_->regexp);
     result += "\" ";
-    result += replacement_.toText();
+    result += impl_->replacement.toText();
     return (result);
 }
 
@@ -158,67 +186,78 @@ int
 NAPTR::compare(const Rdata& other) const {
     const NAPTR other_naptr = dynamic_cast<const NAPTR&>(other);
 
-    if (order_ < other_naptr.order_) {
+    if (impl_->order < other_naptr.impl_->order) {
         return (-1);
-    } else if (order_ > other_naptr.order_) {
+    } else if (impl_->order > other_naptr.impl_->order) {
         return (1);
     }
 
-    if (preference_ < other_naptr.preference_) {
+    if (impl_->preference < other_naptr.impl_->preference) {
         return (-1);
-    } else if (preference_ > other_naptr.preference_) {
+    } else if (impl_->preference > other_naptr.impl_->preference) {
         return (1);
     }
 
-    if (flags_ < other_naptr.flags_) {
-        return (-1);
-    } else if (flags_ > other_naptr.flags_) {
-        return (1);
+    const int fcmp = detail::compareCharStrings(impl_->flags,
+                                                other_naptr.impl_->flags);
+    if (fcmp != 0) {
+        return (fcmp);
     }
 
-    if (services_ < other_naptr.services_) {
-        return (-1);
-    } else if (services_ > other_naptr.services_) {
-        return (1);
+    const int scmp = detail::compareCharStrings(impl_->services,
+                                                other_naptr.impl_->services);
+    if (scmp != 0) {
+        return (scmp);
     }
 
-    if (regexp_ < other_naptr.regexp_) {
-        return (-1);
-    } else if (regexp_ > other_naptr.regexp_) {
-        return (1);
+    const int rcmp = detail::compareCharStrings(impl_->regexp,
+                                                other_naptr.impl_->regexp);
+    if (rcmp != 0) {
+        return (rcmp);
     }
 
-    return (compareNames(replacement_, other_naptr.replacement_));
+    return (compareNames(impl_->replacement, other_naptr.impl_->replacement));
 }
 
 uint16_t
 NAPTR::getOrder() const {
-    return (order_);
+    return (impl_->order);
 }
 
 uint16_t
 NAPTR::getPreference() const {
-    return (preference_);
+    return (impl_->preference);
 }
 
-const std::string&
+const std::string
 NAPTR::getFlags() const {
-    return (flags_);
+    return (detail::charStringToString(impl_->flags));
 }
 
-const std::string&
+const std::string
 NAPTR::getServices() const {
-    return (services_);
+    return (detail::charStringToString(impl_->services));
 }
 
-const std::string&
+const std::string
 NAPTR::getRegexp() const {
-    return (regexp_);
+    return (detail::charStringToString(impl_->regexp));
 }
 
 const Name&
 NAPTR::getReplacement() const {
-    return (replacement_);
+    return (impl_->replacement);
+}
+
+template <typename T>
+void
+NAPTR::toWireHelper(T& outputer) const {
+    outputer.writeUint16(impl_->order);
+    outputer.writeUint16(impl_->preference);
+
+    outputer.writeData(&impl_->flags[0], impl_->flags.size());
+    outputer.writeData(&impl_->services[0], impl_->services.size());
+    outputer.writeData(&impl_->regexp[0], impl_->regexp.size());
 }
 
 // END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/naptr_35.h b/src/lib/dns/rdata/generic/naptr_35.h
index c82ef87..a2e2cae 100644
--- a/src/lib/dns/rdata/generic/naptr_35.h
+++ b/src/lib/dns/rdata/generic/naptr_35.h
@@ -16,6 +16,8 @@
 
 #include <string>
 
+#include <boost/scoped_ptr.hpp>
+
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <util/buffer.h>
@@ -27,6 +29,8 @@
 
 // BEGIN_RDATA_NAMESPACE
 
+class NAPTRImpl;
+
 /// \brief \c NAPTR class represents the NAPTR rdata defined in
 /// RFC2915, RFC2168 and RFC3403
 ///
@@ -39,37 +43,24 @@ public:
     // END_COMMON_MEMBERS
 
     // NAPTR specific methods
+    ~NAPTR();
+
+    NAPTR& operator=(const NAPTR& source);
+
     uint16_t getOrder() const;
     uint16_t getPreference() const;
-    const std::string& getFlags() const;
-    const std::string& getServices() const;
-    const std::string& getRegexp() const;
+    const std::string getFlags() const;
+    const std::string getServices() const;
+    const std::string getRegexp() const;
     const Name& getReplacement() const;
 private:
     /// Helper template function for toWire()
     ///
     /// \param outputer Where to write data in
     template <typename T>
-    void toWireHelper(T& outputer) const {
-        outputer.writeUint16(order_);
-        outputer.writeUint16(preference_);
-
-        outputer.writeUint8(flags_.size());
-        outputer.writeData(flags_.c_str(), flags_.size());
-
-        outputer.writeUint8(services_.size());
-        outputer.writeData(services_.c_str(), services_.size());
-
-        outputer.writeUint8(regexp_.size());
-        outputer.writeData(regexp_.c_str(), regexp_.size());
-    }
+    void toWireHelper(T& outputer) const;
 
-    uint16_t order_;
-    uint16_t preference_;
-    std::string flags_;
-    std::string services_;
-    std::string regexp_;
-    Name replacement_;
+    boost::scoped_ptr<NAPTRImpl> impl_;
 };
 
 // END_RDATA_NAMESPACE
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index 8d32b42..5029681 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -73,7 +73,6 @@ run_unittests_SOURCES += tsig_unittest.cc
 run_unittests_SOURCES += tsigerror_unittest.cc
 run_unittests_SOURCES += tsigkey_unittest.cc
 run_unittests_SOURCES += tsigrecord_unittest.cc
-run_unittests_SOURCES += character_string_unittest.cc
 run_unittests_SOURCES += master_loader_callbacks_test.cc
 run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += zone_checker_unittest.cc
diff --git a/src/lib/dns/tests/character_string_unittest.cc b/src/lib/dns/tests/character_string_unittest.cc
deleted file mode 100644
index e8f5884..0000000
--- a/src/lib/dns/tests/character_string_unittest.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-
-#include <gtest/gtest.h>
-
-#include <dns/rdata.h>
-#include <dns/tests/unittest_util.h>
-#include <dns/character_string.h>
-
-using isc::UnitTestUtil;
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-using namespace isc::dns::characterstr;
-using namespace isc::dns::rdata;
-
-namespace {
-
-class CharacterString {
-public:
-    CharacterString(const string& str){
-        string::const_iterator it = str.begin();
-        characterStr_ = getNextCharacterString(str, it, &is_quoted_);
-    }
-    const string& str() const { return characterStr_; }
-    bool quoted() const { return (is_quoted_); }
-private:
-    string characterStr_;
-    bool is_quoted_;
-};
-
-TEST(CharacterStringTest, testNormalCase) {
-    CharacterString cstr1("foo");
-    EXPECT_EQ(string("foo"), cstr1.str());
-
-    // Test <character-string> that separated by space
-    CharacterString cstr2("foo bar");
-    EXPECT_EQ(string("foo"), cstr2.str());
-    EXPECT_FALSE(cstr2.quoted());
-
-    // Test <character-string> that separated by quotes
-    CharacterString cstr3("\"foo bar\"");
-    EXPECT_EQ(string("foo bar"), cstr3.str());
-    EXPECT_TRUE(cstr3.quoted());
-
-    // Test <character-string> that not separate by quotes but ended with quotes
-    CharacterString cstr4("foo\"");
-    EXPECT_EQ(string("foo\""), cstr4.str());
-    EXPECT_FALSE(cstr4.quoted());
-}
-
-TEST(CharacterStringTest, testBadCase) {
-    // The <character-string> that started with quotes should also be ended
-    // with quotes
-    EXPECT_THROW(CharacterString cstr("\"foo"), InvalidRdataText);
-
-    // The string length cannot exceed 255 characters
-    string str;
-    for (int i = 0; i < 257; ++i) {
-        str += 'A';
-    }
-    EXPECT_THROW(CharacterString cstr(str), CharStringTooLong);
-}
-
-TEST(CharacterStringTest, testEscapeCharacter) {
-    CharacterString cstr1("foo\\bar");
-    EXPECT_EQ(string("foobar"), cstr1.str());
-
-    CharacterString cstr2("foo\\\\bar");
-    EXPECT_EQ(string("foo\\bar"), cstr2.str());
-
-    CharacterString cstr3("fo\\111bar");
-    EXPECT_EQ(string("foobar"), cstr3.str());
-
-    CharacterString cstr4("fo\\1112bar");
-    EXPECT_EQ(string("foo2bar"), cstr4.str());
-
-    // There must be at least 3 digits followed by '\'
-    EXPECT_THROW(CharacterString cstr("foo\\98ar"), InvalidRdataText);
-    EXPECT_THROW(CharacterString cstr("foo\\9ar"), InvalidRdataText);
-    EXPECT_THROW(CharacterString cstr("foo\\98"), InvalidRdataText);
-}
-
-} // namespace
diff --git a/src/lib/dns/tests/rdata_char_string_unittest.cc b/src/lib/dns/tests/rdata_char_string_unittest.cc
index 44bc979..3059669 100644
--- a/src/lib/dns/tests/rdata_char_string_unittest.cc
+++ b/src/lib/dns/tests/rdata_char_string_unittest.cc
@@ -14,8 +14,10 @@
 
 #include <util/unittests/wiredata.h>
 
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 #include <gtest/gtest.h>
 
@@ -25,8 +27,10 @@
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using isc::dns::rdata::generic::detail::CharString;
+using isc::dns::rdata::generic::detail::bufferToCharString;
 using isc::dns::rdata::generic::detail::stringToCharString;
 using isc::dns::rdata::generic::detail::charStringToString;
+using isc::dns::rdata::generic::detail::compareCharStrings;
 using isc::util::unittests::matchWireData;
 
 namespace {
@@ -171,4 +175,78 @@ TEST_F(CharStringTest, charStringToString) {
     }
 }
 
+TEST_F(CharStringTest, bufferToCharString) {
+    const size_t chstr_size = sizeof(test_charstr);
+    isc::util::InputBuffer buf(test_charstr, chstr_size);
+    size_t read = bufferToCharString(buf, chstr_size, chstr);
+
+    EXPECT_EQ(chstr_size, read);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+}
+
+TEST_F(CharStringTest, bufferToCharString_bad) {
+    const size_t chstr_size = sizeof(test_charstr);
+    isc::util::InputBuffer buf(test_charstr, chstr_size);
+    // Set valid data in both so we can make sure the charstr is not
+    // modified
+    bufferToCharString(buf, chstr_size, chstr);
+    ASSERT_EQ("Test String", charStringToString(chstr));
+
+    // Should be at end of buffer now, so it should fail
+    EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+    // reset and try to read with too low rdata_len
+    buf.setPosition(0);
+    EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+    // set internal charstring len too high
+    const uint8_t test_charstr_err[] = {
+        sizeof("Test String") + 1,
+        'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+    };
+    buf = isc::util::InputBuffer(test_charstr_err, sizeof(test_charstr_err));
+    EXPECT_THROW(bufferToCharString(buf, chstr_size, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+}
+
+
+
+TEST_F(CharStringTest, compareCharString) {
+    CharString charstr;
+    CharString charstr2;
+    CharString charstr_small1;
+    CharString charstr_small2;
+    CharString charstr_large1;
+    CharString charstr_large2;
+    CharString charstr_empty;
+
+    stringToCharString(createStringRegion("test string"), charstr);
+    stringToCharString(createStringRegion("test string"), charstr2);
+    stringToCharString(createStringRegion("test strin"), charstr_small1);
+    stringToCharString(createStringRegion("test strina"), charstr_small2);
+    stringToCharString(createStringRegion("test stringa"), charstr_large1);
+    stringToCharString(createStringRegion("test strinz"), charstr_large2);
+
+    EXPECT_EQ(0, compareCharStrings(charstr, charstr2));
+    EXPECT_EQ(0, compareCharStrings(charstr2, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_small1));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_small2));
+    EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large1));
+    EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large2));
+    EXPECT_EQ(-1, compareCharStrings(charstr_small1, charstr));
+    EXPECT_EQ(-1, compareCharStrings(charstr_small2, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr_large1, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr_large2, charstr));
+
+    EXPECT_EQ(-1, compareCharStrings(charstr_empty, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_empty));
+    EXPECT_EQ(0, compareCharStrings(charstr_empty, charstr_empty));
+}
+
 } // unnamed namespace
diff --git a/src/lib/dns/tests/rdata_hinfo_unittest.cc b/src/lib/dns/tests/rdata_hinfo_unittest.cc
index f592066..7be2cb6 100644
--- a/src/lib/dns/tests/rdata_hinfo_unittest.cc
+++ b/src/lib/dns/tests/rdata_hinfo_unittest.cc
@@ -51,10 +51,9 @@ TEST_F(Rdata_HINFO_Test, createFromText) {
     HINFO hinfo(hinfo_str);
     EXPECT_EQ(string("Pentium"), hinfo.getCPU());
     EXPECT_EQ(string("Linux"), hinfo.getOS());
-
     // Test the text with double quotes in the middle of string
     HINFO hinfo1(hinfo_str1);
-    EXPECT_EQ(string("Pen\"tium"), hinfo1.getCPU());
+    EXPECT_EQ(string("Pen\\\"tium"), hinfo1.getCPU());
 }
 
 TEST_F(Rdata_HINFO_Test, badText) {
@@ -96,11 +95,20 @@ TEST_F(Rdata_HINFO_Test, createFromLexer) {
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::HINFO(), RRClass::IN(),
                                              "\"Pentium\" \"Linux\" "
                                              "\"Computer\""));
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::HINFO(), RRClass::IN(),
+                                             "\"Pentium\""));
 }
 
 TEST_F(Rdata_HINFO_Test, toText) {
     HINFO hinfo(hinfo_str);
     EXPECT_EQ(hinfo_str, hinfo.toText());
+
+    // will add quotes even if they were not in the original input
+    EXPECT_EQ("\"a\" \"b\"", HINFO("a b").toText());
+    // will not add additional quotes
+    EXPECT_EQ("\"a\" \"b\"", HINFO("\"a\" \"b\"").toText());
+    // And make sure escaped quotes and spaces are left intact
+    EXPECT_EQ("\"a\\\"\" \"b c\"", HINFO("\"a\\\"\" \"b c\"").toText());
 }
 
 TEST_F(Rdata_HINFO_Test, toWire) {
@@ -135,4 +143,17 @@ TEST_F(Rdata_HINFO_Test, compare) {
     EXPECT_EQ(-1, hinfo.compare(HINFO(hinfo_str_large2)));
 }
 
+// Copy/assign test
+TEST_F(Rdata_HINFO_Test, copy) {
+    HINFO hinfo(hinfo_str);
+    HINFO hinfo2(hinfo);
+    HINFO hinfo3 = hinfo;
+
+    EXPECT_EQ(0, hinfo.compare(hinfo2));
+    EXPECT_EQ(0, hinfo.compare(hinfo3));
+
+    hinfo3 = hinfo;
+    EXPECT_EQ(0, hinfo.compare(hinfo3));
+}
+
 }
diff --git a/src/lib/dns/tests/rdata_naptr_unittest.cc b/src/lib/dns/tests/rdata_naptr_unittest.cc
index fed98cb..d828e73 100644
--- a/src/lib/dns/tests/rdata_naptr_unittest.cc
+++ b/src/lib/dns/tests/rdata_naptr_unittest.cc
@@ -99,10 +99,12 @@ TEST_F(Rdata_NAPTR_Test, badText) {
     // Order or preference cannot be missed
     EXPECT_THROW(const NAPTR naptr("10 \"S\" SIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
-    // Fields must be seperated by spaces
+    // Unquoted fields must be seperated by spaces
     EXPECT_THROW(const NAPTR naptr("100 10S SIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
-    EXPECT_THROW(const NAPTR naptr("100 10 \"S\"\"SIP\" \"\" _sip._udp.example.com."),
+    EXPECT_THROW(const NAPTR naptr("10010 \"S\" \"SIP\" \"\" _sip._udp.example.com."),
+                 InvalidRdataText);
+    EXPECT_THROW(const NAPTR naptr("100 10 SSIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
     // Field cannot be missing
     EXPECT_THROW(const NAPTR naptr("100 10 \"S\""), InvalidRdataText);
@@ -128,6 +130,26 @@ TEST_F(Rdata_NAPTR_Test, createFromWire) {
     EXPECT_EQ(Name("_sip._udp.example.com."), naptr.getReplacement());
 }
 
+TEST_F(Rdata_NAPTR_Test, createFromWireTooLongDataLen) {
+    static uint8_t naptr_rdata_long[] = {
+    0x00,0x0a,0x00,0x64,0x01,0x53,0x07,0x53,0x49,0x50,0x2b,0x44,0x32,0x55,
+    0x00,0x04,0x5f,0x73,0x69,0x70,0x04,0x5f,0x75,0x64,0x70,0x07,0x65,0x78,
+    0x61,0x6d,0x70,0x6c,0x65,0x03,0x63,0x6f,0x6d,0x00,0xff,0xff,0xff,0xff};
+    InputBuffer input_buffer(naptr_rdata_long, sizeof(naptr_rdata_long));
+    EXPECT_THROW(NAPTR naptr(input_buffer, sizeof(naptr_rdata_long)),
+                 isc::dns::DNSMessageFORMERR);
+}
+
+TEST_F(Rdata_NAPTR_Test, createFromWireTooShortDataLen) {
+    // missing data (just set rdata_len too low)
+    for (size_t i = 0; i < sizeof(naptr_rdata); ++i) {
+        // Just use existing correct buffer but set rdata_len too low
+        InputBuffer input_buffer(naptr_rdata, sizeof(naptr_rdata));
+        EXPECT_THROW(NAPTR naptr(input_buffer, i),
+                     isc::dns::DNSMessageFORMERR);
+    }
+}
+
 TEST_F(Rdata_NAPTR_Test, createFromLexer) {
     const NAPTR rdata_naptr(naptr_str);
 
@@ -161,6 +183,14 @@ TEST_F(Rdata_NAPTR_Test, toWireRenderer) {
 TEST_F(Rdata_NAPTR_Test, toText) {
     NAPTR naptr(naptr_str);
     EXPECT_EQ(naptr_str, naptr.toText());
+
+    // will add quotes even if they were not in the original input
+    EXPECT_EQ("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.",
+              NAPTR("10 100 S SIP+D2U .* _sip._udp.example.com.").toText());
+    // will not add additional quotes
+    EXPECT_EQ("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.",
+              NAPTR("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.")
+                .toText());
 }
 
 TEST_F(Rdata_NAPTR_Test, compare) {
@@ -177,16 +207,38 @@ TEST_F(Rdata_NAPTR_Test, compare) {
     NAPTR naptr_large5(naptr_str_large5);
 
     EXPECT_EQ(0, naptr.compare(NAPTR(naptr_str)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small1)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small2)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small3)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small4)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small5)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large1)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large2)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large3)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large4)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large5)));
+    EXPECT_EQ(1, naptr.compare(naptr_small1));
+    EXPECT_EQ(1, naptr.compare(naptr_small2));
+    EXPECT_EQ(1, naptr.compare(naptr_small3));
+    EXPECT_EQ(1, naptr.compare(naptr_small4));
+    EXPECT_EQ(1, naptr.compare(naptr_small5));
+    EXPECT_EQ(-1, naptr.compare(naptr_large1));
+    EXPECT_EQ(-1, naptr.compare(naptr_large2));
+    EXPECT_EQ(-1, naptr.compare(naptr_large3));
+    EXPECT_EQ(-1, naptr.compare(naptr_large4));
+    EXPECT_EQ(-1, naptr.compare(naptr_large5));
+    EXPECT_EQ(-1, naptr_small1.compare(naptr));
+    EXPECT_EQ(-1, naptr_small2.compare(naptr));
+    EXPECT_EQ(-1, naptr_small3.compare(naptr));
+    EXPECT_EQ(-1, naptr_small4.compare(naptr));
+    EXPECT_EQ(-1, naptr_small5.compare(naptr));
+    EXPECT_EQ(1, naptr_large1.compare(naptr));
+    EXPECT_EQ(1, naptr_large2.compare(naptr));
+    EXPECT_EQ(1, naptr_large3.compare(naptr));
+    EXPECT_EQ(1, naptr_large4.compare(naptr));
+    EXPECT_EQ(1, naptr_large5.compare(naptr));
+}
+
+TEST_F(Rdata_NAPTR_Test, copy) {
+    NAPTR naptr(naptr_str);
+    NAPTR naptr2(naptr);
+    NAPTR naptr3 = naptr;
+
+    EXPECT_EQ(0, naptr.compare(naptr2));
+    EXPECT_EQ(0, naptr.compare(naptr3));
+
+    naptr3 = naptr;
+    EXPECT_EQ(0, naptr.compare(naptr3));
 }
 
 }



More information about the bind10-changes mailing list