BIND 10 master, updated. 42073d9d8c264a33ca883c9e80310cb91de706c6 [master] ChangeLog entry for trac2522 merge

BIND 10 source code commits bind10-changes at lists.isc.org
Mon May 27 03:14:51 UTC 2013


The branch, master has been updated
       via  42073d9d8c264a33ca883c9e80310cb91de706c6 (commit)
       via  ea97070cf6b41299351fc29af66fa39c6465d56a (commit)
       via  64bc0886402d587b65343fe6faecf35ed59eb029 (commit)
       via  8ed9ddfe7f17d01d29cdaed8ee800487413e8632 (commit)
       via  e08a21c3bdc637a447d68da727fa3f4cb6a26112 (commit)
       via  7e0b47d099a071d438c45e7cde177d89a0f3151e (commit)
       via  87a710de67996ae01dcee1c2e05f09c9c392f82d (commit)
       via  7acdd8d445081e1a4c70ed58298367a96ccb55fd (commit)
       via  c39edd26a68da49eb507b3d842b8929a57f2710b (commit)
       via  a2b82fc102f6a4f987bf9ba59b05a336dfde8ac4 (commit)
       via  0b2800af6eedeba3b71108765fd4e04195c0a4ad (commit)
       via  ea07789d058ca92c5617c2aca304fb8ad8c69c18 (commit)
       via  1e1f87c3540b2f9de576a0267c694e8ff19a1db1 (commit)
       via  16ad2c551b5a2e90d0931644a07caf02b254fae7 (commit)
       via  29b82a61f1826a72597adcd7ff38e153a135379e (commit)
       via  dc25eefe48a9c76b9889dde024ce8e88ee1eb363 (commit)
       via  fcca4e8c09253602530fe66a04e8e9b71bbf4739 (commit)
       via  592db047a5a82c5af9e837dc2fc9a9df102af8ed (commit)
       via  c7e380374b96d23f682e81a8ff159c8e39538103 (commit)
       via  8cb0a56a019c3cbaacc8ccdeebaf3906eeda8a74 (commit)
       via  b48e4ef0e4f09fdaa48f11dd97e1c378007cebaf (commit)
       via  ab579f5245e995718410e2f59bb7a82814f138a0 (commit)
       via  943f4ea870d5d00101dcdb4dfb5a6892ed3eb634 (commit)
       via  ef6d94432720eaf1fb73d65d78915a23aada2a25 (commit)
       via  9eab41529f7da65498b241f988a8ca096a4286c8 (commit)
       via  a2500cf8f53c5beaa5e9f872458f10650f91b95d (commit)
       via  da4f84b70faf79d279dd1ad978ee007b9fbd6447 (commit)
       via  adc3e2f94dcb38c4594408774599d946605f3cdb (commit)
       via  60c3b4447c47bd08d990d91a3a412ac6b329ff08 (commit)
       via  dc4cf0c6d071ef5661203ef42894ff8ecc6a90e4 (commit)
       via  1a3909427319f08fb5dacef02baa8c89b0b97408 (commit)
       via  c8aff6addd2137edd3b5b727ff40c3f7f6b00e71 (commit)
       via  320f10a5395ec1799f11d172ad6936da5467e815 (commit)
       via  323d64cc1465f7a1ef8813fa7a541f495c5e9dba (commit)
       via  2b5052e66a62634e8da2495a0d97018a144b7919 (commit)
       via  3d234878c77fab6f7bb172c5ef2bd21cde768a72 (commit)
       via  7482587271347cc071f95cf1709a0370c0087fd7 (commit)
       via  8c06e54ac7cdefa669326da0280294ea88196575 (commit)
       via  a154032687e8ba7c5c5cff880f34cd37166688c9 (commit)
       via  6620f7a7d1c0d952ad6da4b1441608cf56c2702b (commit)
       via  0857d558e83343a266e8bf67f835017c07f773c0 (commit)
       via  03a458983cf7d345ffa7d9d1b2cad0b509b3be54 (commit)
       via  9bfdf12f2fd3108a4b3b772c20e9b78396164042 (commit)
       via  4daf58b65f126c84a0d68d102ad899e260ea5662 (commit)
       via  20a8d4adbdcc32b17fabc43ef1e6af4c4b7c67d2 (commit)
       via  fc2a9e9876510fd425d693aaa5b93230606d26ec (commit)
       via  5306dddc94101bb87bcad59d1c29adc7bef4fe75 (commit)
       via  b1b78de66931aa416fda81f136b584f515561afd (commit)
       via  8aa47f6c343499103fcf86bdbe4c3918253a810a (commit)
       via  d7eecc60198a4bdd4cdf23dda9663f9d0d803f9b (commit)
       via  6713fdc5fb825c90598bbc48029027ed3f2515e0 (commit)
      from  bf2a2aab27a29e23699f42c393ac31b324c7f096 (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 42073d9d8c264a33ca883c9e80310cb91de706c6
Author: Paul Selkirk <pselkirk at isc.org>
Date:   Sun May 26 23:12:52 2013 -0400

    [master] ChangeLog entry for trac2522 merge

commit ea97070cf6b41299351fc29af66fa39c6465d56a
Merge: bf2a2aa 64bc088
Author: Paul Selkirk <pselkirk at isc.org>
Date:   Sun May 26 23:07:00 2013 -0400

    Merge branch 'trac2522'

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

Summary of changes:
 ChangeLog                                     |   12 ++
 src/lib/dns/gen-rdatacode.py.in               |   52 +-----
 src/lib/dns/rdata/any_255/tsig_250.cc         |  245 +++++++++++++++++--------
 src/lib/dns/rdata/any_255/tsig_250.h          |   14 +-
 src/lib/dns/rdata/ch_3/a_1.cc                 |    8 +-
 src/lib/dns/rdata/generic/minfo_14.cc         |   73 +++++---
 src/lib/dns/rdata/generic/minfo_14.h          |    6 +-
 src/lib/dns/rdata/generic/rp_17.cc            |   86 ++++++---
 src/lib/dns/rdata/generic/rp_17.h             |   12 +-
 src/lib/dns/rdata/generic/sshfp_44.cc         |  239 ++++++++++++++++++------
 src/lib/dns/rdata/generic/sshfp_44.h          |   17 +-
 src/lib/dns/rdata/hs_4/a_1.cc                 |    8 +-
 src/lib/dns/rrparamregistry-placeholder.cc    |   44 +----
 src/lib/dns/rrparamregistry.h                 |   17 +-
 src/lib/dns/tests/rdata_minfo_unittest.cc     |  113 ++++++++----
 src/lib/dns/tests/rdata_rp_unittest.cc        |   72 ++++++--
 src/lib/dns/tests/rdata_sshfp_unittest.cc     |   97 ++++++++--
 src/lib/dns/tests/rdata_tsig_unittest.cc      |  198 +++++++++++++-------
 src/lib/dns/tests/rrparamregistry_unittest.cc |    7 +-
 19 files changed, 862 insertions(+), 458 deletions(-)

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index ac75bf6..1ec49e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+621.	[func]		team
+	libdns++: All Rdata classes now use the generic lexer in
+	constructors from text. This means that the name fields in such
+	RRs in a zone file can now be non-absolute (the origin name in that
+	context will be used), e.g., when loaded by b10-loadzone. Note
+	that the existing string constructors for these Rdata classes also
+	use the generic lexer, and they now expect an absolute name (with
+	the trailing '.') in the name fields.
+	(Trac #2522, git ea97070cf6b41299351fc29af66fa39c6465d56a)
+	(Trac #2521, git c6603decaadcd33ccf9aee4a7b22447acec4b7f6)
+	(See also ChangeLog 594, 564, 545)
+
 620.	[bug]		jinmei
 	b10-auth now returns SERVFAIL to queries for a zone that is
 	configured to be loaded in-memory but isn't due to load time
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index a49f72f..3fd3b33 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -24,39 +24,6 @@ from os.path import getmtime
 import re
 import sys
 
-# new_rdata_factory_users[] is a list of tuples of the form (rrtype,
-# rrclass). Items in the list use the (new) RdataFactory class, and
-# items which are not in the list use OldRdataFactory class.
-# Note: rrtype and rrclass must be specified in lowercase in
-# new_rdata_factory_users.
-#
-# Example:
-#     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = [('a', 'in'),
-                           ('aaaa', 'in'),
-                           ('afsdb', 'generic'),
-                           ('cname', 'generic'),
-                           ('dhcid', 'in'),
-                           ('dlv', 'generic'),
-                           ('dname', 'generic'),
-                           ('dnskey', 'generic'),
-                           ('ds', 'generic'),
-                           ('hinfo', 'generic'),
-                           ('naptr', 'generic'),
-                           ('mx', 'generic'),
-                           ('ns', 'generic'),
-                           ('nsec', 'generic'),
-                           ('nsec3', 'generic'),
-                           ('nsec3param', 'generic'),
-                           ('opt', 'generic'),
-                           ('ptr', 'generic'),
-                           ('rrsig', 'generic'),
-                           ('soa', 'generic'),
-                           ('spf', 'generic'),
-                           ('srv', 'in'),
-                           ('txt', 'generic')
-                          ]
-
 re_typecode = re.compile('([\da-z\-]+)_(\d+)')
 classcode2txt = {}
 typecode2txt = {}
@@ -66,7 +33,7 @@ meta_types = {
     # Real meta types.  We won't have Rdata implement for them, but we need
     # RRType constants.
     '251': 'ixfr', '252': 'axfr', '255': 'any',
-    # Obsolete types.  We probalby won't implement Rdata for them, but it's
+    # Obsolete types.  We probably won't implement Rdata for them, but it's
     # better to have RRType constants.
     '3': 'md', '4': 'mf', '7': 'mb', '8': 'mg', '9': 'mr', '30': 'nxt',
     '38': 'a6', '254': 'maila',
@@ -375,28 +342,15 @@ def generate_rrparam(fileprefix, basemtime):
         indent = ' ' * 8
         typeandclassparams += indent
 
-        # By default, we use OldRdataFactory (see bug #2497). If you
-        # want to pick RdataFactory for a particular type, add it to
-        # new_rdata_factory_users.  Note that we explicitly generate (for
-        # optimization) class-independent ("generic") factories for class IN
-        # for optimization.
-        if (((type_txt.lower(), class_txt.lower()) in
-             new_rdata_factory_users) or
-            ((class_txt.lower() == 'in') and
-             ((type_txt.lower(), 'generic') in new_rdata_factory_users))):
-            rdf_class = 'RdataFactory'
-        else:
-            rdf_class = 'OldRdataFactory'
-
         if class_tuple[1] != 'generic':
             typeandclassparams += 'add("' + type_utxt + '", '
             typeandclassparams += str(type_code) + ', "' + class_utxt
             typeandclassparams += '", ' + str(class_code)
-            typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
+            typeandclassparams += ', RdataFactoryPtr(new ' + 'RdataFactory' + '<'
             typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
         else:
             typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
-            typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
+            typeandclassparams += ', RdataFactoryPtr(new ' + 'RdataFactory' + '<'
             typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
 
     typeandclassparams += indent + '// Meta and non-implemented RR types\n'
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
index ff848fa..4e86cf9 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ b/src/lib/dns/rdata/any_255/tsig_250.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -19,26 +19,28 @@
 #include <boost/lexical_cast.hpp>
 
 #include <util/buffer.h>
-#include <util/strutil.h>
 #include <util/encode/base64.h>
 
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rcode.h>
 #include <dns/tsigerror.h>
+#include <dns/rdata/generic/detail/lexer_util.h>
 
 using namespace std;
 using boost::lexical_cast;
 using namespace isc::util;
 using namespace isc::util::encode;
-using namespace isc::util::str;
+using namespace isc::dns;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
-/// This is a straightforward representation of TSIG RDATA fields.
-struct TSIG::TSIGImpl {
+// straightforward representation of TSIG RDATA fields
+struct TSIGImpl {
     TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge,
              vector<uint8_t>& mac, uint16_t original_id, uint16_t error,
              vector<uint8_t>& other_data) :
@@ -68,99 +70,184 @@ struct TSIG::TSIGImpl {
     const vector<uint8_t> other_data_;
 };
 
+// helper function for string and lexer constructors
+TSIGImpl*
+TSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) {
+    const Name& algorithm =
+        createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME());
+
+    const string& time_txt =
+        lexer.getNextToken(MasterToken::STRING).getString();
+    uint64_t time_signed;
+    try {
+        time_signed = boost::lexical_cast<uint64_t>(time_txt);
+    } catch (const boost::bad_lexical_cast&) {
+        isc_throw(InvalidRdataText, "Invalid TSIG Time");
+    }
+    if ((time_signed >> 48) != 0) {
+        isc_throw(InvalidRdataText, "TSIG Time out of range");
+    }
+
+    const uint32_t fudge = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (fudge > 0xffff) {
+        isc_throw(InvalidRdataText, "TSIG Fudge out of range");
+    }
+    const uint32_t macsize =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (macsize > 0xffff) {
+        isc_throw(InvalidRdataText, "TSIG MAC Size out of range");
+    }
+
+    const string& mac_txt = (macsize > 0) ?
+            lexer.getNextToken(MasterToken::STRING).getString() : "";
+    vector<uint8_t> mac;
+    decodeBase64(mac_txt, mac);
+    if (mac.size() != macsize) {
+        isc_throw(InvalidRdataText, "TSIG MAC Size and data are inconsistent");
+    }
+
+    const uint32_t orig_id =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (orig_id > 0xffff) {
+        isc_throw(InvalidRdataText, "TSIG Original ID out of range");
+    }
+
+    const string& error_txt =
+        lexer.getNextToken(MasterToken::STRING).getString();
+    uint32_t error = 0;
+    // XXX: In the initial implementation we hardcode the mnemonics.
+    // We'll soon generalize this.
+    if (error_txt == "NOERROR") {
+        error = Rcode::NOERROR_CODE;
+    } else if (error_txt == "BADSIG") {
+        error = TSIGError::BAD_SIG_CODE;
+    } else if (error_txt == "BADKEY") {
+        error = TSIGError::BAD_KEY_CODE;
+    } else if (error_txt == "BADTIME") {
+        error = TSIGError::BAD_TIME_CODE;
+    } else {
+	/// we cast to uint32_t and range-check, because casting directly to
+	/// uint16_t will convert negative numbers to large positive numbers
+        try {
+            error = boost::lexical_cast<uint32_t>(error_txt);
+        } catch (const boost::bad_lexical_cast&) {
+            isc_throw(InvalidRdataText, "Invalid TSIG Error");
+        }
+        if (error > 0xffff) {
+            isc_throw(InvalidRdataText, "TSIG Error out of range");
+        }
+    }
+
+    const uint32_t otherlen =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (otherlen > 0xffff) {
+        isc_throw(InvalidRdataText, "TSIG Other Len out of range");
+    }
+    const string otherdata_txt = (otherlen > 0) ?
+            lexer.getNextToken(MasterToken::STRING).getString() : "";
+    vector<uint8_t> other_data;
+    decodeBase64(otherdata_txt, other_data);
+    if (other_data.size() != otherlen) {
+        isc_throw(InvalidRdataText,
+                  "TSIG Other Data length does not match Other Len");
+    }
+    // RFC2845 says Other Data is "empty unless Error == BADTIME".
+    // However, we don't enforce that.
+
+    return (new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
+                         error, other_data));
+}
+
 /// \brief Constructor from string.
 ///
+/// The given string must represent a valid TSIG RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
 /// \c tsig_str must be formatted as follows:
-/// \code <Alg> <Time> <Fudge> <MACsize> [<MAC>] <OrigID> <Error> <OtherLen> [<OtherData>]
+/// \code <Algorithm Name> <Time Signed> <Fudge> <MAC Size> [<MAC>]
+/// <Original ID> <Error> <Other Len> [<Other Data>]
 /// \endcode
-/// where
-/// - <Alg> is a valid textual representation of domain name.
-/// - <Time> is an unsigned 48-bit decimal integer.
-/// - <MACSize>, <OrigID>, and <OtherLen> are an unsigned
-///   16-bit decimal
-///   integer.
-/// - <Error> is an unsigned 16-bit decimal integer or a valid mnemonic
-///   for the Error field specified in RFC2845.  Currently, "BADSIG", "BADKEY",
-///   and "BADTIME" are supported (case sensitive).  In future versions
-///   other representations that are compatible with the DNS RCODE will be
-///   supported.
-/// - <MAC> and <OtherData> is a BASE-64 encoded string that does
-///   not contain space characters.
-///   When <MACSize> and <OtherLen> is 0, <MAC> and
-///   <OtherData> must not appear in \c tsig_str, respectively.
-/// - The decoded data of <MAC> is <MACSize> bytes of binary
-///   stream.
-/// - The decoded data of <OtherData> is <OtherLen> bytes of
-///   binary stream.
+///
+/// Note that, since the Algorithm Name field is defined to be "in domain name
+/// syntax", but it is not actually a domain name, it does not have to be
+/// fully qualified.
+///
+/// The Error field is an unsigned 16-bit decimal integer or a valid mnemonic
+/// as specified in RFC2845.  Currently, "NOERROR", "BADSIG", "BADKEY", and
+/// "BADTIME" are supported (case sensitive).  In future versions other
+/// representations that are compatible with the DNS RCODE may be supported.
+///
+/// The MAC and Other Data fields are base-64 encoded strings that do not
+/// contain space characters.
+/// If the MAC Size field is 0, the MAC field must not appear in \c tsig_str.
+/// If the Other Len field is 0, the Other Data field must not appear in
+/// \c tsig_str.
+/// The decoded data of the MAC field is MAC Size bytes of binary stream.
+/// The decoded data of the Other Data field is Other Len bytes of binary
+/// stream.
 ///
 /// An example of valid string is:
 /// \code "hmac-sha256. 853804800 300 3 AAAA 2845 0 0" \endcode
-/// In this example <OtherData> is missing because <OtherLen> is 0.
+/// In this example Other Data is missing because Other Len is 0.
 ///
 /// Note that RFC2845 does not define the standard presentation format
 /// of %TSIG RR, so the above syntax is implementation specific.
 /// This is, however, compatible with the format acceptable to BIND 9's
 /// RDATA parser.
 ///
-/// <b>Exceptions</b>
+/// \throw Others Exception from the Name constructors.
+/// \throw InvalidRdataText if any fields are out of their valid range,
+/// or are incorrect.
+/// \throw BadValue if MAC or Other Data is not validly encoded in base-64.
 ///
-/// If <Alg> is not a valid domain name, a corresponding exception from
-/// the \c Name class will be thrown;
-/// if <MAC> or <OtherData> is not validly encoded in BASE-64, an
-/// exception of class \c isc::BadValue will be thrown;
-/// if %any of the other bullet points above is not met, an exception of
-/// class \c InvalidRdataText will be thrown.
-/// This constructor internally involves resource allocation, and if it fails
-/// a corresponding standard exception will be thrown.
+/// \param tsig_str A string containing the RDATA to be created
 TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
-    istringstream iss(tsig_str);
+    // We use auto_ptr here because if there is an exception in this
+    // constructor, the destructor is not called and there could be a
+    // leak of the TSIGImpl that constructFromLexer() returns.
+    std::auto_ptr<TSIGImpl> impl_ptr(NULL);
 
     try {
-        const Name algorithm(getToken(iss));
-        const int64_t time_signed = tokenToNum<int64_t, 48>(getToken(iss));
-        const int32_t fudge = tokenToNum<int32_t, 16>(getToken(iss));
-        const int32_t macsize = tokenToNum<int32_t, 16>(getToken(iss));
-
-        const string mac_txt = (macsize > 0) ? getToken(iss) : "";
-        vector<uint8_t> mac;
-        decodeBase64(mac_txt, mac);
-        if (mac.size() != macsize) {
-            isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent");
-        }
-
-        const int32_t orig_id = tokenToNum<int32_t, 16>(getToken(iss));
-
-        const string error_txt = getToken(iss);
-        int32_t error = 0;
-        // XXX: In the initial implementation we hardcode the mnemonics.
-        // We'll soon generalize this.
-        if (error_txt == "BADSIG") {
-            error = 16;
-        } else if (error_txt == "BADKEY") {
-            error = 17;
-        } else if (error_txt == "BADTIME") {
-            error = 18;
-        } else {
-            error = tokenToNum<int32_t, 16>(error_txt);
-        }
+        std::istringstream ss(tsig_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
 
-        const int32_t otherlen = tokenToNum<int32_t, 16>(getToken(iss));
-        const string otherdata_txt = (otherlen > 0) ? getToken(iss) : "";
-        vector<uint8_t> other_data;
-        decodeBase64(otherdata_txt, other_data);
+        impl_ptr.reset(constructFromLexer(lexer, NULL));
 
-        if (!iss.eof()) {
-            isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " <<
-                    tsig_str);
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText,
+                      "Extra input text for TSIG: " << tsig_str);
         }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText,
+                  "Failed to construct TSIG from '" << tsig_str << "': "
+                  << ex.what());
+    }
 
-        impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
-                            error, other_data);
+    impl_ = impl_ptr.release();
+}
 
-    } catch (const StringTokenError& ste) {
-        isc_throw(InvalidRdataText, "Invalid TSIG text: " << ste.what() <<
-                  ": " << tsig_str);
-    }
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of an TSIG RDATA.
+///
+/// See \c TSIG::TSIG(const std::string&) for description of the
+/// expected RDATA fields.
+///
+/// \throw MasterLexer::LexerError General parsing error such as
+/// missing field.
+/// \throw InvalidRdataText if any fields are out of their valid range,
+/// or are incorrect.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+TSIG::TSIG(MasterLexer& lexer, const Name* origin,
+           MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(constructFromLexer(lexer, origin))
+{
 }
 
 /// \brief Constructor from wire-format data.
@@ -183,7 +270,9 @@ TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
 /// But this constructor does not use this parameter; if necessary, the caller
 /// must check consistency between the length parameter and the actual
 /// RDATA length.
-TSIG::TSIG(InputBuffer& buffer, size_t) : impl_(NULL) {
+TSIG::TSIG(InputBuffer& buffer, size_t) :
+    impl_(NULL)
+{
     Name algorithm(buffer);
 
     uint8_t time_signed_buf[6];
@@ -298,7 +387,7 @@ TSIG::toText() const {
 // toWire().
 template <typename Output>
 void
-TSIG::TSIGImpl::toWireCommon(Output& output) const {
+TSIGImpl::toWireCommon(Output& output) const {
     output.writeUint16(time_signed_ >> 32);
     output.writeUint32(time_signed_ & 0xffffffff);
     output.writeUint16(fudge_);
diff --git a/src/lib/dns/rdata/any_255/tsig_250.h b/src/lib/dns/rdata/any_255/tsig_250.h
index ff24925..62f599a 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.h
+++ b/src/lib/dns/rdata/any_255/tsig_250.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -18,14 +18,9 @@
 
 #include <string>
 
+#include <dns/name.h>
 #include <dns/rdata.h>
 
-namespace isc {
-namespace dns {
-class Name;
-}
-}
-
 // BEGIN_ISC_NAMESPACE
 
 // BEGIN_COMMON_DECLARATIONS
@@ -33,6 +28,8 @@ class Name;
 
 // BEGIN_RDATA_NAMESPACE
 
+struct TSIGImpl;
+
 /// \brief \c rdata::TSIG class represents the TSIG RDATA as defined %in
 /// RFC2845.
 ///
@@ -145,7 +142,8 @@ public:
     /// This method never throws an exception.
     const void* getOtherData() const;
 private:
-    struct TSIGImpl;
+    TSIGImpl* constructFromLexer(MasterLexer& lexer, const Name* origin);
+
     TSIGImpl* impl_;
 };
 
diff --git a/src/lib/dns/rdata/ch_3/a_1.cc b/src/lib/dns/rdata/ch_3/a_1.cc
index 3d13a9e..5e2852f 100644
--- a/src/lib/dns/rdata/ch_3/a_1.cc
+++ b/src/lib/dns/rdata/ch_3/a_1.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -31,6 +31,12 @@ A::A(const std::string&) {
     // TBD
 }
 
+A::A(MasterLexer&, const Name*,
+     MasterLoader::Options, MasterLoaderCallbacks&)
+{
+    // TBD
+}
+
 A::A(InputBuffer&, size_t) {
     // TBD
 }
diff --git a/src/lib/dns/rdata/generic/minfo_14.cc b/src/lib/dns/rdata/generic/minfo_14.cc
index aa5272c..58d6f3c 100644
--- a/src/lib/dns/rdata/generic/minfo_14.cc
+++ b/src/lib/dns/rdata/generic/minfo_14.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -21,10 +21,12 @@
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/lexer_util.h>
 
 using namespace std;
 using namespace isc::dns;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -39,12 +41,10 @@ using namespace isc::util;
 /// An example of valid string is:
 /// \code "rmail.example.com. email.example.com." \endcode
 ///
-/// <b>Exceptions</b>
-///
-/// \exception InvalidRdataText The number of RDATA fields (must be 2) is
+/// \throw InvalidRdataText The number of RDATA fields (must be 2) is
 /// incorrect.
-/// \exception std::bad_alloc Memory allocation for names fails.
-/// \exception Other The constructor of the \c Name class will throw if the
+/// \throw std::bad_alloc Memory allocation for names fails.
+/// \throw Other The constructor of the \c Name class will throw if the
 /// names in the string is invalid.
 MINFO::MINFO(const std::string& minfo_str) :
     // We cannot construct both names in the initialization list due to the
@@ -52,21 +52,44 @@ MINFO::MINFO(const std::string& minfo_str) :
     // name and replace them later.
     rmailbox_(Name::ROOT_NAME()), emailbox_(Name::ROOT_NAME())
 {
-    istringstream iss(minfo_str);
-    string rmailbox_str, emailbox_str;
-    iss >> rmailbox_str >> emailbox_str;
-
-    // Validation: A valid MINFO RR must have exactly two fields.
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid MINFO text: " << minfo_str);
-    }
-    if (!iss.eof()) {
-        isc_throw(InvalidRdataText, "Invalid MINFO text (redundant field): "
-                  << minfo_str);
+    try {
+        std::istringstream ss(minfo_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+	rmailbox_ = createNameFromLexer(lexer, NULL);
+	emailbox_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for MINFO: "
+                      << minfo_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct MINFO from '" <<
+                  minfo_str << "': " << ex.what());
     }
+}
 
-    rmailbox_ = Name(rmailbox_str);
-    emailbox_ = Name(emailbox_str);
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an MINFO RDATA.  The RMAILBOX and EMAILBOX fields can be non-absolute
+/// if \c origin is non-NULL, in which case \c origin is used to make them
+/// absolute.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and constructors if construction of
+/// textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of SERVER when it
+/// is non-absolute.
+MINFO::MINFO(MasterLexer& lexer, const Name* origin,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    rmailbox_(createNameFromLexer(lexer, origin)),
+    emailbox_(createNameFromLexer(lexer, origin))
+{
 }
 
 /// \brief Constructor from wire-format data.
@@ -75,8 +98,8 @@ MINFO::MINFO(const std::string& minfo_str) :
 /// length) for parsing.
 /// If necessary, the caller will check consistency.
 ///
-/// \exception std::bad_alloc Memory allocation for names fails.
-/// \exception Other The constructor of the \c Name class will throw if the
+/// \throw std::bad_alloc Memory allocation for names fails.
+/// \throw Other The constructor of the \c Name class will throw if the
 /// names in the wire is invalid.
 MINFO::MINFO(InputBuffer& buffer, size_t) :
     rmailbox_(buffer), emailbox_(buffer)
@@ -84,7 +107,7 @@ MINFO::MINFO(InputBuffer& buffer, size_t) :
 
 /// \brief Copy constructor.
 ///
-/// \exception std::bad_alloc Memory allocation fails in copying internal
+/// \throw std::bad_alloc Memory allocation fails in copying internal
 /// member variables (this should be very rare).
 MINFO::MINFO(const MINFO& other) :
     Rdata(), rmailbox_(other.rmailbox_), emailbox_(other.emailbox_)
@@ -95,7 +118,7 @@ MINFO::MINFO(const MINFO& other) :
 /// The output of this method is formatted as described in the "from string"
 /// constructor (\c MINFO(const std::string&))).
 ///
-/// \exception std::bad_alloc Internal resource allocation fails.
+/// \throw std::bad_alloc Internal resource allocation fails.
 ///
 /// \return A \c string object that represents the \c MINFO object.
 std::string
@@ -105,7 +128,7 @@ MINFO::toText() const {
 
 /// \brief Render the \c MINFO in the wire format without name compression.
 ///
-/// \exception std::bad_alloc Internal resource allocation fails.
+/// \throw std::bad_alloc Internal resource allocation fails.
 ///
 /// \param buffer An output buffer to store the wire data.
 void
@@ -128,7 +151,7 @@ MINFO::operator=(const MINFO& source) {
 /// As specified in RFC3597, TYPE MINFO is "well-known", the rmailbox and
 /// emailbox fields (domain names) will be compressed.
 ///
-/// \exception std::bad_alloc Internal resource allocation fails.
+/// \throw std::bad_alloc Internal resource allocation fails.
 ///
 /// \param renderer DNS message rendering context that encapsulates the
 /// output buffer and name compression information.
diff --git a/src/lib/dns/rdata/generic/minfo_14.h b/src/lib/dns/rdata/generic/minfo_14.h
index f3ee1d0..ce4586f 100644
--- a/src/lib/dns/rdata/generic/minfo_14.h
+++ b/src/lib/dns/rdata/generic/minfo_14.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -45,7 +45,7 @@ public:
 
     /// \brief Return the value of the rmailbox field.
     ///
-    /// \exception std::bad_alloc If resource allocation for the returned
+    /// \throw std::bad_alloc If resource allocation for the returned
     /// \c Name fails.
     ///
     /// \note
@@ -64,7 +64,7 @@ public:
 
     /// \brief Return the value of the emailbox field.
     ///
-    /// \exception std::bad_alloc If resource allocation for the returned
+    /// \throw std::bad_alloc If resource allocation for the returned
     /// \c Name fails.
     Name getEmailbox() const { return (emailbox_); }
 
diff --git a/src/lib/dns/rdata/generic/rp_17.cc b/src/lib/dns/rdata/generic/rp_17.cc
index 781b55d..d3d86fd 100644
--- a/src/lib/dns/rdata/generic/rp_17.cc
+++ b/src/lib/dns/rdata/generic/rp_17.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -21,10 +21,12 @@
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/lexer_util.h>
 
 using namespace std;
 using namespace isc::dns;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -36,32 +38,54 @@ using namespace isc::util;
 /// \endcode
 /// where both fields must represent a valid domain name.
 ///
-/// \exception InvalidRdataText The number of RDATA fields (must be 2) is
+/// \throw InvalidRdataText The number of RDATA fields (must be 2) is
 /// incorrect.
-/// \exception Other The constructor of the \c Name class will throw if the
+/// \throw std::bad_alloc Memory allocation for names fails.
+/// \throw Other The constructor of the \c Name class will throw if the
 /// given name is invalid.
-/// \exception std::bad_alloc Memory allocation for names fails.
 RP::RP(const std::string& rp_str) :
     // We cannot construct both names in the initialization list due to the
     // necessary text processing, so we have to initialize them with a dummy
     // name and replace them later.
     mailbox_(Name::ROOT_NAME()), text_(Name::ROOT_NAME())
 {
-    istringstream iss(rp_str);
-    string mailbox_str, text_str;
-    iss >> mailbox_str >> text_str;
-
-    // Validation: A valid RP RR must have exactly two fields.
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid RP text: " << rp_str);
-    }
-    if (!iss.eof()) {
-        isc_throw(InvalidRdataText, "Invalid RP text (redundant field): "
-                  << rp_str);
+    try {
+        std::istringstream ss(rp_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        mailbox_ = createNameFromLexer(lexer, NULL);
+        text_ = createNameFromLexer(lexer, NULL);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for RP: "
+                      << rp_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct RP from '" <<
+                  rp_str << "': " << ex.what());
     }
+}
 
-    mailbox_ = Name(mailbox_str);
-    text_ = Name(text_str);
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an RP RDATA.  The MAILBOX and TEXT fields can be non-absolute if \c
+/// origin is non-NULL, in which case \c origin is used to make them absolute.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and constructors if construction of
+/// textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of SERVER when it
+/// is non-absolute.
+RP::RP(MasterLexer& lexer, const Name* origin,
+       MasterLoader::Options, MasterLoaderCallbacks&) :
+    mailbox_(createNameFromLexer(lexer, origin)),
+    text_(createNameFromLexer(lexer, origin))
+{
 }
 
 /// \brief Constructor from wire-format data.
@@ -70,15 +94,15 @@ RP::RP(const std::string& rp_str) :
 /// length) for parsing.
 /// If necessary, the caller will check consistency.
 ///
-/// \exception std::bad_alloc Memory allocation for names fails.
-/// \exception Other The constructor of the \c Name class will throw if the
+/// \throw std::bad_alloc Memory allocation for names fails.
+/// \throw Other The constructor of the \c Name class will throw if the
 /// names in the wire is invalid.
 RP::RP(InputBuffer& buffer, size_t) : mailbox_(buffer), text_(buffer) {
 }
 
 /// \brief Copy constructor.
 ///
-/// \exception std::bad_alloc Memory allocation fails in copying internal
+/// \throw std::bad_alloc Memory allocation fails in copying internal
 /// member variables (this should be very rare).
 RP::RP(const RP& other) :
     Rdata(), mailbox_(other.mailbox_), text_(other.text_)
@@ -89,7 +113,7 @@ RP::RP(const RP& other) :
 /// The output of this method is formatted as described in the "from string"
 /// constructor (\c RP(const std::string&))).
 ///
-/// \exception std::bad_alloc Internal resource allocation fails.
+/// \throw std::bad_alloc Internal resource allocation fails.
 ///
 /// \return A \c string object that represents the \c RP object.
 std::string
@@ -97,20 +121,36 @@ RP::toText() const {
     return (mailbox_.toText() + " " + text_.toText());
 }
 
+/// \brief Render the \c RP in the wire format without name compression.
+///
+/// \throw std::bad_alloc Internal resource allocation fails.
+///
+/// \param buffer An output buffer to store the wire data.
 void
 RP::toWire(OutputBuffer& buffer) const {
     mailbox_.toWire(buffer);
     text_.toWire(buffer);
 }
 
+/// \brief Render the \c RP in the wire format with taking into account
+/// compression.
+///
+// Type RP is not "well-known", and name compression must be disabled
+// per RFC3597.
+///
+/// \throw std::bad_alloc Internal resource allocation fails.
+///
+/// \param renderer DNS message rendering context that encapsulates the
+/// output buffer and name compression information.
 void
 RP::toWire(AbstractMessageRenderer& renderer) const {
-    // Type RP is not "well-known", and name compression must be disabled
-    // per RFC3597.
     renderer.writeName(mailbox_, false);
     renderer.writeName(text_, false);
 }
 
+/// \brief Compare two instances of \c RP RDATA.
+///
+/// See documentation in \c Rdata.
 int
 RP::compare(const Rdata& other) const {
     const RP& other_rp = dynamic_cast<const RP&>(other);
diff --git a/src/lib/dns/rdata/generic/rp_17.h b/src/lib/dns/rdata/generic/rp_17.h
index a90a530..2fb89df 100644
--- a/src/lib/dns/rdata/generic/rp_17.h
+++ b/src/lib/dns/rdata/generic/rp_17.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -49,9 +49,8 @@ public:
 
     /// \brief Return the value of the mailbox field.
     ///
-    /// This method normally does not throw an exception, but if resource
-    /// allocation for the returned \c Name object fails, a corresponding
-    /// standard exception will be thrown.
+    /// \throw std::bad_alloc If resource allocation for the returned
+    /// \c Name fails.
     ///
     /// \note
     /// Unlike the case of some other RDATA classes (such as
@@ -69,9 +68,8 @@ public:
 
     /// \brief Return the value of the text field.
     ///
-    /// This method normally does not throw an exception, but if resource
-    /// allocation for the returned \c Name object fails, a corresponding
-    /// standard exception will be thrown.
+    /// \throw std::bad_alloc If resource allocation for the returned
+    /// \c Name fails.
     Name getText() const { return (text_); }
 
 private:
diff --git a/src/lib/dns/rdata/generic/sshfp_44.cc b/src/lib/dns/rdata/generic/sshfp_44.cc
index 64b3cc1..c7199f3 100644
--- a/src/lib/dns/rdata/generic/sshfp_44.cc
+++ b/src/lib/dns/rdata/generic/sshfp_44.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -35,122 +35,239 @@ using namespace isc::util::encode;
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
-SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len) {
-    if (rdata_len < 2) {
-        isc_throw(InvalidRdataLength, "SSHFP record too short");
+struct SSHFPImpl {
+    // straightforward representation of SSHFP RDATA fields
+    SSHFPImpl(uint8_t algorithm, uint8_t fingerprint_type,
+              vector<uint8_t>& fingerprint) :
+        algorithm_(algorithm),
+        fingerprint_type_(fingerprint_type),
+        fingerprint_(fingerprint)
+    {}
+
+    uint8_t algorithm_;
+    uint8_t fingerprint_type_;
+    const vector<uint8_t> fingerprint_;
+};
+
+// helper function for string and lexer constructors
+SSHFPImpl*
+SSHFP::constructFromLexer(MasterLexer& lexer) {
+    const uint32_t algorithm =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (algorithm > 255) {
+        isc_throw(InvalidRdataText, "SSHFP algorithm number out of range");
     }
 
-    algorithm_ = buffer.readUint8();
-    fingerprint_type_ = buffer.readUint8();
-
-    rdata_len -= 2;
-    if (rdata_len > 0) {
-        fingerprint_.resize(rdata_len);
-        buffer.readData(&fingerprint_[0], rdata_len);
+    const uint32_t fingerprint_type =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (fingerprint_type > 255) {
+        isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range");
     }
-}
-
-SSHFP::SSHFP(const std::string& sshfp_str) {
-    std::istringstream iss(sshfp_str);
-    std::stringbuf fingerprintbuf;
-    uint32_t algorithm, fingerprint_type;
 
-    iss >> algorithm >> fingerprint_type;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid SSHFP text");
+    std::string fingerprint_str;
+    std::string fingerprint_substr;
+    while (true) {
+        const MasterToken& token =
+            lexer.getNextToken(MasterToken::STRING, true);
+        if ((token.getType() == MasterToken::END_OF_FILE) ||
+            (token.getType() == MasterToken::END_OF_LINE)) {
+            break;
+        }
+        token.getString(fingerprint_substr);
+        fingerprint_str.append(fingerprint_substr);
     }
+    lexer.ungetToken();
 
-    if (algorithm > 255) {
-        isc_throw(InvalidRdataText, "SSHFP algorithm number out of range");
+    vector<uint8_t> fingerprint;
+    // If fingerprint is missing, it's OK. See the API documentation of the
+    // constructor.
+    if (fingerprint_str.size() > 0) {
+        decodeHex(fingerprint_str, fingerprint);
     }
 
-    if (fingerprint_type > 255) {
-        isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range");
-    }
+    return (new SSHFPImpl(algorithm, fingerprint_type, fingerprint));
+}
+
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid SSHFP RDATA.  There can be
+/// extra space characters at the beginning or end of the text (which
+/// are simply ignored), but other extra text, including a new line,
+/// will make the construction fail with an exception.
+///
+/// The Algorithm and Fingerprint Type fields must be within their valid
+/// ranges, but are not constrained to the values defined in RFC4255.
+///
+/// The Fingerprint field may be absent, but if present it must contain a
+/// valid hex encoding of the fingerprint. For compatibility with BIND 9,
+/// whitespace is allowed in the hex text (RFC4255 is silent on the matter).
+///
+/// \throw InvalidRdataText if any fields are missing, out of their valid
+/// ranges, or incorrect.
+///
+/// \param sshfp_str A string containing the RDATA to be created
+SSHFP::SSHFP(const string& sshfp_str) :
+    impl_(NULL)
+{
+    // We use auto_ptr here because if there is an exception in this
+    // constructor, the destructor is not called and there could be a
+    // leak of the SSHFPImpl that constructFromLexer() returns.
+    std::auto_ptr<SSHFPImpl> impl_ptr(NULL);
 
-    iss >> &fingerprintbuf;
     try {
-        decodeHex(fingerprintbuf.str(), fingerprint_);
+        std::istringstream ss(sshfp_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        impl_ptr.reset(constructFromLexer(lexer));
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for SSHFP: "
+                      << sshfp_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" <<
+                  sshfp_str << "': " << ex.what());
     } catch (const isc::BadValue& e) {
         isc_throw(InvalidRdataText,
                   "Bad SSHFP fingerprint: " << e.what());
     }
 
-    algorithm_ = algorithm;
-    fingerprint_type_ = fingerprint_type;
+    impl_ = impl_ptr.release();
 }
 
-SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type,
-             const std::string& fingerprint)
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an SSHFP RDATA.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw InvalidRdataText Fields are out of their valid range, or are
+/// incorrect.
+/// \throw BadValue Fingerprint is not a valid hex string.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+SSHFP::SSHFP(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(constructFromLexer(lexer))
 {
-    algorithm_ = algorithm;
-    fingerprint_type_ = fingerprint_type;
+}
+
+/// \brief Constructor from InputBuffer.
+///
+/// The passed buffer must contain a valid SSHFP RDATA.
+///
+/// The Algorithm and Fingerprint Type fields are not checked for unknown
+/// values.  It is okay for the fingerprint data to be missing (see the
+/// description of the constructor from string).
+SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len) {
+    if (rdata_len < 2) {
+        isc_throw(InvalidRdataLength, "SSHFP record too short");
+    }
+
+    const uint8_t algorithm = buffer.readUint8();
+    const uint8_t fingerprint_type = buffer.readUint8();
+
+    vector<uint8_t> fingerprint;
+    rdata_len -= 2;
+    if (rdata_len > 0) {
+        fingerprint.resize(rdata_len);
+        buffer.readData(&fingerprint[0], rdata_len);
+    }
+
+    impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
+}
 
+SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type,
+             const string& fingerprint_txt) :
+    impl_(NULL)
+{
+    vector<uint8_t> fingerprint;
     try {
-        decodeHex(fingerprint, fingerprint_);
+        decodeHex(fingerprint_txt, fingerprint);
     } catch (const isc::BadValue& e) {
         isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what());
     }
+
+    impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
 }
 
 SSHFP::SSHFP(const SSHFP& other) :
-  Rdata(), algorithm_(other.algorithm_),
-  fingerprint_type_(other.fingerprint_type_),
-  fingerprint_(other.fingerprint_)
+        Rdata(), impl_(new SSHFPImpl(*other.impl_))
 {}
 
+SSHFP&
+SSHFP::operator=(const SSHFP& source) {
+    if (impl_ == source.impl_) {
+        return (*this);
+    }
+
+    SSHFPImpl* newimpl = new SSHFPImpl(*source.impl_);
+    delete impl_;
+    impl_ = newimpl;
+
+    return (*this);
+}
+
+SSHFP::~SSHFP() {
+    delete impl_;
+}
+
 void
 SSHFP::toWire(OutputBuffer& buffer) const {
-    buffer.writeUint8(algorithm_);
-    buffer.writeUint8(fingerprint_type_);
+    buffer.writeUint8(impl_->algorithm_);
+    buffer.writeUint8(impl_->fingerprint_type_);
 
-    if (!fingerprint_.empty()) {
-        buffer.writeData(&fingerprint_[0], fingerprint_.size());
+    if (!impl_->fingerprint_.empty()) {
+        buffer.writeData(&impl_->fingerprint_[0],
+                         impl_->fingerprint_.size());
     }
 }
 
 void
 SSHFP::toWire(AbstractMessageRenderer& renderer) const {
-    renderer.writeUint8(algorithm_);
-    renderer.writeUint8(fingerprint_type_);
+    renderer.writeUint8(impl_->algorithm_);
+    renderer.writeUint8(impl_->fingerprint_type_);
 
-    if (!fingerprint_.empty()) {
-        renderer.writeData(&fingerprint_[0], fingerprint_.size());
+    if (!impl_->fingerprint_.empty()) {
+        renderer.writeData(&impl_->fingerprint_[0],
+                           impl_->fingerprint_.size());
     }
 }
 
 string
 SSHFP::toText() const {
-    return (lexical_cast<string>(static_cast<int>(algorithm_)) +
-            " " + lexical_cast<string>(static_cast<int>(fingerprint_type_)) +
-            (fingerprint_.empty() ? "" : " " + encodeHex(fingerprint_)));
+    return (lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + " " +
+            lexical_cast<string>(static_cast<int>(impl_->fingerprint_type_)) +
+            (impl_->fingerprint_.empty() ? "" :
+             " " + encodeHex(impl_->fingerprint_)));
 }
 
 int
 SSHFP::compare(const Rdata& other) const {
     const SSHFP& other_sshfp = dynamic_cast<const SSHFP&>(other);
 
-    /* This doesn't really make any sort of sense, but in the name of
-       consistency... */
-
-    if (algorithm_ < other_sshfp.algorithm_) {
+    if (impl_->algorithm_ < other_sshfp.impl_->algorithm_) {
         return (-1);
-    } else if (algorithm_ > other_sshfp.algorithm_) {
+    } else if (impl_->algorithm_ > other_sshfp.impl_->algorithm_) {
         return (1);
     }
 
-    if (fingerprint_type_ < other_sshfp.fingerprint_type_) {
+    if (impl_->fingerprint_type_ < other_sshfp.impl_->fingerprint_type_) {
         return (-1);
-    } else if (fingerprint_type_ > other_sshfp.fingerprint_type_) {
+    } else if (impl_->fingerprint_type_ >
+               other_sshfp.impl_->fingerprint_type_) {
         return (1);
     }
 
-    const size_t this_len = fingerprint_.size();
-    const size_t other_len = other_sshfp.fingerprint_.size();
+    const size_t this_len = impl_->fingerprint_.size();
+    const size_t other_len = other_sshfp.impl_->fingerprint_.size();
     const size_t cmplen = min(this_len, other_len);
 
     if (cmplen > 0) {
-        const int cmp = memcmp(&fingerprint_[0], &other_sshfp.fingerprint_[0],
+        const int cmp = memcmp(&impl_->fingerprint_[0],
+                               &other_sshfp.impl_->fingerprint_[0],
                                cmplen);
         if (cmp != 0) {
             return (cmp);
@@ -168,17 +285,17 @@ SSHFP::compare(const Rdata& other) const {
 
 uint8_t
 SSHFP::getAlgorithmNumber() const {
-    return (algorithm_);
+    return (impl_->algorithm_);
 }
 
 uint8_t
 SSHFP::getFingerprintType() const {
-    return (fingerprint_type_);
+    return (impl_->fingerprint_type_);
 }
 
 size_t
 SSHFP::getFingerprintLen() const {
-    return (fingerprint_.size());
+    return (impl_->fingerprint_.size());
 }
 
 // END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/sshfp_44.h b/src/lib/dns/rdata/generic/sshfp_44.h
index d9ebea4..28ce0f3 100644
--- a/src/lib/dns/rdata/generic/sshfp_44.h
+++ b/src/lib/dns/rdata/generic/sshfp_44.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -28,12 +28,17 @@
 
 // BEGIN_RDATA_NAMESPACE
 
+struct SSHFPImpl;
+
 class SSHFP : public Rdata {
 public:
     // BEGIN_COMMON_MEMBERS
     // END_COMMON_MEMBERS
 
-    SSHFP(uint8_t algorithm, uint8_t fingerprint_type, const std::string& fingerprint);
+    SSHFP(uint8_t algorithm, uint8_t fingerprint_type,
+          const std::string& fingerprint);
+    SSHFP& operator=(const SSHFP& source);
+    ~SSHFP();
 
     ///
     /// Specialized methods
@@ -43,11 +48,9 @@ public:
     size_t getFingerprintLen() const;
 
 private:
-    /// Note: this is a prototype version; we may reconsider
-    /// this representation later.
-    uint8_t algorithm_;
-    uint8_t fingerprint_type_;
-    std::vector<uint8_t> fingerprint_;
+    SSHFPImpl* constructFromLexer(MasterLexer& lexer);
+
+    SSHFPImpl* impl_;
 };
 
 // END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/hs_4/a_1.cc b/src/lib/dns/rdata/hs_4/a_1.cc
index 3d13a9e..5e2852f 100644
--- a/src/lib/dns/rdata/hs_4/a_1.cc
+++ b/src/lib/dns/rdata/hs_4/a_1.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -31,6 +31,12 @@ A::A(const std::string&) {
     // TBD
 }
 
+A::A(MasterLexer&, const Name*,
+     MasterLoader::Options, MasterLoaderCallbacks&)
+{
+    // TBD
+}
+
 A::A(InputBuffer&, size_t) {
     // TBD
 }
diff --git a/src/lib/dns/rrparamregistry-placeholder.cc b/src/lib/dns/rrparamregistry-placeholder.cc
index 5960759..ae735bc 100644
--- a/src/lib/dns/rrparamregistry-placeholder.cc
+++ b/src/lib/dns/rrparamregistry-placeholder.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -41,35 +41,6 @@ using namespace isc::dns::rdata;
 namespace isc {
 namespace dns {
 
-namespace rdata {
-
-RdataPtr
-AbstractRdataFactory::create(MasterLexer& lexer, const Name*,
-                             MasterLoader::Options,
-                             MasterLoaderCallbacks&) const
-{
-    std::string s;
-
-    while (true) {
-        const MasterToken& token = lexer.getNextToken();
-        if ((token.getType() == MasterToken::END_OF_FILE) ||
-            (token.getType() == MasterToken::END_OF_LINE)) {
-            lexer.ungetToken(); // let the upper layer handle the end-of token
-            break;
-        }
-
-        if (!s.empty()) {
-            s += " ";
-        }
-
-        s += token.getString();
-    }
-
-    return (create(s));
-}
-
-} // end of namespace isc::dns::rdata
-
 namespace {
 ///
 /// The following function and class are a helper to define case-insensitive
@@ -190,10 +161,8 @@ typedef map<RRTypeClass, RdataFactoryPtr> RdataFactoryMap;
 typedef map<RRType, RdataFactoryPtr> GenericRdataFactoryMap;
 
 template <typename T>
-class OldRdataFactory : public AbstractRdataFactory {
+class RdataFactory : public AbstractRdataFactory {
 public:
-    using AbstractRdataFactory::create;
-
     virtual RdataPtr create(const string& rdata_str) const
     {
         return (RdataPtr(new T(rdata_str)));
@@ -208,16 +177,11 @@ public:
     {
         return (RdataPtr(new T(dynamic_cast<const T&>(source))));
     }
-};
-
-template <typename T>
-class RdataFactory : public OldRdataFactory<T> {
-public:
-    using OldRdataFactory<T>::create;
 
     virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
                             MasterLoader::Options options,
-                            MasterLoaderCallbacks& callbacks) const {
+                            MasterLoaderCallbacks& callbacks) const
+    {
         return (RdataPtr(new T(lexer, origin, options, callbacks)));
     }
 };
diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h
index bf86436..1d59e01 100644
--- a/src/lib/dns/rrparamregistry.h
+++ b/src/lib/dns/rrparamregistry.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -55,11 +55,11 @@ namespace rdata {
 /// \brief The \c AbstractRdataFactory class is an abstract base class to
 /// encapsulate a set of Rdata factory methods in a polymorphic way.
 ///
-/// An external developers who want to introduce a new or experimental RR type
-/// are expected to define a corresponding derived class of \c
+/// An external developer who wants to introduce a new or experimental RR type
+/// is expected to define a corresponding derived class of \c
 /// AbstractRdataFactory and register it via \c RRParamRegistry.
 ///
-/// For other users of this API normally do not have to care about this class
+/// Other users of this API normally do not have to care about this class
 /// or its derived classes; this class is generally intended to be used
 /// as an internal utility of the API implementation.
 class AbstractRdataFactory {
@@ -125,16 +125,9 @@ public:
     /// of a specific RR type and class for \c RRParamRegistry::createRdata()
     /// that uses \c MasterLexer.  See its description for the expected
     /// behavior and meaning of the parameters.
-    ///
-    /// \note Right now this is not defined as a pure virtual method and
-    /// provides the default implementation.  This is an intermediate
-    /// workaround until we implement the underlying constructor for all
-    /// supported \c Rdata classes; once it's completed the workaround
-    /// default implementation should be removed and this method should become
-    /// pure virtual.
     virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
                             MasterLoader::Options options,
-                            MasterLoaderCallbacks& callbacks) const;
+                            MasterLoaderCallbacks& callbacks) const = 0;
     //@}
 };
 
diff --git a/src/lib/dns/tests/rdata_minfo_unittest.cc b/src/lib/dns/tests/rdata_minfo_unittest.cc
index 2f717fe..3ce6a6c 100644
--- a/src/lib/dns/tests/rdata_minfo_unittest.cc
+++ b/src/lib/dns/tests/rdata_minfo_unittest.cc
@@ -1,6 +1,6 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
 //
-// Permission to use, copy, modify, and/or distribute this software for generic
+// 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.
 //
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <string>
+
 #include <util/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
@@ -27,22 +29,62 @@
 
 using isc::UnitTestUtil;
 using namespace std;
-using namespace isc::dns;
 using namespace isc::util;
+using namespace isc::dns;
 using namespace isc::dns::rdata;
 
-// minfo text
-const char* const minfo_txt = "rmailbox.example.com. emailbox.example.com.";
-const char* const minfo_txt2 = "root.example.com. emailbox.example.com.";
-const char* const too_long_label = "01234567890123456789012345678901234567"
-                                   "89012345678901234567890123";
-
 namespace {
 class Rdata_MINFO_Test : public RdataTest {
-public:
+protected:
     Rdata_MINFO_Test():
-        rdata_minfo(string(minfo_txt)), rdata_minfo2(string(minfo_txt2)) {}
-
+        minfo_txt("rmailbox.example.com. emailbox.example.com."),
+        minfo_txt2("root.example.com. emailbox.example.com."),
+        too_long_label("01234567890123456789012345678901234567"
+                       "89012345678901234567890123."),
+        rdata_minfo(minfo_txt),
+        rdata_minfo2(minfo_txt2)
+    {}
+
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<generic::MINFO, isc::Exception, isc::Exception>(
+            rdata_str, rdata_minfo, false, false);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <generic::MINFO, InvalidRdataText, MasterLexer::LexerError>(
+            rdata_str, rdata_minfo, true, true);
+    }
+
+    void checkFromText_TooLongLabel(const string& rdata_str) {
+        checkFromText<generic::MINFO, TooLongLabel, TooLongLabel>(
+            rdata_str, rdata_minfo, true, true);
+    }
+
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText<generic::MINFO, InvalidRdataText, isc::Exception>(
+            rdata_str, rdata_minfo, true, false);
+    }
+
+    void checkFromText_EmptyLabel(const string& rdata_str) {
+        checkFromText<generic::MINFO, EmptyLabel, EmptyLabel>(
+            rdata_str, rdata_minfo, true, true);
+    }
+
+    void checkFromText_MissingOrigin(const string& rdata_str) {
+        checkFromText
+            <generic::MINFO, MissingNameOrigin, MissingNameOrigin>(
+                rdata_str, rdata_minfo, true, true);
+    }
+
+    void checkFromText_Origin(const string& rdata_str, const Name* origin) {
+        checkFromText<generic::MINFO, MissingNameOrigin, isc::Exception>(
+            rdata_str, rdata_minfo, true, false, origin);
+    }
+
+    const string minfo_txt;
+    const string minfo_txt2;
+    const string too_long_label;
     const generic::MINFO rdata_minfo;
     const generic::MINFO rdata_minfo2;
 };
@@ -54,24 +96,35 @@ TEST_F(Rdata_MINFO_Test, createFromText) {
 
     EXPECT_EQ(Name("root.example.com."), rdata_minfo2.getRmailbox());
     EXPECT_EQ(Name("emailbox.example.com."), rdata_minfo2.getEmailbox());
+
+    checkFromText_None(minfo_txt);
+
+    // origin defined for lexer constructor, but not string constructor
+    const Name origin("example.com");
+    checkFromText_Origin("rmailbox emailbox", &origin);
+
+    // lexer constructor accepts extra text, but string constructor doesn't
+    checkFromText_BadString("rmailbox.example.com. emailbox.example.com. "
+                            "extra.example.com.");
 }
 
 TEST_F(Rdata_MINFO_Test, badText) {
-    // incomplete text
-    EXPECT_THROW(generic::MINFO("root.example.com."),
-                 InvalidRdataText);
-    // number of fields (must be 2) is incorrect
-    EXPECT_THROW(generic::MINFO("root.example.com emailbox.example.com. "
-                                "example.com."),
-                 InvalidRdataText);
-    // bad rmailbox name
-    EXPECT_THROW(generic::MINFO("root.example.com. emailbox.example.com." +
-                                string(too_long_label)),
-                 TooLongLabel);
-    // bad emailbox name
-    EXPECT_THROW(generic::MINFO("root.example.com."  +
-                          string(too_long_label) + " emailbox.example.com."),
-                 TooLongLabel);
+    // too long names
+    checkFromText_TooLongLabel("root.example.com."  + too_long_label +
+                               " emailbox.example.com.");
+    checkFromText_TooLongLabel("root.example.com. emailbox.example.com." +
+                               too_long_label);
+
+    // invalid names
+    checkFromText_EmptyLabel("root..example.com. emailbox.example.com.");
+    checkFromText_EmptyLabel("root.example.com. emailbox..example.com.");
+
+    // missing name
+    checkFromText_LexerError("root.example.com.");
+
+    // missing origin
+    checkFromText_MissingOrigin("root.example.com emailbox.example.com.");
+    checkFromText_MissingOrigin("root.example.com. emailbox.example.com");
 }
 
 TEST_F(Rdata_MINFO_Test, createFromWire) {
@@ -103,12 +156,6 @@ TEST_F(Rdata_MINFO_Test, createFromWire) {
                  DNSMessageFORMERR);
 }
 
-TEST_F(Rdata_MINFO_Test, createFromLexer) {
-    EXPECT_EQ(0, rdata_minfo.compare(
-        *test::createRdataUsingLexer(RRType::MINFO(), RRClass::IN(),
-                                     minfo_txt)));
-}
-
 TEST_F(Rdata_MINFO_Test, assignment) {
     generic::MINFO copy((string(minfo_txt2)));
     copy = rdata_minfo;
diff --git a/src/lib/dns/tests/rdata_rp_unittest.cc b/src/lib/dns/tests/rdata_rp_unittest.cc
index 5508d9c..38bec04 100644
--- a/src/lib/dns/tests/rdata_rp_unittest.cc
+++ b/src/lib/dns/tests/rdata_rp_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -41,6 +41,38 @@ protected:
         obuffer(0)
     {}
 
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<generic::RP, isc::Exception, isc::Exception>(
+            rdata_str, rdata_rp, false, false);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <generic::RP, InvalidRdataText, MasterLexer::LexerError>(
+                rdata_str, rdata_rp, true, true);
+    }
+
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText<generic::RP, InvalidRdataText, isc::Exception>(
+            rdata_str, rdata_rp, true, false);
+    }
+
+    void checkFromText_EmptyLabel(const string& rdata_str) {
+        checkFromText<generic::RP, EmptyLabel, EmptyLabel>(
+            rdata_str, rdata_rp, true, true);
+    }
+
+    void checkFromText_MissingOrigin(const string& rdata_str) {
+        checkFromText
+            <generic::RP, MissingNameOrigin, MissingNameOrigin>(
+                rdata_str, rdata_rp, true, true);
+    }
+
+    void checkFromText_Origin(const string& rdata_str, const Name* origin) {
+        checkFromText<generic::RP, MissingNameOrigin, isc::Exception>(
+            rdata_str, rdata_rp, true, false, origin);
+    }
+
     const Name mailbox_name, text_name;
     const generic::RP rdata_rp; // commonly used test RDATA
     OutputBuffer obuffer;
@@ -52,17 +84,28 @@ TEST_F(Rdata_RP_Test, createFromText) {
     EXPECT_EQ(mailbox_name, rdata_rp.getMailbox());
     EXPECT_EQ(text_name, rdata_rp.getText());
 
-    // Invalid textual input cases follow:
-    // names are invalid
-    EXPECT_THROW(generic::RP("bad..name. rp-text.example.com"), EmptyLabel);
-    EXPECT_THROW(generic::RP("mailbox.example.com. bad..name"), EmptyLabel);
+    checkFromText_None("root.example.com. rp-text.example.com.");
+
+    // origin defined for lexer constructor, but not string constructor
+    const Name origin("example.com");
+    checkFromText_Origin("root rp-text", &origin);
+
+    // lexer constructor accepts extra text, but string constructor doesn't
+    checkFromText_BadString("root.example.com. rp-text.example.com. "
+                            "extra.example.com.");
+}
+
+TEST_F(Rdata_RP_Test, badText) {
+    // invalid names
+    checkFromText_EmptyLabel("root..example.com. rp-text.example.com.");
+    checkFromText_EmptyLabel("root.example.com. rp-text..example.com.");
 
     // missing field
-    EXPECT_THROW(generic::RP("mailbox.example.com."), InvalidRdataText);
+    checkFromText_LexerError("root.example.com.");
 
-    // redundant field
-    EXPECT_THROW(generic::RP("mailbox.example.com. rp-text.example.com. "
-                             "redundant.example."), InvalidRdataText);
+    // missing origin
+    checkFromText_MissingOrigin("root.example.com rp-text.example.com.");
+    checkFromText_MissingOrigin("root.example.com. rp-text.example.com");
 }
 
 TEST_F(Rdata_RP_Test, createFromWire) {
@@ -106,17 +149,6 @@ TEST_F(Rdata_RP_Test, createFromParams) {
     EXPECT_EQ(text_name, generic::RP(mailbox_name, text_name).getText());
 }
 
-TEST_F(Rdata_RP_Test, createFromLexer) {
-    EXPECT_EQ(0, rdata_rp.compare(
-        *test::createRdataUsingLexer(RRType::RP(), RRClass::IN(),
-                                     "root.example.com. "
-                                     "rp-text.example.com.")));
-
-    // Exceptions cause NULL to be returned.
-    EXPECT_FALSE(test::createRdataUsingLexer(RRType::RP(), RRClass::IN(),
-                                             "mailbox.example.com."));
-}
-
 TEST_F(Rdata_RP_Test, toWireBuffer) {
     // construct expected data
     UnitTestUtil::readWireData("rdata_rp_toWire1.wire", expected_wire);
diff --git a/src/lib/dns/tests/rdata_sshfp_unittest.cc b/src/lib/dns/tests/rdata_sshfp_unittest.cc
index 6c13ad9..b85dfa5 100644
--- a/src/lib/dns/tests/rdata_sshfp_unittest.cc
+++ b/src/lib/dns/tests/rdata_sshfp_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -30,17 +30,50 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_SSHFP_Test : public RdataTest {
-    // there's nothing to specialize
+protected:
+        Rdata_SSHFP_Test() :
+            sshfp_txt("2 1 123456789abcdef67890123456789abcdef67890"),
+            rdata_sshfp(sshfp_txt)
+        {}
+
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<generic::SSHFP, isc::Exception, isc::Exception>(
+            rdata_str, rdata_sshfp, false, false);
+    }
+
+    void checkFromText_InvalidText(const string& rdata_str) {
+        checkFromText<generic::SSHFP, InvalidRdataText, InvalidRdataText>(
+            rdata_str, rdata_sshfp, true, true);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <generic::SSHFP, InvalidRdataText, MasterLexer::LexerError>(
+                rdata_str, rdata_sshfp, true, true);
+    }
+
+    void checkFromText_BadValue(const string& rdata_str) {
+        checkFromText<generic::SSHFP, InvalidRdataText, BadValue>(
+            rdata_str, rdata_sshfp, true, true);
+    }
+
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText
+            <generic::SSHFP, InvalidRdataText, isc::Exception>(
+                rdata_str, rdata_sshfp, true, false);
+    }
+
+    const string sshfp_txt;
+    const generic::SSHFP rdata_sshfp;
 };
 
-const string sshfp_txt("2 1 123456789abcdef67890123456789abcdef67890");
-const generic::SSHFP rdata_sshfp(2, 1, "123456789abcdef67890123456789abcdef67890");
 const uint8_t rdata_sshfp_wiredata[] = {
     // algorithm
     0x02,
@@ -56,22 +89,23 @@ const uint8_t rdata_sshfp_wiredata[] = {
 
 TEST_F(Rdata_SSHFP_Test, createFromText) {
     // Basic test
-    const generic::SSHFP rdata_sshfp2(sshfp_txt);
-    EXPECT_EQ(0, rdata_sshfp2.compare(rdata_sshfp));
+    checkFromText_None(sshfp_txt);
 
     // With different spacing
-    const generic::SSHFP rdata_sshfp3("2 1   123456789abcdef67890123456789abcdef67890");
-    EXPECT_EQ(0, rdata_sshfp3.compare(rdata_sshfp));
+    checkFromText_None("2 1   123456789abcdef67890123456789abcdef67890");
 
     // Combination of lowercase and uppercase
-    const generic::SSHFP rdata_sshfp4("2 1   123456789ABCDEF67890123456789abcdef67890");
-    EXPECT_EQ(0, rdata_sshfp4.compare(rdata_sshfp));
-}
+    checkFromText_None("2 1 123456789ABCDEF67890123456789abcdef67890");
 
-TEST_F(Rdata_SSHFP_Test, createFromLexer) {
-    EXPECT_EQ(0, rdata_sshfp.compare(
-        *test::createRdataUsingLexer(RRType::SSHFP(), RRClass::IN(),
-                                     "2 1 123456789abcdef67890123456789abcdef67890")));
+    // spacing in the fingerprint field
+    checkFromText_None("2 1 123456789abcdef67890 123456789abcdef67890");
+
+    // multi-line fingerprint field
+    checkFromText_None("2 1 ( 123456789abcdef67890\n 123456789abcdef67890 )");
+
+    // string constructor throws if there's extra text,
+    // but lexer constructor doesn't
+    checkFromText_BadString(sshfp_txt + "\n" + sshfp_txt);
 }
 
 TEST_F(Rdata_SSHFP_Test, algorithmTypes) {
@@ -101,13 +135,30 @@ TEST_F(Rdata_SSHFP_Test, algorithmTypes) {
 }
 
 TEST_F(Rdata_SSHFP_Test, badText) {
-    EXPECT_THROW(const generic::SSHFP rdata_sshfp("1"), InvalidRdataText);
-    EXPECT_THROW(const generic::SSHFP rdata_sshfp("BUCKLE MY SHOES"), InvalidRdataText);
-    EXPECT_THROW(const generic::SSHFP rdata_sshfp("1 2 foo bar"), InvalidRdataText);
+    checkFromText_LexerError("1");
+    checkFromText_LexerError("ONE 2 123456789abcdef67890123456789abcdef67890");
+    checkFromText_LexerError("1 TWO 123456789abcdef67890123456789abcdef67890");
+    checkFromText_BadValue("1 2 BUCKLEMYSHOE");
+    checkFromText_BadValue(sshfp_txt + " extra text");
+
+    // yes, these are redundant to the last test cases in algorithmTypes
+    checkFromText_InvalidText(
+        "2345 1 123456789abcdef67890123456789abcdef67890");
+    checkFromText_InvalidText(
+        "2 1234 123456789abcdef67890123456789abcdef67890");
+
+    // negative values are trapped in the lexer rather than the constructor
+    checkFromText_LexerError("-2 1 123456789abcdef67890123456789abcdef67890");
+    checkFromText_LexerError("2 -1 123456789abcdef67890123456789abcdef67890");
 }
 
-TEST_F(Rdata_SSHFP_Test, copy) {
-    const generic::SSHFP rdata_sshfp2(rdata_sshfp);
+TEST_F(Rdata_SSHFP_Test, copyAndAssign) {
+    // Copy construct
+    generic::SSHFP rdata_sshfp2(rdata_sshfp);
+    EXPECT_EQ(0, rdata_sshfp.compare(rdata_sshfp2));
+
+    // Assignment, mainly to confirm it doesn't cause disruption.
+    rdata_sshfp2 = rdata_sshfp;
     EXPECT_EQ(0, rdata_sshfp.compare(rdata_sshfp2));
 }
 
@@ -160,6 +211,12 @@ TEST_F(Rdata_SSHFP_Test, createFromWire) {
                  InvalidBufferPosition);
 }
 
+TEST_F(Rdata_SSHFP_Test, createFromParams) {
+    const generic::SSHFP rdata_sshfp2(
+        2, 1, "123456789abcdef67890123456789abcdef67890");
+    EXPECT_EQ(0, rdata_sshfp2.compare(rdata_sshfp));
+}
+
 TEST_F(Rdata_SSHFP_Test, toText) {
     EXPECT_TRUE(boost::iequals(sshfp_txt, rdata_sshfp.toText()));
 
diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc
index df35842..d351b40 100644
--- a/src/lib/dns/tests/rdata_tsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_tsig_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -23,6 +23,7 @@
 #include <dns/rdataclass.h>
 #include <dns/rrclass.h>
 #include <dns/rrtype.h>
+#include <dns/tsigerror.h>
 
 #include <gtest/gtest.h>
 
@@ -31,34 +32,84 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::util;
 using namespace isc::dns::rdata;
 
 namespace {
+
 class Rdata_TSIG_Test : public RdataTest {
 protected:
-    vector<uint8_t> expect_data;
-};
+    Rdata_TSIG_Test() :
+	// no MAC or Other Data
+        valid_text1("hmac-md5.sig-alg.reg.int. 1286779327 300 "
+                    "0 16020 BADKEY 0"),
+	// MAC but no Other Data
+        valid_text2("hmac-sha256. 1286779327 300 12 "
+                    "FAKEFAKEFAKEFAKE 16020 BADSIG 0"),
+	// MAC and Other Data
+        valid_text3("hmac-sha1. 1286779327 300 12 "
+                    "FAKEFAKEFAKEFAKE 16020 BADTIME 6 FAKEFAKE"),
+	// MAC and Other Data (with Error that doesn't expect Other Data)
+        valid_text4("hmac-sha1. 1286779327 300 12 "
+                    "FAKEFAKEFAKEFAKE 16020 BADSIG 6 FAKEFAKE"),
+	// numeric error code
+        valid_text5("hmac-sha256. 1286779327 300 12 "
+                    "FAKEFAKEFAKEFAKE 16020 2845 0"),
+        rdata_tsig(valid_text1)
+    {}
+
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<any::TSIG, isc::Exception, isc::Exception>(
+            rdata_str, rdata_tsig, false, false);
+    }
+
+    void checkFromText_InvalidText(const string& rdata_str) {
+        checkFromText<any::TSIG, InvalidRdataText, InvalidRdataText>(
+            rdata_str, rdata_tsig, true, true);
+    }
 
-const char* const valid_text1 = "hmac-md5.sig-alg.reg.int. 1286779327 300 "
-    "0 16020 BADKEY 0";
-const char* const valid_text2 = "hmac-sha256. 1286779327 300 12 "
-    "FAKEFAKEFAKEFAKE 16020 BADSIG 0";
+    void checkFromText_BadValue(const string& rdata_str) {
+        checkFromText<any::TSIG, BadValue, BadValue>(
+            rdata_str, rdata_tsig, true, true);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <any::TSIG, InvalidRdataText, MasterLexer::LexerError>(
+                rdata_str, rdata_tsig, true, true);
+    }
 
-const char* const valid_text3 = "hmac-sha1. 1286779327 300 12 "
-    "FAKEFAKEFAKEFAKE 16020 BADTIME 6 FAKEFAKE";
-const char* const valid_text4 = "hmac-sha1. 1286779327 300 12 "
-    "FAKEFAKEFAKEFAKE 16020 BADSIG 6 FAKEFAKE";
-const char* const valid_text5 = "hmac-sha256. 1286779327 300 12 "
-    "FAKEFAKEFAKEFAKE 16020 2845 0"; // using numeric error code
-const char* const too_long_label = "012345678901234567890123456789"
-    "0123456789012345678901234567890123";
+    void checkFromText_TooLongLabel(const string& rdata_str) {
+        checkFromText<any::TSIG, TooLongLabel, TooLongLabel>(
+            rdata_str, rdata_tsig, true, true);
+    }
 
-// commonly used test RDATA
-const any::TSIG rdata_tsig((string(valid_text1)));
+    void checkFromText_EmptyLabel(const string& rdata_str) {
+        checkFromText<any::TSIG, EmptyLabel, EmptyLabel>(
+            rdata_str, rdata_tsig, true, true);
+    }
 
-TEST_F(Rdata_TSIG_Test, createFromText) {
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText
+            <any::TSIG, InvalidRdataText, isc::Exception>(
+                rdata_str, rdata_tsig, true, false);
+    }
+
+    template <typename Output>
+    void toWireCommonChecks(Output& output) const;
+
+    const string valid_text1;
+    const string valid_text2;
+    const string valid_text3;
+    const string valid_text4;
+    const string valid_text5;
+    vector<uint8_t> expect_data;
+    const any::TSIG rdata_tsig; // commonly used test RDATA
+};
+
+TEST_F(Rdata_TSIG_Test, fromText) {
     // normal case.  it also tests getter methods.
     EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), rdata_tsig.getAlgorithm());
     EXPECT_EQ(1286779327, rdata_tsig.getTimeSigned());
@@ -66,59 +117,80 @@ TEST_F(Rdata_TSIG_Test, createFromText) {
     EXPECT_EQ(0, rdata_tsig.getMACSize());
     EXPECT_EQ(static_cast<void*>(NULL), rdata_tsig.getMAC());
     EXPECT_EQ(16020, rdata_tsig.getOriginalID());
-    EXPECT_EQ(17, rdata_tsig.getError()); // TODO: use constant
+    EXPECT_EQ(TSIGError::BAD_KEY_CODE, rdata_tsig.getError());
     EXPECT_EQ(0, rdata_tsig.getOtherLen());
     EXPECT_EQ(static_cast<void*>(NULL), rdata_tsig.getOtherData());
 
-    any::TSIG tsig2((string(valid_text2)));
+    any::TSIG tsig2(valid_text2);
     EXPECT_EQ(12, tsig2.getMACSize());
-    EXPECT_EQ(16, tsig2.getError()); // TODO: use constant
+    EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig2.getError());
 
-    any::TSIG tsig3((string(valid_text3)));
+    any::TSIG tsig3(valid_text3);
     EXPECT_EQ(6, tsig3.getOtherLen());
 
     // The other data is unusual, but we don't reject it.
-    EXPECT_NO_THROW(any::TSIG(string(valid_text4)));
+    EXPECT_NO_THROW(any::TSIG tsig4(valid_text4));
 
     // numeric representation of TSIG error
-    any::TSIG tsig5((string(valid_text5)));
+    any::TSIG tsig5(valid_text5);
     EXPECT_EQ(2845, tsig5.getError());
 
-    //
-    // invalid cases
-    //
-    // there's a garbage parameter at the end
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 BADKEY 0 0"), InvalidRdataText);
-    // input is too short
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 BADKEY"), InvalidRdataText);
+    // not fully qualified algorithm name
+    any::TSIG tsig1("hmac-md5.sig-alg.reg.int 1286779327 300 "
+                    "0 16020 BADKEY 0");
+    EXPECT_EQ(0, tsig1.compare(rdata_tsig));
+
+    // multi-line rdata
+    checkFromText_None("hmac-md5.sig-alg.reg.int. ( 1286779327 300 \n"
+                       "0 16020 BADKEY 0 )");
+};
+
+TEST_F(Rdata_TSIG_Test, badText) {
+    // too many fields
+    checkFromText_BadString(valid_text1 + " 0 0");
+    // not enough fields
+    checkFromText_LexerError("foo 0 0 0 0 BADKEY");
     // bad domain name
-    EXPECT_THROW(any::TSIG(string(too_long_label) + "0 0 0 0 BADKEY 0"),
-                 TooLongLabel);
+    checkFromText_TooLongLabel(
+        "0123456789012345678901234567890123456789012345678901234567890123"
+        " 0 0 0 0 BADKEY 0");
+    checkFromText_EmptyLabel("foo..bar 0 0 0 0 BADKEY");
     // time is too large (2814...6 is 2^48)
-    EXPECT_THROW(any::TSIG("foo 281474976710656 0 0 0 BADKEY 0"),
-                 InvalidRdataText);
+    checkFromText_InvalidText("foo 281474976710656 0 0 0 BADKEY 0");
     // invalid time (negative)
-    EXPECT_THROW(any::TSIG("foo -1 0 0 0 BADKEY 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo -1 0 0 0 BADKEY 0");
+    // invalid time (not a number)
+    checkFromText_InvalidText("foo TIME 0 0 0 BADKEY 0");
     // fudge is too large
-    EXPECT_THROW(any::TSIG("foo 0 65536 0 0 BADKEY 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 65536 0 0 BADKEY 0");
     // invalid fudge (negative)
-    EXPECT_THROW(any::TSIG("foo 0 -1 0 0 BADKEY 0"), InvalidRdataText);
+    checkFromText_LexerError("foo 0 -1 0 0 BADKEY 0");
+    // invalid fudge (not a number)
+    checkFromText_LexerError("foo 0 FUDGE 0 0 BADKEY 0");
     // MAC size is too large
-    EXPECT_THROW(any::TSIG("foo 0 0 65536 0 BADKEY 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 65536 0 BADKEY 0");
+    // invalide MAC size (negative)
+    checkFromText_LexerError("foo 0 0 -1 0 BADKEY 0");
+    // invalid MAC size (not a number)
+    checkFromText_LexerError("foo 0 0 MACSIZE 0 BADKEY 0");
     // MAC size and MAC mismatch
-    EXPECT_THROW(any::TSIG("foo 0 0 9 FAKE 0 BADKEY 0"), InvalidRdataText);
-    EXPECT_THROW(any::TSIG("foo 0 0 0 FAKE 0 BADKEY 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 9 FAKE 0 BADKEY 0");
     // MAC is bad base64
-    EXPECT_THROW(any::TSIG("foo 0 0 3 FAK= 0 BADKEY 0"), isc::BadValue);
+    checkFromText_BadValue("foo 0 0 3 FAK= 0 BADKEY 0");
     // Unknown error code
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 TEST 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 0 0 TEST 0");
     // Numeric error code is too large
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 65536 0"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 0 0 65536 0");
+    // Numeric error code is negative
+    checkFromText_InvalidText("foo 0 0 0 0 -1 0");
     // Other len is too large
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 NOERROR 65536 FAKE"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 0 0 NOERROR 65536 FAKE");
+    // Other len is negative
+    checkFromText_LexerError("foo 0 0 0 0 NOERROR -1 FAKE");
+    // invalid Other len
+    checkFromText_LexerError("foo 0 0 0 0 NOERROR LEN FAKE");
     // Other len and data mismatch
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 NOERROR 9 FAKE"), InvalidRdataText);
-    EXPECT_THROW(any::TSIG("foo 0 0 0 0 NOERROR 0 FAKE"), InvalidRdataText);
+    checkFromText_InvalidText("foo 0 0 0 0 NOERROR 9 FAKE");
 }
 
 void
@@ -221,12 +293,12 @@ TEST_F(Rdata_TSIG_Test, createFromParams) {
 
     const uint8_t fake_data[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84,
                                   0x14, 0x02, 0x84, 0x14, 0x02, 0x84 }; 
-    EXPECT_EQ(0, any::TSIG((string(valid_text2))).compare(
+    EXPECT_EQ(0, any::TSIG(valid_text2).compare(
                   any::TSIG(Name("hmac-sha256"), 1286779327, 300, 12,
                             fake_data, 16020, 16, 0, NULL)));
 
     const uint8_t fake_data2[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84 };
-    EXPECT_EQ(0, any::TSIG((string(valid_text3))).compare(
+    EXPECT_EQ(0, any::TSIG(valid_text3).compare(
                   any::TSIG(Name("hmac-sha1"), 1286779327, 300, 12,
                             fake_data, 16020, 18, 6, fake_data2)));
 
@@ -247,24 +319,14 @@ TEST_F(Rdata_TSIG_Test, createFromParams) {
                  isc::InvalidParameter);
 }
 
-TEST_F(Rdata_TSIG_Test, createFromLexer) {
-    EXPECT_EQ(0, rdata_tsig.compare(
-        *test::createRdataUsingLexer(RRType::TSIG(), RRClass::ANY(),
-                                     valid_text1)));
-
-    // Exceptions cause NULL to be returned.
-    EXPECT_FALSE(test::createRdataUsingLexer(RRType::TSIG(), RRClass::ANY(),
-                                             "foo 0 0 0 0 BADKEY 0 0"));
-}
-
 TEST_F(Rdata_TSIG_Test, assignment) {
-    any::TSIG copy((string(valid_text2)));
+    any::TSIG copy(valid_text2);
     copy = rdata_tsig;
     EXPECT_EQ(0, copy.compare(rdata_tsig));
 
     // Check if the copied data is valid even after the original is deleted
     any::TSIG* copy2 = new any::TSIG(rdata_tsig);
-    any::TSIG copy3((string(valid_text2)));
+    any::TSIG copy3(valid_text2);
     copy3 = *copy2;
     delete copy2;
     EXPECT_EQ(0, copy3.compare(rdata_tsig));
@@ -276,7 +338,7 @@ TEST_F(Rdata_TSIG_Test, assignment) {
 
 template <typename Output>
 void
-toWireCommonChecks(Output& output) {
+Rdata_TSIG_Test::toWireCommonChecks(Output& output) const {
     vector<uint8_t> expect_data;
 
     output.clear();
@@ -291,7 +353,7 @@ toWireCommonChecks(Output& output) {
 
     expect_data.clear();
     output.clear();
-    any::TSIG(string(valid_text2)).toWire(output);
+    any::TSIG(valid_text2).toWire(output);
     UnitTestUtil::readWireData("rdata_tsig_toWire2.wire", expect_data);
     expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
@@ -300,7 +362,7 @@ toWireCommonChecks(Output& output) {
 
     expect_data.clear();
     output.clear();
-    any::TSIG(string(valid_text3)).toWire(output);
+    any::TSIG(valid_text3).toWire(output);
     UnitTestUtil::readWireData("rdata_tsig_toWire3.wire", expect_data);
     expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
@@ -339,10 +401,10 @@ TEST_F(Rdata_TSIG_Test, toWireRenderer) {
 }
 
 TEST_F(Rdata_TSIG_Test, toText) {
-    EXPECT_EQ(string(valid_text1), rdata_tsig.toText());
-    EXPECT_EQ(string(valid_text2), any::TSIG(string(valid_text2)).toText());
-    EXPECT_EQ(string(valid_text3), any::TSIG(string(valid_text3)).toText());
-    EXPECT_EQ(string(valid_text5), any::TSIG(string(valid_text5)).toText());
+    EXPECT_EQ(valid_text1, rdata_tsig.toText());
+    EXPECT_EQ(valid_text2, any::TSIG(valid_text2).toText());
+    EXPECT_EQ(valid_text3, any::TSIG(valid_text3).toText());
+    EXPECT_EQ(valid_text5, any::TSIG(valid_text5).toText());
 }
 
 TEST_F(Rdata_TSIG_Test, compare) {
diff --git a/src/lib/dns/tests/rrparamregistry_unittest.cc b/src/lib/dns/tests/rrparamregistry_unittest.cc
index 08e0af1..b0d43a8 100644
--- a/src/lib/dns/tests/rrparamregistry_unittest.cc
+++ b/src/lib/dns/tests/rrparamregistry_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -108,13 +108,16 @@ TEST_F(RRParamRegistryTest, addError) {
 
 class TestRdataFactory : public AbstractRdataFactory {
 public:
-    using AbstractRdataFactory::create;
     virtual RdataPtr create(const string& rdata_str) const
     { return (RdataPtr(new in::A(rdata_str))); }
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
     { return (RdataPtr(new in::A(buffer, rdata_len))); }
     virtual RdataPtr create(const Rdata& source) const
     { return (RdataPtr(new in::A(dynamic_cast<const in::A&>(source)))); }
+    virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
+                            MasterLoader::Options options,
+                            MasterLoaderCallbacks& callbacks) const
+    { return (RdataPtr(new in::A(lexer, origin, options, callbacks))); }
 };
 
 TEST_F(RRParamRegistryTest, addRemoveFactory) {



More information about the bind10-changes mailing list