BIND 10 trac2096, updated. b97f714d59f1990b62a01e5ca0c5f1c95834ed7c [2096] Reader and encoder merged to the same file

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Aug 24 09:47:43 UTC 2012


The branch, trac2096 has been updated
       via  b97f714d59f1990b62a01e5ca0c5f1c95834ed7c (commit)
      from  d9e1e79ffff5bf77517474d811ed7cfece349559 (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 b97f714d59f1990b62a01e5ca0c5f1c95834ed7c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri Aug 24 11:45:40 2012 +0200

    [2096] Reader and encoder merged to the same file
    
    They share some bit of private stuff, so we get rid of the private
    header. We still have a bit of the code included from outside, but this
    is only for tests (and it's not a header).

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

Summary of changes:
 src/lib/datasrc/memory/Makefile.am                 |    5 +-
 src/lib/datasrc/memory/benchmarks/.gitignore       |    1 +
 .../memory/benchmarks/rdata_reader_bench.cc        |    3 +-
 src/lib/datasrc/memory/rdata_encoder.cc            |  306 ----------
 src/lib/datasrc/memory/rdata_field.cc              |  211 -------
 src/lib/datasrc/memory/rdata_field.h               |  161 -----
 src/lib/datasrc/memory/rdata_reader.cc             |  169 ------
 src/lib/datasrc/memory/rdata_reader.h              |  237 --------
 src/lib/datasrc/memory/rdata_serialization.cc      |  635 ++++++++++++++++++++
 .../{rdata_encoder.h => rdata_serialization.h}     |  214 ++++++-
 src/lib/datasrc/memory/rdata_serialization_priv.cc |   64 ++
 .../memory/tests/rdata_serialization_unittest.cc   |   20 +-
 12 files changed, 928 insertions(+), 1098 deletions(-)
 create mode 100644 src/lib/datasrc/memory/benchmarks/.gitignore
 delete mode 100644 src/lib/datasrc/memory/rdata_encoder.cc
 delete mode 100644 src/lib/datasrc/memory/rdata_field.cc
 delete mode 100644 src/lib/datasrc/memory/rdata_field.h
 delete mode 100644 src/lib/datasrc/memory/rdata_reader.cc
 delete mode 100644 src/lib/datasrc/memory/rdata_reader.h
 create mode 100644 src/lib/datasrc/memory/rdata_serialization.cc
 rename src/lib/datasrc/memory/{rdata_encoder.h => rdata_serialization.h} (51%)
 create mode 100644 src/lib/datasrc/memory/rdata_serialization_priv.cc

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 0ec2add..16e7fd0 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -11,7 +11,6 @@ CLEANFILES = *.gcno *.gcda datasrc_messages.h datasrc_messages.cc
 noinst_LTLIBRARIES = libdatasrc_memory.la
 
 libdatasrc_memory_la_SOURCES = \
-	rdata_encoder.h rdata_encoder.cc \
-	rdata_field.h rdata_field.cc \
-	rdata_reader.h rdata_reader.cc \
+	rdata_serialization.h rdata_serialization.cc \
 	domaintree.h
+EXTRA_DIST  = rdata_serialization_priv.cc
diff --git a/src/lib/datasrc/memory/benchmarks/.gitignore b/src/lib/datasrc/memory/benchmarks/.gitignore
new file mode 100644
index 0000000..ea243a4
--- /dev/null
+++ b/src/lib/datasrc/memory/benchmarks/.gitignore
@@ -0,0 +1 @@
+/rdata_reader_bench
diff --git a/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
index e3fb396..4e6af56 100644
--- a/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
+++ b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
@@ -22,8 +22,7 @@
 #include <dns/rrclass.h>
 #include <dns/masterload.h>
 
-#include <datasrc/memory/rdata_encoder.h>
-#include <datasrc/memory/rdata_reader.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 #include <boost/bind.hpp>
 
diff --git a/src/lib/datasrc/memory/rdata_encoder.cc b/src/lib/datasrc/memory/rdata_encoder.cc
deleted file mode 100644
index 9b47b67..0000000
--- a/src/lib/datasrc/memory/rdata_encoder.cc
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright (C) 2012  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 "rdata_encoder.h"
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-
-#include <dns/name.h>
-#include <dns/labelsequence.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <cassert>
-#include <cstring>
-#include <vector>
-
-using namespace isc::dns;
-using std::vector;
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-namespace {
-
-// This class is a helper for RdataEncoder to divide the content of RDATA
-// fields for encoding by "abusing" the  message rendering logic.
-// The idea is to identify domain name fields in the writeName() method,
-// while keeping track of the size and position of other types of data
-// around the names.
-//
-// Technically, this use of inheritance may be considered a violation of
-// Liskov Substitution Principle in that it doesn't actually compress domain
-// names, and some of the methods are not expected to be used.
-// In fact, skip() or trim() may not be make much sense in this context.
-// Nevertheless we keep this idea at the moment.  Since the usage is limited
-// (it's only used within this file, and only used with \c Rdata variants),
-// it's hopefully an acceptable practice.
-class RdataFieldComposer : public AbstractMessageRenderer {
-public:
-    RdataFieldComposer() : last_data_pos_(0), encode_spec_(NULL),
-                           current_field_(0)
-    {}
-    virtual ~RdataFieldComposer() {}
-    virtual bool isTruncated() const { return (false); }
-    virtual size_t getLengthLimit() const { return (65535); }
-    virtual CompressMode getCompressMode() const { return (CASE_INSENSITIVE); }
-    virtual void setTruncated() {}
-    virtual void setLengthLimit(size_t) {}
-    virtual void setCompressMode(CompressMode) {}
-
-    // Called for each domain name in the RDATA, from the RDATA's toWire()
-    // implementation.
-    virtual void writeName(const Name& name, bool compress) {
-        // First, see if we have other data already stored in the renderer's
-        // buffer, and handle it appropriately.
-        updateOtherData();
-
-        // Then, we should still have a field in the spec, and it must be a
-        // domain name field.
-        if (current_field_ >= encode_spec_->field_count) {
-            isc_throw(BadValue,
-                      "RDATA encoder encounters an unexpected name data: " <<
-                      name);
-        }
-        const RdataFieldSpec& field =
-            encode_spec_->fields[current_field_++];
-        // Since we know we've passed any prior data field, the next field
-        // must be a domain name as long as it exists; otherwise it's a bug
-        // in the spec (not a bogus input).  So we assert() that condition.
-        assert(field.type == RdataFieldSpec::DOMAIN_NAME);
-
-        // It would be compressed iff the field has that attribute.
-        if (compress !=
-            ((field.name_attributes & NAMEATTR_COMPRESSIBLE) != 0)) {
-            isc_throw(BadValue, "RDATA encoder error, inconsistent name "
-                      "compression policy: " << name);
-        }
-
-        const LabelSequence labels(name);
-        labels.serialize(labels_placeholder_, sizeof(labels_placeholder_));
-        writeData(labels_placeholder_, labels.getSerializedLength());
-
-        last_data_pos_ += labels.getSerializedLength();
-    }
-    // Clear all internal states and resources for a new set of RDATA.
-    void clearLocal(const RdataEncodeSpec* encode_spec) {
-        AbstractMessageRenderer::clear();
-        encode_spec_ = encode_spec;
-        data_lengths_.clear();
-        last_data_pos_ = 0;
-    }
-    // Called at the beginning of an RDATA.
-    void startRdata() {
-        current_field_ = 0;
-    }
-    // Called at the end of an RDATA.
-    void endRdata() {
-        // Handle any remaining data (there should be no more name).  Then
-        // we should reach the end of the fields.
-        updateOtherData();
-        if (current_field_ != encode_spec_->field_count) {
-            isc_throw(BadValue,
-                      "RDATA encoder didn't find all expected fields");
-        }
-    }
-
-    // Hold the lengths of variable length fields, in the order of their
-    // appearance.  For convenience, allow the encoder to refer to it
-    // directly.
-    vector<uint16_t> data_lengths_;
-
-private:
-    // We use generict write* methods, with the exception of writeName.
-    // So new data can arrive without us knowing it, this considers all new
-    // data to be just data, checking consistency with the field spec, and
-    // if it contains variable-length field, record its length.
-    size_t last_data_pos_;
-    void updateOtherData() {
-        // If we've reached the end of the fields or we are expecting a
-        // domain name, there's nothing to do here.
-        if (current_field_ >= encode_spec_->field_count ||
-            encode_spec_->fields[current_field_].type ==
-            RdataFieldSpec::DOMAIN_NAME) {
-            return;
-        }
-
-        const size_t cur_pos = getLength();
-        const size_t data_len = cur_pos - last_data_pos_;
-
-        const RdataFieldSpec& field = encode_spec_->fields[current_field_];
-        if (field.type == RdataFieldSpec::FIXEDLEN_DATA) {
-            // The data length of a fixed length field must be the one
-            // specified in the field spec.
-            if (data_len != field.fixeddata_len) {
-                isc_throw(BadValue,
-                          "RDATA encoding: available data too short for the "
-                          "type");
-            }
-        } else {
-            // For encoding purposes, a variable-length data field is
-            // a single field covering all data, even if it may
-            // consist of multiple fields as DNS RDATA (e.g. TXT).
-            if (data_len > 0xffff) {
-                isc_throw(RdataEncodingError, "RDATA field is too large: "
-                          << data_len << " bytes");
-            }
-            data_lengths_.push_back(data_len);
-        }
-
-        ++current_field_;
-        last_data_pos_ = cur_pos;
-    }
-
-    // The RDATA field spec of the current session.  Set at the beginning of
-    // each session.
-    const RdataEncodeSpec* encode_spec_;
-    // the RDATA field (for encoding) currently handled.  Reset to 0 for
-    // each RDATA of the session.
-    size_t current_field_;
-    // Placeholder to convert a name object to a label sequence.
-    uint8_t labels_placeholder_[LabelSequence::MAX_SERIALIZED_LENGTH];
-};
-} // end of unnamed namespace
-
-struct RdataEncoder::RdataEncoderImpl {
-    RdataEncoderImpl() : encode_spec_(NULL), rrsig_buffer_(0),
-                         rdata_count_(0)
-    {}
-
-    const RdataEncodeSpec* encode_spec_; // encode spec of current RDATA set
-    RdataFieldComposer field_composer_;
-    util::OutputBuffer rrsig_buffer_;
-    size_t rdata_count_;
-    vector<uint16_t> rrsig_lengths_;
-};
-
-RdataEncoder::RdataEncoder() :
-    impl_(new RdataEncoderImpl)
-{}
-
-RdataEncoder::~RdataEncoder() {
-    delete impl_;
-}
-
-void
-RdataEncoder::start(RRClass rrclass, RRType rrtype) {
-    if (rrtype == RRType::RRSIG()) {
-        isc_throw(BadValue, "RRSIG cannot be encoded as main RDATA type");
-    }
-
-    impl_->encode_spec_ = &getRdataEncodeSpec(rrclass, rrtype);
-    impl_->field_composer_.clearLocal(impl_->encode_spec_);
-    impl_->rrsig_buffer_.clear();
-    impl_->rdata_count_ = 0;
-    impl_->rrsig_lengths_.clear();
-}
-
-void
-RdataEncoder::addRdata(const rdata::Rdata& rdata) {
-    if (impl_->encode_spec_ == NULL) {
-        isc_throw(InvalidOperation,
-                  "RdataEncoder::addRdata performed before start");
-    }
-
-    impl_->field_composer_.startRdata();
-    rdata.toWire(impl_->field_composer_);
-    impl_->field_composer_.endRdata();
-    ++impl_->rdata_count_;
-}
-
-void
-RdataEncoder::addSIGRdata(const rdata::Rdata& sig_rdata) {
-    if (impl_->encode_spec_ == NULL) {
-        isc_throw(InvalidOperation,
-                  "RdataEncoder::addSIGRdata performed before start");
-    }
-    const size_t cur_pos = impl_->rrsig_buffer_.getLength();
-    sig_rdata.toWire(impl_->rrsig_buffer_);
-    const size_t rrsig_datalen = impl_->rrsig_buffer_.getLength() - cur_pos;
-    if (rrsig_datalen > 0xffff) {
-        isc_throw(RdataEncodingError, "RRSIG is too large: "
-                  << rrsig_datalen << " bytes");
-    }
-    impl_->rrsig_lengths_.push_back(rrsig_datalen);
-}
-
-size_t
-RdataEncoder::getStorageLength() const {
-    if (impl_->encode_spec_ == NULL) {
-        isc_throw(InvalidOperation,
-                  "RdataEncoder::getStorageLength performed before start");
-    }
-
-    return (sizeof(uint16_t) * impl_->field_composer_.data_lengths_.size() +
-            sizeof(uint16_t) * impl_->rrsig_lengths_.size() +
-            impl_->rrsig_buffer_.getLength() +
-            impl_->field_composer_.getLength());
-}
-
-void
-RdataEncoder::encode(void* buf, size_t buf_len) const {
-    if (impl_->encode_spec_ == NULL) {
-        isc_throw(InvalidOperation,
-                  "RdataEncoder::encode performed before start");
-    }
-    if (buf == NULL) {
-        isc_throw(BadValue,
-                  "RdataEncoder::encode NULL buffer is given");
-    }
-    if (getStorageLength() > buf_len) {
-        isc_throw(BadValue, "RdataEncoder::encode short buffer given");
-    }
-
-    uint8_t* const dp_beg = reinterpret_cast<uint8_t*>(buf);
-    uint8_t* dp = dp_beg;
-    uint16_t* lenp = reinterpret_cast<uint16_t*>(buf);
-
-    // Encode list of lengths for variable length fields (if any)
-    if (!impl_->field_composer_.data_lengths_.empty()) {
-        const size_t varlen_fields_len =
-            impl_->field_composer_.data_lengths_.size() * sizeof(uint16_t);
-        std::memcpy(lenp, &impl_->field_composer_.data_lengths_[0],
-                    varlen_fields_len);
-        lenp += impl_->field_composer_.data_lengths_.size();
-        dp += varlen_fields_len;
-    }
-    // Encode list of lengths for RRSIGs (if any)
-    if (!impl_->rrsig_lengths_.empty()) {
-        const size_t rrsigs_len =
-            impl_->rrsig_lengths_.size() * sizeof(uint16_t);
-        std::memcpy(lenp, &impl_->rrsig_lengths_[0], rrsigs_len);
-        dp += rrsigs_len;
-    }
-    // Encode main RDATA
-    std::memcpy(dp, impl_->field_composer_.getData(),
-                impl_->field_composer_.getLength());
-    dp += impl_->field_composer_.getLength();
-    // Encode RRSIGs, if any
-    std::memcpy(dp, impl_->rrsig_buffer_.getData(),
-                impl_->rrsig_buffer_.getLength());
-    dp += impl_->rrsig_buffer_.getLength();
-
-    // The validation at the entrance must ensure this
-    assert(buf_len >= dp - dp_beg);
-}
-
-
-} // namespace memory
-} // namespace datasrc
-} // datasrc isc
diff --git a/src/lib/datasrc/memory/rdata_encoder.h b/src/lib/datasrc/memory/rdata_encoder.h
deleted file mode 100644
index 585a500..0000000
--- a/src/lib/datasrc/memory/rdata_encoder.h
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (C) 2012  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 DATASRC_MEMORY_RDATA_ENCODER_H
-#define DATASRC_MEMORY_RDATA_ENCODER_H 1
-
-#include <datasrc/memory/rdata_field.h>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/labelsequence.h>
-#include <dns/rdata.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <boost/function.hpp>
-#include <boost/noncopyable.hpp>
-
-#include <vector>
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-/// \brief General error in RDATA encoding.
-///
-/// This is thrown when \c RdataEncoder encounters a rare, unsupported
-/// situation. a method is called for a name or RRset which
-/// is not in or below the zone.
-class RdataEncodingError : public Exception {
-public:
-    RdataEncodingError(const char* file, size_t line, const char* what) :
-        Exception(file, line, what) {}
-};
-
-/// \brief RDATA encoder.
-///
-/// This class provides interfaces to encode a set of RDATA of a specific
-/// RR class and type, possibly with their RRSIG RDATAs, in a memory-efficient
-/// format.  In many cases these sets of RDATA come from a specific (signed
-/// or unsigned) RRset.
-///
-/// It is expected for a single \c RdataEncoder object to be used multiple
-/// times for different sets of RDATA, such as in loading an entire zone
-/// into memory.  Each encoding session begins with the \c start() method,
-/// which sets the context for the specific RR class and type to be encoded.
-/// Any number of calls to \c addRdata() or \c addSIGRdata() follow, each
-/// of which updates the internal state of the encoder with the encoding
-/// information for the given RDATA or RRSIG RDATA, respectively.
-/// The \c addRdata() is expected to be called with an
-/// \c isc::dns::rdata::Rdata object
-/// of the specified class and type, and \c addRdata() checks the consistency
-/// for the purpose of encoding (but it's not completely type safe; for
-/// example, it wouldn't distinguish TXT RDATA and HINFO RDATA.
-/// Likewise, an \c isc::dns::rdata::Rdata given to \c addSIGRdata() is
-/// expected to be of RRSIG, but the method does not check the assumption).
-///
-/// After passing the complete set of RDATA and their RRSIG, the application
-/// is expected to call \c getStorageLength() to know the size of storage
-/// that is sufficient to store all encoded data.  Normally the application
-/// would allocate a memory region of that size, and then call \c encode()
-/// with the prepared region.  The \c encode() method dumps encoded data
-/// to the given memory region.
-///
-/// The caller can reuse the \c RdataEncoder object for another set of RDATA
-/// by repeating the session from \c start().
-class RdataEncoder : boost::noncopyable {
-public:
-    /// \brief Default constructor.
-    RdataEncoder();
-
-    /// \brief The destrcutor.
-    ~RdataEncoder();
-
-    /// \brief Start the encoding session.
-    ///
-    /// It re-initializes the internal encoder state for a new encoding
-    /// session.  The \c rrclass and \c rrtype parameters specify the
-    /// type of RDATA to be encoded in the new session.  Note that if the
-    /// set of RDATA is signed, \c rrtype always specifies the "signed" type;
-    /// it must not be RRSIG.
-    ///
-    /// \throw BadValue RRSIG is specified for rrtype.
-    ///
-    /// \param rrclass The RR class of RDATA to be encoded in the session.
-    /// \param rrtype The RR type of RDATA to be encoded in the session.
-    void start(dns::RRClass rrclass, dns::RRType rrtype);
-
-    /// \brief Add an RDATA for encoding.
-    ///
-    /// This method updates internal state of the \c RdataEncoder() with the
-    /// given RDATA so it will be part of the encoded data in a subsequent
-    /// call to \c encode().
-    ///
-    /// The given \c rdata must be of the RR class and type specified at
-    /// the prior call to \c start().  This method checks the assumption
-    /// to some extent, but the check is not complete; this is generally
-    /// the responsibility of the caller.
-    ///
-    /// The caller can destroy \c rdata after this call is completed.
-    ///
-    /// \note This implementation does not support RDATA (or any subfield of
-    /// it) whose size exceeds 65535 bytes (max uint16_t value).  Such RDATA
-    /// may not necessarily be considered invalid in terms of protocol
-    /// specification, but in practice it's mostly useless because the
-    /// corresponding RR won't fit in any valid DNS message.
-    ///
-    /// As long as the \c rdata is of the correct type and its size is normal,
-    /// this method should normally be exception free.  If it throws, however,
-    /// it doesn't always provide the strong exception guarantee.  In general,
-    /// the caller needs to either destroy the encoder object or restart a
-    /// new session from \c start() should this method throws an exception.
-    ///
-    /// \throw InvalidOperation called before start().
-    /// \throw BadValue inconsistent data found.
-    /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
-    /// \throw std::bad_alloc Internal memory allocation failure.
-    ///
-    /// \param rdata An RDATA to be encoded in the session.
-    void addRdata(const dns::rdata::Rdata& rdata);
-
-    /// \brief Add an RRSIG RDATA for encoding.
-    ///
-    /// This method updates internal state of the \c RdataEncoder() with the
-    /// given RDATA, which is assumed to be of type RRSIG that covers the
-    /// type specified at the time of \c start() for the encoding session.
-    /// The corresponding data for the RRSIG RDATA will be encoded in a
-    /// subsequent call to \c encode().
-    ///
-    /// The passed \c sig_rdata is expected to be of type RRSIG and cover
-    /// the RR type specified at the call to \c start() to this encoding
-    /// session.  But this method does not check if it is the case at all;
-    /// it could even accept any type of RDATA as opaque data.  It's caller's
-    /// responsibility to ensure the assumption.
-    ///
-    /// The caller can destroy \c rdata after this call is completed.
-    ///
-    /// \note Like addRdata(), this implementation does not support
-    /// RRSIG RDATA whose size (in the form of wire format) exceeds 65535
-    /// bytes.
-    ///
-    /// The same note about exception safety as \c addRdata() applies.
-    ///
-    /// \throw InvalidOperation called before start().
-    /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
-    /// \throw std::bad_alloc Internal memory allocation failure.
-    ///
-    /// \param sig_rdata An RDATA to be encoded in the session.  Supposed to
-    /// be of type RRSIG.
-    void addSIGRdata(const dns::rdata::Rdata& sig_rdata);
-
-    /// \brief Return the length of space for encoding for the session.
-    ///
-    /// It returns the size of the encoded data that would be generated for
-    /// the set of RDATA (and RRSIGs) in the encoder at the call of this
-    /// method.  It's ensured that a buffer of that size can be safely passed
-    /// to \c encode() unless there's no other "add" method is called by then.
-    ///
-    /// As long as this method is called after start(), it never throws.
-    ///
-    /// \throw InvalidOperation called before start().
-    ///
-    /// \return The expected size of the encoded data at the time of the call.
-    size_t getStorageLength() const;
-
-    /// \brief Encode RDATAs of the session to a buffer.
-    ///
-    /// This method dumps encoded data for the stored set of RDATA and
-    /// their RRSIGs to a given buffer.  The buffer must have a size
-    /// at least as large as the return value of a prior call to
-    /// \c getStorageLength() (it may be larger than that).
-    ///
-    /// The given buffer must be aligned at the natural boundary for
-    /// 16-bit integers.  The method doesn't check this condition; it's
-    /// caller's responsibility to ensure that.  Note: the alignment
-    /// requirement may change in a future version of this implementation.
-    ///
-    /// As long as this method is called after start() and the buffer is
-    /// valid with a sufficient size, this method never throws.
-    ///
-    /// \throw InvalidOperation called before start().
-    /// \throw BadValue buffer is NULL or it's too short for the encoded data.
-    ///
-    /// \param buf A pointer to the buffer to which encoded data are to be
-    /// dumped.
-    /// \param buf_len The size of the buffer in bytes.
-    void encode(void* buf, size_t buf_len) const;
-
-private:
-    struct RdataEncoderImpl;
-    RdataEncoderImpl* impl_;
-};
-
-} // namespace memory
-} // namespace datasrc
-} // namespace isc
-
-#endif // DATASRC_MEMORY_RDATA_ENCODER_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/memory/rdata_field.cc b/src/lib/datasrc/memory/rdata_field.cc
deleted file mode 100644
index bc48a52..0000000
--- a/src/lib/datasrc/memory/rdata_field.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright (C) 2012  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 "rdata_field.h"
-
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <boost/static_assert.hpp>
-
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-namespace {
-
-// Many types of RDATA can be treated as a single-field, variable length
-// field (in terms of our encoding).  The following define such most general
-// form of field spec.
-const RdataFieldSpec generic_data_fields[] = {
-    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
-};
-const uint16_t n_generic_data_fields =
-    sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
-const RdataEncodeSpec generic_data_spec = {
-    n_generic_data_fields, 0, 1, generic_data_fields
-};
-
-// RDATA consist of a single IPv4 address field.
-const RdataFieldSpec single_ipv4_fields[] = {
-    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t), NAMEATTR_NONE}
-};
-const uint16_t n_ipv4_fields =
-    sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
-
-// RDATA consist of a single IPv6 address field.
-const RdataFieldSpec single_ipv6_fields[] = {
-    {RdataFieldSpec::FIXEDLEN_DATA, 16, NAMEATTR_NONE} // 128bits = 16 bytes
-};
-const uint16_t n_ipv6_fields =
-    sizeof(single_ipv6_fields) / sizeof(RdataFieldSpec);
-
-// There are several RR types that consist of a single domain name.
-const RdataFieldSpec single_noattr_name_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
-};
-const RdataFieldSpec single_compressible_name_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
-};
-const RdataFieldSpec single_compadditional_name_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0,
-     static_cast<RdataNameAttributes>(
-         static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
-         static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
-};
-const uint16_t n_single_name_fields =
-    sizeof(single_noattr_name_fields) / sizeof(RdataFieldSpec);
-
-// RDATA consisting of two names.  There are some of this type.
-const RdataFieldSpec double_compressible_name_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
-};
-const RdataFieldSpec double_noattr_name_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
-};
-const uint16_t n_double_name_fields =
-    sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
-
-// SOA specific: two compressible names + 5*32-bit data
-const RdataFieldSpec soa_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
-    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t) * 5, NAMEATTR_NONE}
-};
-const uint16_t n_soa_fields = sizeof(soa_fields) / sizeof(RdataFieldSpec);
-
-// MX specific: 16-bit data + compressible/additional name
-const RdataFieldSpec mx_fields[] = {
-    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
-    {RdataFieldSpec::DOMAIN_NAME, 0,
-     static_cast<RdataNameAttributes>(
-         static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
-         static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
-};
-const uint16_t n_mx_fields = sizeof(mx_fields) / sizeof(RdataFieldSpec);
-
-// AFSDB specific: 16-bit data + no-attribute name
-const RdataFieldSpec afsdb_fields[] = {
-    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
-};
-const uint16_t n_afsdb_fields = sizeof(afsdb_fields) / sizeof(RdataFieldSpec);
-
-// SRV specific: 3*16-bit data + additional name
-const RdataFieldSpec srv_fields[] = {
-    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t) * 3, NAMEATTR_NONE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_ADDITIONAL}
-};
-const uint16_t n_srv_fields = sizeof(srv_fields) / sizeof(RdataFieldSpec);
-
-// NAPTR specific: (multi-field) variable data + (additional) name
-// NAPTR requires complicated additional section handling; for now, we skip
-// the additional handling completely.
-const RdataFieldSpec naptr_fields[] = {
-    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE},
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
-};
-const uint16_t n_naptr_fields = sizeof(naptr_fields) / sizeof(RdataFieldSpec);
-
-// NSEC specific: no-attribute name + varlen data
-const RdataFieldSpec nsec_fields[] = {
-    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
-    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
-};
-const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
-
-// Class IN encode specs.  This gives a shortcut to the encode spec for
-// some well-known types of RDATA specific to class IN (most of which are
-// generic and can be used for other classes).  The array index is the
-// RR type code.
-const RdataEncodeSpec encode_spec_list_in[] = {
-    generic_data_spec,                         // #0: (NONE)
-    {n_ipv4_fields, 0, 0, single_ipv4_fields},   // #1: A
-    {n_single_name_fields, 1, 0, single_compadditional_name_fields}, // #2: NS
-    generic_data_spec,          // #3
-    generic_data_spec,          // #4
-    {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #5: CNAME
-    {n_soa_fields, 2, 0, soa_fields}, // #6: SOA
-    generic_data_spec,                // #7
-    generic_data_spec,                // #8
-    generic_data_spec,                // #9
-    generic_data_spec,                // #10
-    generic_data_spec,                // #11
-    {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #12: PTR
-    generic_data_spec,          // #13: HINFO
-    {n_double_name_fields, 2, 0, double_compressible_name_fields}, // #14:HINFO
-    {n_mx_fields, 1, 0, mx_fields}, // #15: MX
-    generic_data_spec, // #16: TXT
-    {n_double_name_fields, 2, 0, double_noattr_name_fields}, // 17: RP
-    {n_afsdb_fields, 1, 0, afsdb_fields}, // #18: AFSDB
-    // #19-#26
-    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
-    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
-    generic_data_spec,                // #27
-    {n_ipv6_fields, 0, 0, single_ipv6_fields},   // #28: AAAA
-    // #29-#32
-    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
-    {n_srv_fields, 1, 0, srv_fields},   // #33: SRV
-    generic_data_spec,                  // #34
-    {n_naptr_fields, 1, 1, naptr_fields}, // #35: NAPTR
-    generic_data_spec,                  // #36
-    generic_data_spec,                  // #37
-    generic_data_spec,                  // #38
-    {n_single_name_fields, 1, 0, single_noattr_name_fields}, // #39 DNAME
-    generic_data_spec,                  // #40
-    generic_data_spec,                  // #41 (OPT)
-    generic_data_spec,                  // #42
-    generic_data_spec, // #43: DS (this is opaque for encoding purposes)
-    generic_data_spec, // #44: SSHFP (this is opaque for encoding purposes)
-    generic_data_spec,                  // #45
-    generic_data_spec, // #46: RRSIG (this is opaque for encoding purposes)
-    {n_nsec_fields, 1, 1, nsec_fields} // #47: NSEC
-
-    // All others can be treated as single-field variable length data, at
-    // least for currently supported RR types.
-};
-
-// # of entries in encode_spec_list_in
-const size_t encode_spec_list_in_size =
-    sizeof(encode_spec_list_in) / sizeof(encode_spec_list_in[0]);
-BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
-
-}
-
-const RdataEncodeSpec&
-getRdataEncodeSpec(const RRClass& rrclass, const RRType& rrtype) {
-    // Special case: for classes other than IN, we treat RDATA of RR types
-    // that are class-IN specific as generic opaque data.
-    if (rrclass != RRClass::IN() &&
-        (rrtype == RRType::A() || rrtype == RRType::AAAA() ||
-         rrtype == RRType::SRV())) {
-        return (generic_data_spec);
-    }
-
-    // Otherwise, if the type is in the pre-defined range, we use the defined
-    // spec; otherwise we treat it as opaque data.
-    const uint16_t typecode = rrtype.getCode();
-    if (typecode < encode_spec_list_in_size) {
-        return (encode_spec_list_in[rrtype.getCode()]);
-    }
-    return (generic_data_spec);
-}
-
-}
-}
-}
diff --git a/src/lib/datasrc/memory/rdata_field.h b/src/lib/datasrc/memory/rdata_field.h
deleted file mode 100644
index d9ab415..0000000
--- a/src/lib/datasrc/memory/rdata_field.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (C) 2012  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 DATASRC_MEMORY_RDATA_FIELD
-#define DATASRC_MEMORY_RDATA_FIELD
-
-#include <stdint.h>
-
-/// \file rdata_field.h
-///
-/// This header should be considered private to the implementation and should
-/// not be used included directly.
-///
-/// It is used to share the definition of encoding for RRtypes.
-///
-/// These are types shared by classes in rdata_encoder.h and rdata_reader.h.
-/// The defyne a set of interfaces (classes, types, constants) to
-/// manipulate a given set of RDATA of the same type (normally associated with
-/// an RRset) that may be accompanied with RRSIGs in a memory efficient way.
-///
-/// The entire set of RDATA is stored in a packed form in a contiguous
-/// memory region.  It's opaque data, without containing non trivial
-/// data structures, so it can be located anywhere in the memory or even
-/// dumped to a file.
-///
-/// Two main classes are provided: one is
-/// \c isc::datasrc::memory::RdataEncoder, which allows
-/// the application to create encoded data for a set of RDATA;
-/// the isc::datasrc::memory::RdataReader provides an interface to iterate
-/// over encoded set of RDATA for purposes such as data lookups or rendering
-/// the data into the wire format to create a DNS message.
-///
-/// The actual encoding detail is private information to the implementation,
-/// and the application shouldn't assume anything about that except that
-/// each RDATA is considered to consist of one or more generic fields,
-/// and each field is typed as either opaque data or a domain name.
-/// A domain name field has additional attributes
-/// (see \c isc::datasrc::memory::RdataNameAttributes)
-/// so the application can change how the name should be handled in terms
-/// of the DNS protocol (e.g., whether it's subject to name compression).
-///
-/// The following are the current implementation of internal encoding, shown
-/// only for reference.  Applications must not assume this particular form
-/// for the encoded data; in fact, it can change in a future version of the
-/// implementation.
-/// \verbatim
-// The encoded data begin with a series of 16-bit length fields (values are
-// stored in the host byte order).  The sequence may be empty.
-// uint16_t n1_1: size of 1st variable len field (if any) of 1st RDATA
-// uint16_t n1_2: size of 2nd variable len field of 1st RDATA
-// ...
-// uint16_t nN_M: size of last (Mth) variable len field of last (Nth) RDATA
-// uint16_t ns1: size of 1st RRSIG (if any) data
-// ...
-// uint16_t nsL: size of last (Lth) RRSIG data
-// A sequence of packed data fields follows:
-// uint8_t[]: data field value, length specified by nI_J (in case it's
-//            variable-length) or by the per type field spec (in case it's
-//            fixed-length).
-// or
-// opaque data, LabelSequence::getSerializedLength() bytes: data for a name
-// uint8_t[ns1]: 1st RRSIG data
-// ...
-// uint8_t[nsL]: last RRSIG data
-// \endverbatim
-///
-/// As described above, this implementation treats RRSIGs as opaque data
-/// that don't contain any domain names.  Technically, it has a "signer"
-/// domain name field in the sense of RFC4034.  In practice, however, this
-/// field is essentially mere data; it's not subject to name compression,
-/// and since it's very likely to be a subdomain of (or equal to) the
-/// owner name of the corresponding RR (or, if used in a DNS message,
-/// some domain name that already appears before this field), so it won't
-/// be a target of name compression either.  By treating the entire RRSIG
-/// as single-field data we can make the implementation simpler, and probably
-/// make it faster in rendering it into a DNS message.
-
-namespace isc {
-namespace dns {
-class RRType;
-class RRClass;
-}
-namespace datasrc {
-namespace memory {
-
-/// \brief Attributes of domain name fields of encoded RDATA.
-///
-/// The enum values define special traits of the name that can affect how
-/// it should be handled in rendering or query processing.
-enum RdataNameAttributes {
-    NAMEATTR_NONE = 0,          ///< No special attributes
-    NAMEATTR_COMPRESSIBLE = 1,  ///< Name should be compressed when rendered
-    NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
-                                                      ///< Additional section
-                                                      ///< handling
-};
-
-/// Specification of a single RDATA field in terms of internal encoding.
-struct RdataFieldSpec {
-    enum FieldType {
-        FIXEDLEN_DATA = 0,      // fixed-length data field
-        VARLEN_DATA,            // variable-length data field
-        DOMAIN_NAME             // domain name
-    };
-
-    const FieldType type;       // field type
-
-    // The length of fixed-length data field.  Only valid for FIXEDLEN_DATA.
-    // For type DOMAIN_NAME, set it to 0.
-    const uint16_t fixeddata_len;
-
-    // Attributes of the name.  Only valid for DOMAIN_NAME.
-    // For type _DATA, set it to NAMEATTR_NONE.
-    const RdataNameAttributes name_attributes;
-};
-
-/// Specification of RDATA in terms of internal encoding.
-///
-/// The fields must be a sequence of:
-/// <0 or 1 fixed/var-len data field>,
-/// <1 or more domain name fields>,
-/// <1 fixed/var-len data field>,
-/// <1 or more domain name fields>,
-/// <1 fixed/var-len data field>,
-/// ...and so on.
-/// There must not be more than one consecutive data fields (i.e., without
-/// interleaved by a domain name); it would just be inefficient in terms of
-/// memory footprint and iterating over the fields, and it would break
-/// some assumption within the encoder implementation.  For consecutive
-/// data fields in the DNS protocol, if all fields have fixed lengths, they
-/// should be combined into a single fixed-length field (like the last 20
-/// bytes of SOA RDATA).  If there's a variable length field, they should be
-/// combined into a single variable-length field (such as DNSKEY, which has
-/// 3 fixed-length fields followed by one variable-length field).
-struct RdataEncodeSpec {
-    const uint16_t field_count; // total number of fields (# of fields member)
-    const uint16_t name_count;  // number of domain name fields
-    const uint16_t varlen_count; // number of variable-length data fields
-    const RdataFieldSpec* const fields; // list of field specs
-};
-
-/// \brief Get the spec for given class and type
-const RdataEncodeSpec&
-getRdataEncodeSpec(const dns::RRClass& rrclass, const dns::RRType& rrtype);
-
-}
-}
-}
-
-#endif
diff --git a/src/lib/datasrc/memory/rdata_reader.cc b/src/lib/datasrc/memory/rdata_reader.cc
deleted file mode 100644
index 5429fb9..0000000
--- a/src/lib/datasrc/memory/rdata_reader.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (C) 2012  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 "rdata_reader.h"
-
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-RdataReader::RdataReader(const RRClass& rrclass, const RRType& rrtype,
-                         const void* data,
-                         size_t rdata_count, size_t sig_count,
-                         const NameAction& name_action,
-                         const DataAction& data_action) :
-    name_action_(name_action),
-    data_action_(data_action),
-    spec_(getRdataEncodeSpec(rrclass, rrtype)),
-    var_count_total_(spec_.varlen_count * rdata_count),
-    sig_count_(sig_count),
-    spec_count_(spec_.field_count * rdata_count),
-    // The lenghts are stored first
-    lengths_(reinterpret_cast<const uint16_t*>(data)),
-    // And the data just after all the lengths
-    data_(reinterpret_cast<const uint8_t*>(data) +
-          (var_count_total_ + sig_count_) * sizeof(uint16_t)),
-    sigs_(NULL)
-{
-    rewind();
-}
-
-void
-RdataReader::rewind() {
-    data_pos_ = 0;
-    spec_pos_ = 0;
-    length_pos_ = 0;
-    sig_data_pos_ = 0;
-    sig_pos_ = 0;
-}
-
-RdataReader::Boundary
-RdataReader::nextInternal(const NameAction& name_action,
-                          const DataAction& data_action)
-{
-    if (spec_pos_ < spec_count_) {
-        const RdataFieldSpec& spec(spec_.fields[(spec_pos_++) %
-                                                spec_.field_count]);
-        if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
-            const LabelSequence sequence(data_ + data_pos_);
-            data_pos_ += sequence.getSerializedLength();
-            name_action(sequence, spec.name_attributes);
-        } else {
-            const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
-                                spec.fixeddata_len : lengths_[length_pos_++]);
-            const uint8_t* const pos = data_ + data_pos_;
-            data_pos_ += length;
-            data_action(pos, length);
-        }
-        return (spec_pos_ % spec_.field_count == 0 ?
-                RDATA_BOUNDARY : NO_BOUNDARY);
-    } else {
-        sigs_ = data_ + data_pos_;
-        return (RRSET_BOUNDARY);
-    }
-}
-
-RdataReader::Boundary
-RdataReader::next() {
-    return (nextInternal(name_action_, data_action_));
-}
-
-namespace {
-
-void
-emptyNameAction(const LabelSequence&, unsigned) {
-    // Do nothing here.
-}
-
-void
-emptyDataAction(const void*, size_t) {
-    // Do nothing here.
-}
-
-}
-
-RdataReader::Boundary
-RdataReader::nextSig() {
-    if (sig_pos_ < sig_count_) {
-        if (sigs_ == NULL) {
-            // We didn't find where the signatures start yet. We do it
-            // by iterating the whole data and then returning the state
-            // back.
-            const size_t data_pos = data_pos_;
-            const size_t spec_pos = spec_pos_;
-            const size_t length_pos = length_pos_;
-            // When the next() gets to the last item, it sets the sigs_
-            while (nextInternal(emptyNameAction, emptyDataAction) !=
-                   RRSET_BOUNDARY) {}
-            assert(sigs_ != NULL);
-            // Return the state
-            data_pos_ = data_pos;
-            spec_pos_ = spec_pos;
-            length_pos_ = length_pos;
-        }
-        // Extract the result
-        const size_t length = lengths_[var_count_total_ + sig_pos_];
-        const uint8_t* const pos = sigs_ + sig_data_pos_;
-        // Move the position of iterator.
-        sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
-        ++sig_pos_;
-        // Call the callback
-        data_action_(pos, length);
-        return (RDATA_BOUNDARY);
-    } else {
-        return (RRSET_BOUNDARY);
-    }
-}
-
-size_t
-RdataReader::getSize() const {
-    size_t storage_size = 0;    // this will be the end result
-    size_t data_pos = 0;
-    size_t length_pos = 0;
-
-    // Go over all data fields, adding their lengths to storage_size
-    for (size_t spec_pos = 0; spec_pos < spec_count_; ++spec_pos) {
-        const RdataFieldSpec& spec =
-            spec_.fields[spec_pos % spec_.field_count];
-        if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
-            const size_t seq_len =
-                LabelSequence(data_ + data_pos).getSerializedLength();
-            data_pos += seq_len;
-            storage_size += seq_len;
-        } else {
-            const size_t data_len =
-                (spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
-                 spec.fixeddata_len : lengths_[length_pos++]);
-            data_pos += data_len;
-            storage_size += data_len;
-        }
-    }
-    // Same for all RRSIG data
-    for (size_t sig_pos = 0; sig_pos < sig_count_; ++sig_pos) {
-        const size_t sig_data_len = lengths_[length_pos++];
-        storage_size += sig_data_len;
-    }
-
-    // Finally, add the size for 16-bit length fields
-    storage_size += (var_count_total_ * sizeof(uint16_t) +
-                     sig_count_ * sizeof(uint16_t));
-
-    return (storage_size);
-}
-
-}
-}
-}
diff --git a/src/lib/datasrc/memory/rdata_reader.h b/src/lib/datasrc/memory/rdata_reader.h
deleted file mode 100644
index 8f50225..0000000
--- a/src/lib/datasrc/memory/rdata_reader.h
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (C) 2012  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 DATASRC_MEMORY_RDATA_READER_H
-#define DATASRC_MEMORY_RDATA_READER_H 1
-
-#include "rdata_field.h"
-
-#include <boost/function.hpp>
-
-#include <dns/labelsequence.h>
-#include <dns/name.h>
-
-namespace isc {
-// Some forward declarations
-namespace dns{
-class RRClass;
-class RRType;
-}
-
-namespace datasrc {
-namespace memory {
-
-/// \brief Class to read serialized rdata
-///
-/// This class allows you to read the data encoded by RdataEncoder.
-/// It is rather low-level -- it provides sequence of data fields.
-/// Each field is either opaque data, passed as a pointer and length,
-/// or a name, in the form of dns::LabelSequence (which is always
-/// absolute) and attributes.
-///
-/// Conceptually, these fields correspond to consecutive regions in
-/// wire-format representation of the RDATA, varying the type of above
-/// two cases depending on whether the region corresponds to a domain
-/// name or other data.  For example, for an MX RDATA the field
-/// sequence will be
-/// - 2 bytes of opaque data (which corresponds to the MX preference)
-/// - a domain name (which corresponds to the MX name)
-///
-/// If the encoded data contain multiple MX RDATAs, the same type of
-/// sequence continues for the number of RDATAs.  Note that the opaque
-/// data field does not always corresponds to a specific RDATA field
-/// as is the 2-byte preference field of MX.  For example, the field
-/// sequence for an SOA RDATA in terms of RdataEncoder will be:
-/// - a domain name (which corresponds to the SOA MNAME)
-/// - a domain name (which corresponds to the SOA RNAME)
-/// - 20 bytes of opaque data (for the rest of fields)
-///
-/// So, if you want to construct a general purpose dns::Rdata object
-/// from the field sequence, you'll need to build the complete
-/// wire-format data, and then construct a dns::Rdata object from it.
-///
-/// To use it, contstruct it with the data you got from RDataEncoder,
-/// provide it with callbacks and then iterate through the data.
-/// The callbacks are called with the data fields contained in the
-/// data.
-///
-/// \code
-/// void handleName(const dns::LabelSequence& labels, unsigned int flags) {
-///     ...
-/// }
-/// void handleData(const void* data, size_t size) {
-///     ...
-/// }
-///
-/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
-///                    &handleName, &handleData);
-/// reader.iterate();
-/// \endcode
-///
-/// \note It is caller's responsibility to pass valid data here. This means
-///     the data returned by RdataEncoder and the corresponding class and type.
-///     If this is not the case, all the kinds of pointer hell might get loose.
-class RdataReader {
-public:
-    /// \brief Function called on each name encountered in the data.
-    typedef boost::function<void(const dns::LabelSequence&,
-                                 RdataNameAttributes)> NameAction;
-    /// \brief Function called on each data field in the data.
-    typedef boost::function<void(const void*, size_t)> DataAction;
-
-    /// \brief Constructor
-    ///
-    /// This constructs the reader on top of some serialized data.
-    /// It does not copy the data, you have to make sure the data
-    /// is valid for the whole life of this object and that they
-    /// don't change.
-    ///
-    /// \param rrclass The class the encoded rdata belongs to.
-    /// \param rrtype The type of the encode rdata.
-    /// \param data The actual data.
-    /// \param rdata_count The number of Rdata encoded in the data.
-    /// \param sig_count The number of RRSig rdata bundled with the data.
-    /// \param name_action The callback to be called on each encountered name.
-    /// \param data_action The callback to be called on each data chunk.
-    RdataReader(const dns::RRClass& rrclass, const dns::RRType& rrtype,
-                const void* data, size_t rdata_count, size_t sig_count,
-                const NameAction& name_action, const DataAction& data_action);
-
-    /// \brief Result of next() and nextSig()
-    ///
-    /// This specifies if there's any boundary in the data at the
-    /// place where the corresponding call to next() or nextSig()
-    /// finished.
-    enum Boundary {
-        NO_BOUNDARY,    ///< It is in the middle of Rdata
-        RDATA_BOUNDARY, ///< At the end of single Rdata
-        RRSET_BOUNDARY  ///< At the end of the RRset (past the end)
-    };
-
-    /// \brief Step to next data field.
-    ///
-    /// Iterate over the next field and call appropriate hook (name_action
-    /// or data_action, depending on the type) as passed to the constructor.
-    ///
-    /// \return It returns NO_BOUNDARY if the next call to next() will process
-    ///     data of the same rdata as this one. RDATA_BOUNDARY is returned when
-    ///     this field is the last of the current rdata. If there are no more
-    ///     data to process, no hook is called and RRSET_BOUNDARY is returned.
-    ///     Therefore, at the end of the whole data, once it processes the last
-    ///     field and returns RDATA_BOUNDARY and then it returns RRSET_BOUNDARY
-    ///     on the next call.
-    Boundary next();
-
-    /// \brief Call next() until the end.
-    ///
-    /// This is just convenience method to iterate through all the data.
-    /// It calls next until it reaches the end (it does not rewind beforehand,
-    /// therefore if you already called next() yourself, it does not start
-    /// at the beginning).
-    void iterate() {
-        while (next() != RRSET_BOUNDARY) {}
-    }
-
-    /// \brief Call next() until the end of current rdata.
-    ///
-    /// This is a convenience method to iterate until the end of current
-    /// rdata. Notice this may cause more than one field being processed,
-    /// as some rrtypes are more complex.
-    ///
-    /// \return If there was Rdata to iterate through.
-    bool iterateRdata() {
-        while (true) {
-            switch (next()) {
-                case NO_BOUNDARY: break;
-                case RDATA_BOUNDARY: return (true);
-                case RRSET_BOUNDARY: return (false);
-            }
-        }
-    }
-
-    /// \brief Step to next field of RRSig data.
-    ///
-    /// This is almost the same as next(), but it iterates through the
-    /// associated RRSig data, not the data for the given RRType.
-    Boundary nextSig();
-
-    /// \brief Iterate through all RRSig data.
-    ///
-    /// This is almost the same as iterate(), but it iterates through the
-    /// RRSig data instead.
-    void iterateAllSigs() {
-        while (nextSig() != RRSET_BOUNDARY) {}
-    }
-
-    /// \brief Iterate through the current RRSig Rdata.
-    ///
-    /// This is almote the same as iterateRdata, except it is for single
-    /// signature Rdata.
-    ///
-    /// In practice, this should process one DATA field.
-    bool iterateSingleSig() {
-        while (true) {
-            switch (nextSig()) {
-                case NO_BOUNDARY: break;
-                case RDATA_BOUNDARY: return (true);
-                case RRSET_BOUNDARY: return (false);
-            }
-        }
-    }
-
-    /// \brief Rewind the iterator to the beginnig of data.
-    ///
-    /// The following next() and nextSig() will start iterating from the
-    /// beginning again.
-    void rewind();
-
-    /// \brief Returns the size of associated data.
-    ///
-    /// This should be the same as the return value of
-    /// RdataEncoder::getStorageLength() for the same set of data.
-    /// The intended use of this method is to tell the caller the size of
-    /// data that were possibly dynamically allocated so that the caller can
-    /// use it for deallocation.
-    ///
-    /// This method only uses the parameters given at the construction of the
-    /// object, and does not rely on or modify other mutable states.
-    /// In practice, when the caller wants to call this method, that would be
-    /// the only purpose of that RdataReader object (although it doesn't have
-    /// to be so).
-    size_t getSize() const;
-private:
-    const NameAction name_action_;
-    const DataAction data_action_;
-    const RdataEncodeSpec& spec_;
-    // Total number of var-length fields, count of signatures
-    const size_t var_count_total_, sig_count_, spec_count_;
-    // Pointer to the beginning of length fields
-    const uint16_t* const lengths_;
-    // Pointer to the beginning of the data (after the lengths)
-    const uint8_t* const data_;
-    // Pointer to the first data signature
-    // Will be computed during the normal RR iteration
-    const uint8_t* sigs_;
-    // The positions in data.
-    size_t data_pos_, spec_pos_, length_pos_;
-    size_t sig_pos_, sig_data_pos_;
-    Boundary nextInternal(const NameAction& name_action,
-                          const DataAction& data_action);
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/lib/datasrc/memory/rdata_serialization.cc b/src/lib/datasrc/memory/rdata_serialization.cc
new file mode 100644
index 0000000..9c020b2
--- /dev/null
+++ b/src/lib/datasrc/memory/rdata_serialization.cc
@@ -0,0 +1,635 @@
+// Copyright (C) 2012  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 "rdata_serialization.h"
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <cassert>
+#include <cstring>
+#include <vector>
+#include <boost/static_assert.hpp>
+
+using namespace isc::dns;
+using std::vector;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+#include "rdata_serialization_priv.cc"
+
+namespace {
+
+// Many types of RDATA can be treated as a single-field, variable length
+// field (in terms of our encoding).  The following define such most general
+// form of field spec.
+const RdataFieldSpec generic_data_fields[] = {
+    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
+};
+const uint16_t n_generic_data_fields =
+    sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
+const RdataEncodeSpec generic_data_spec = {
+    n_generic_data_fields, 0, 1, generic_data_fields
+};
+
+// RDATA consist of a single IPv4 address field.
+const RdataFieldSpec single_ipv4_fields[] = {
+    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t), NAMEATTR_NONE}
+};
+const uint16_t n_ipv4_fields =
+    sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
+
+// RDATA consist of a single IPv6 address field.
+const RdataFieldSpec single_ipv6_fields[] = {
+    {RdataFieldSpec::FIXEDLEN_DATA, 16, NAMEATTR_NONE} // 128bits = 16 bytes
+};
+const uint16_t n_ipv6_fields =
+    sizeof(single_ipv6_fields) / sizeof(RdataFieldSpec);
+
+// There are several RR types that consist of a single domain name.
+const RdataFieldSpec single_noattr_name_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
+};
+const RdataFieldSpec single_compressible_name_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
+};
+const RdataFieldSpec single_compadditional_name_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0,
+     static_cast<RdataNameAttributes>(
+         static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
+         static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
+};
+const uint16_t n_single_name_fields =
+    sizeof(single_noattr_name_fields) / sizeof(RdataFieldSpec);
+
+// RDATA consisting of two names.  There are some of this type.
+const RdataFieldSpec double_compressible_name_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
+};
+const RdataFieldSpec double_noattr_name_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
+};
+const uint16_t n_double_name_fields =
+    sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
+
+// SOA specific: two compressible names + 5*32-bit data
+const RdataFieldSpec soa_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
+    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t) * 5, NAMEATTR_NONE}
+};
+const uint16_t n_soa_fields = sizeof(soa_fields) / sizeof(RdataFieldSpec);
+
+// MX specific: 16-bit data + compressible/additional name
+const RdataFieldSpec mx_fields[] = {
+    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
+    {RdataFieldSpec::DOMAIN_NAME, 0,
+     static_cast<RdataNameAttributes>(
+         static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
+         static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
+};
+const uint16_t n_mx_fields = sizeof(mx_fields) / sizeof(RdataFieldSpec);
+
+// AFSDB specific: 16-bit data + no-attribute name
+const RdataFieldSpec afsdb_fields[] = {
+    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
+};
+const uint16_t n_afsdb_fields = sizeof(afsdb_fields) / sizeof(RdataFieldSpec);
+
+// SRV specific: 3*16-bit data + additional name
+const RdataFieldSpec srv_fields[] = {
+    {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t) * 3, NAMEATTR_NONE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_ADDITIONAL}
+};
+const uint16_t n_srv_fields = sizeof(srv_fields) / sizeof(RdataFieldSpec);
+
+// NAPTR specific: (multi-field) variable data + (additional) name
+// NAPTR requires complicated additional section handling; for now, we skip
+// the additional handling completely.
+const RdataFieldSpec naptr_fields[] = {
+    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE},
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
+};
+const uint16_t n_naptr_fields = sizeof(naptr_fields) / sizeof(RdataFieldSpec);
+
+// NSEC specific: no-attribute name + varlen data
+const RdataFieldSpec nsec_fields[] = {
+    {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
+    {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
+};
+const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
+
+// Class IN encode specs.  This gives a shortcut to the encode spec for
+// some well-known types of RDATA specific to class IN (most of which are
+// generic and can be used for other classes).  The array index is the
+// RR type code.
+const RdataEncodeSpec encode_spec_list_in[] = {
+    generic_data_spec,                         // #0: (NONE)
+    {n_ipv4_fields, 0, 0, single_ipv4_fields},   // #1: A
+    {n_single_name_fields, 1, 0, single_compadditional_name_fields}, // #2: NS
+    generic_data_spec,          // #3
+    generic_data_spec,          // #4
+    {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #5: CNAME
+    {n_soa_fields, 2, 0, soa_fields}, // #6: SOA
+    generic_data_spec,                // #7
+    generic_data_spec,                // #8
+    generic_data_spec,                // #9
+    generic_data_spec,                // #10
+    generic_data_spec,                // #11
+    {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #12: PTR
+    generic_data_spec,          // #13: HINFO
+    {n_double_name_fields, 2, 0, double_compressible_name_fields}, // #14:HINFO
+    {n_mx_fields, 1, 0, mx_fields}, // #15: MX
+    generic_data_spec, // #16: TXT
+    {n_double_name_fields, 2, 0, double_noattr_name_fields}, // 17: RP
+    {n_afsdb_fields, 1, 0, afsdb_fields}, // #18: AFSDB
+    // #19-#26
+    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
+    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
+    generic_data_spec,                // #27
+    {n_ipv6_fields, 0, 0, single_ipv6_fields},   // #28: AAAA
+    // #29-#32
+    generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
+    {n_srv_fields, 1, 0, srv_fields},   // #33: SRV
+    generic_data_spec,                  // #34
+    {n_naptr_fields, 1, 1, naptr_fields}, // #35: NAPTR
+    generic_data_spec,                  // #36
+    generic_data_spec,                  // #37
+    generic_data_spec,                  // #38
+    {n_single_name_fields, 1, 0, single_noattr_name_fields}, // #39 DNAME
+    generic_data_spec,                  // #40
+    generic_data_spec,                  // #41 (OPT)
+    generic_data_spec,                  // #42
+    generic_data_spec, // #43: DS (this is opaque for encoding purposes)
+    generic_data_spec, // #44: SSHFP (this is opaque for encoding purposes)
+    generic_data_spec,                  // #45
+    generic_data_spec, // #46: RRSIG (this is opaque for encoding purposes)
+    {n_nsec_fields, 1, 1, nsec_fields} // #47: NSEC
+
+    // All others can be treated as single-field variable length data, at
+    // least for currently supported RR types.
+};
+
+// # of entries in encode_spec_list_in
+const size_t encode_spec_list_in_size =
+    sizeof(encode_spec_list_in) / sizeof(encode_spec_list_in[0]);
+BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
+
+}
+
+/// \brief Get the spec for given class and type
+const RdataEncodeSpec&
+getRdataEncodeSpec(const RRClass& rrclass, const RRType& rrtype) {
+    // Special case: for classes other than IN, we treat RDATA of RR types
+    // that are class-IN specific as generic opaque data.
+    if (rrclass != RRClass::IN() &&
+        (rrtype == RRType::A() || rrtype == RRType::AAAA() ||
+         rrtype == RRType::SRV())) {
+        return (generic_data_spec);
+    }
+
+    // Otherwise, if the type is in the pre-defined range, we use the defined
+    // spec; otherwise we treat it as opaque data.
+    const uint16_t typecode = rrtype.getCode();
+    if (typecode < encode_spec_list_in_size) {
+        return (encode_spec_list_in[rrtype.getCode()]);
+    }
+    return (generic_data_spec);
+}
+
+namespace {
+
+// This class is a helper for RdataEncoder to divide the content of RDATA
+// fields for encoding by "abusing" the  message rendering logic.
+// The idea is to identify domain name fields in the writeName() method,
+// while keeping track of the size and position of other types of data
+// around the names.
+//
+// Technically, this use of inheritance may be considered a violation of
+// Liskov Substitution Principle in that it doesn't actually compress domain
+// names, and some of the methods are not expected to be used.
+// In fact, skip() or trim() may not be make much sense in this context.
+// Nevertheless we keep this idea at the moment.  Since the usage is limited
+// (it's only used within this file, and only used with \c Rdata variants),
+// it's hopefully an acceptable practice.
+class RdataFieldComposer : public AbstractMessageRenderer {
+public:
+    RdataFieldComposer() : last_data_pos_(0), encode_spec_(NULL),
+                           current_field_(0)
+    {}
+    virtual ~RdataFieldComposer() {}
+    virtual bool isTruncated() const { return (false); }
+    virtual size_t getLengthLimit() const { return (65535); }
+    virtual CompressMode getCompressMode() const { return (CASE_INSENSITIVE); }
+    virtual void setTruncated() {}
+    virtual void setLengthLimit(size_t) {}
+    virtual void setCompressMode(CompressMode) {}
+
+    // Called for each domain name in the RDATA, from the RDATA's toWire()
+    // implementation.
+    virtual void writeName(const Name& name, bool compress) {
+        // First, see if we have other data already stored in the renderer's
+        // buffer, and handle it appropriately.
+        updateOtherData();
+
+        // Then, we should still have a field in the spec, and it must be a
+        // domain name field.
+        if (current_field_ >= encode_spec_->field_count) {
+            isc_throw(BadValue,
+                      "RDATA encoder encounters an unexpected name data: " <<
+                      name);
+        }
+        const RdataFieldSpec& field =
+            encode_spec_->fields[current_field_++];
+        // Since we know we've passed any prior data field, the next field
+        // must be a domain name as long as it exists; otherwise it's a bug
+        // in the spec (not a bogus input).  So we assert() that condition.
+        assert(field.type == RdataFieldSpec::DOMAIN_NAME);
+
+        // It would be compressed iff the field has that attribute.
+        if (compress !=
+            ((field.name_attributes & NAMEATTR_COMPRESSIBLE) != 0)) {
+            isc_throw(BadValue, "RDATA encoder error, inconsistent name "
+                      "compression policy: " << name);
+        }
+
+        const LabelSequence labels(name);
+        labels.serialize(labels_placeholder_, sizeof(labels_placeholder_));
+        writeData(labels_placeholder_, labels.getSerializedLength());
+
+        last_data_pos_ += labels.getSerializedLength();
+    }
+    // Clear all internal states and resources for a new set of RDATA.
+    void clearLocal(const RdataEncodeSpec* encode_spec) {
+        AbstractMessageRenderer::clear();
+        encode_spec_ = encode_spec;
+        data_lengths_.clear();
+        last_data_pos_ = 0;
+    }
+    // Called at the beginning of an RDATA.
+    void startRdata() {
+        current_field_ = 0;
+    }
+    // Called at the end of an RDATA.
+    void endRdata() {
+        // Handle any remaining data (there should be no more name).  Then
+        // we should reach the end of the fields.
+        updateOtherData();
+        if (current_field_ != encode_spec_->field_count) {
+            isc_throw(BadValue,
+                      "RDATA encoder didn't find all expected fields");
+        }
+    }
+
+    // Hold the lengths of variable length fields, in the order of their
+    // appearance.  For convenience, allow the encoder to refer to it
+    // directly.
+    vector<uint16_t> data_lengths_;
+
+private:
+    // We use generict write* methods, with the exception of writeName.
+    // So new data can arrive without us knowing it, this considers all new
+    // data to be just data, checking consistency with the field spec, and
+    // if it contains variable-length field, record its length.
+    size_t last_data_pos_;
+    void updateOtherData() {
+        // If we've reached the end of the fields or we are expecting a
+        // domain name, there's nothing to do here.
+        if (current_field_ >= encode_spec_->field_count ||
+            encode_spec_->fields[current_field_].type ==
+            RdataFieldSpec::DOMAIN_NAME) {
+            return;
+        }
+
+        const size_t cur_pos = getLength();
+        const size_t data_len = cur_pos - last_data_pos_;
+
+        const RdataFieldSpec& field = encode_spec_->fields[current_field_];
+        if (field.type == RdataFieldSpec::FIXEDLEN_DATA) {
+            // The data length of a fixed length field must be the one
+            // specified in the field spec.
+            if (data_len != field.fixeddata_len) {
+                isc_throw(BadValue,
+                          "RDATA encoding: available data too short for the "
+                          "type");
+            }
+        } else {
+            // For encoding purposes, a variable-length data field is
+            // a single field covering all data, even if it may
+            // consist of multiple fields as DNS RDATA (e.g. TXT).
+            if (data_len > 0xffff) {
+                isc_throw(RdataEncodingError, "RDATA field is too large: "
+                          << data_len << " bytes");
+            }
+            data_lengths_.push_back(data_len);
+        }
+
+        ++current_field_;
+        last_data_pos_ = cur_pos;
+    }
+
+    // The RDATA field spec of the current session.  Set at the beginning of
+    // each session.
+    const RdataEncodeSpec* encode_spec_;
+    // the RDATA field (for encoding) currently handled.  Reset to 0 for
+    // each RDATA of the session.
+    size_t current_field_;
+    // Placeholder to convert a name object to a label sequence.
+    uint8_t labels_placeholder_[LabelSequence::MAX_SERIALIZED_LENGTH];
+};
+
+} // end of unnamed namespace
+
+struct RdataEncoder::RdataEncoderImpl {
+    RdataEncoderImpl() : encode_spec_(NULL), rrsig_buffer_(0),
+                         rdata_count_(0)
+    {}
+
+    const RdataEncodeSpec* encode_spec_; // encode spec of current RDATA set
+    RdataFieldComposer field_composer_;
+    util::OutputBuffer rrsig_buffer_;
+    size_t rdata_count_;
+    vector<uint16_t> rrsig_lengths_;
+};
+
+RdataEncoder::RdataEncoder() :
+    impl_(new RdataEncoderImpl)
+{}
+
+RdataEncoder::~RdataEncoder() {
+    delete impl_;
+}
+
+void
+RdataEncoder::start(RRClass rrclass, RRType rrtype) {
+    if (rrtype == RRType::RRSIG()) {
+        isc_throw(BadValue, "RRSIG cannot be encoded as main RDATA type");
+    }
+
+    impl_->encode_spec_ = &getRdataEncodeSpec(rrclass, rrtype);
+    impl_->field_composer_.clearLocal(impl_->encode_spec_);
+    impl_->rrsig_buffer_.clear();
+    impl_->rdata_count_ = 0;
+    impl_->rrsig_lengths_.clear();
+}
+
+void
+RdataEncoder::addRdata(const rdata::Rdata& rdata) {
+    if (impl_->encode_spec_ == NULL) {
+        isc_throw(InvalidOperation,
+                  "RdataEncoder::addRdata performed before start");
+    }
+
+    impl_->field_composer_.startRdata();
+    rdata.toWire(impl_->field_composer_);
+    impl_->field_composer_.endRdata();
+    ++impl_->rdata_count_;
+}
+
+void
+RdataEncoder::addSIGRdata(const rdata::Rdata& sig_rdata) {
+    if (impl_->encode_spec_ == NULL) {
+        isc_throw(InvalidOperation,
+                  "RdataEncoder::addSIGRdata performed before start");
+    }
+    const size_t cur_pos = impl_->rrsig_buffer_.getLength();
+    sig_rdata.toWire(impl_->rrsig_buffer_);
+    const size_t rrsig_datalen = impl_->rrsig_buffer_.getLength() - cur_pos;
+    if (rrsig_datalen > 0xffff) {
+        isc_throw(RdataEncodingError, "RRSIG is too large: "
+                  << rrsig_datalen << " bytes");
+    }
+    impl_->rrsig_lengths_.push_back(rrsig_datalen);
+}
+
+size_t
+RdataEncoder::getStorageLength() const {
+    if (impl_->encode_spec_ == NULL) {
+        isc_throw(InvalidOperation,
+                  "RdataEncoder::getStorageLength performed before start");
+    }
+
+    return (sizeof(uint16_t) * impl_->field_composer_.data_lengths_.size() +
+            sizeof(uint16_t) * impl_->rrsig_lengths_.size() +
+            impl_->rrsig_buffer_.getLength() +
+            impl_->field_composer_.getLength());
+}
+
+void
+RdataEncoder::encode(void* buf, size_t buf_len) const {
+    if (impl_->encode_spec_ == NULL) {
+        isc_throw(InvalidOperation,
+                  "RdataEncoder::encode performed before start");
+    }
+    if (buf == NULL) {
+        isc_throw(BadValue,
+                  "RdataEncoder::encode NULL buffer is given");
+    }
+    if (getStorageLength() > buf_len) {
+        isc_throw(BadValue, "RdataEncoder::encode short buffer given");
+    }
+
+    uint8_t* const dp_beg = reinterpret_cast<uint8_t*>(buf);
+    uint8_t* dp = dp_beg;
+    uint16_t* lenp = reinterpret_cast<uint16_t*>(buf);
+
+    // Encode list of lengths for variable length fields (if any)
+    if (!impl_->field_composer_.data_lengths_.empty()) {
+        const size_t varlen_fields_len =
+            impl_->field_composer_.data_lengths_.size() * sizeof(uint16_t);
+        std::memcpy(lenp, &impl_->field_composer_.data_lengths_[0],
+                    varlen_fields_len);
+        lenp += impl_->field_composer_.data_lengths_.size();
+        dp += varlen_fields_len;
+    }
+    // Encode list of lengths for RRSIGs (if any)
+    if (!impl_->rrsig_lengths_.empty()) {
+        const size_t rrsigs_len =
+            impl_->rrsig_lengths_.size() * sizeof(uint16_t);
+        std::memcpy(lenp, &impl_->rrsig_lengths_[0], rrsigs_len);
+        dp += rrsigs_len;
+    }
+    // Encode main RDATA
+    std::memcpy(dp, impl_->field_composer_.getData(),
+                impl_->field_composer_.getLength());
+    dp += impl_->field_composer_.getLength();
+    // Encode RRSIGs, if any
+    std::memcpy(dp, impl_->rrsig_buffer_.getData(),
+                impl_->rrsig_buffer_.getLength());
+    dp += impl_->rrsig_buffer_.getLength();
+
+    // The validation at the entrance must ensure this
+    assert(buf_len >= dp - dp_beg);
+}
+
+RdataReader::RdataReader(const RRClass& rrclass, const RRType& rrtype,
+                         const void* data,
+                         size_t rdata_count, size_t sig_count,
+                         const NameAction& name_action,
+                         const DataAction& data_action) :
+    name_action_(name_action),
+    data_action_(data_action),
+    spec_(getRdataEncodeSpec(rrclass, rrtype)),
+    var_count_total_(spec_.varlen_count * rdata_count),
+    sig_count_(sig_count),
+    spec_count_(spec_.field_count * rdata_count),
+    // The lenghts are stored first
+    lengths_(reinterpret_cast<const uint16_t*>(data)),
+    // And the data just after all the lengths
+    data_(reinterpret_cast<const uint8_t*>(data) +
+          (var_count_total_ + sig_count_) * sizeof(uint16_t)),
+    sigs_(NULL)
+{
+    rewind();
+}
+
+void
+RdataReader::rewind() {
+    data_pos_ = 0;
+    spec_pos_ = 0;
+    length_pos_ = 0;
+    sig_data_pos_ = 0;
+    sig_pos_ = 0;
+}
+
+RdataReader::Boundary
+RdataReader::nextInternal(const NameAction& name_action,
+                          const DataAction& data_action)
+{
+    if (spec_pos_ < spec_count_) {
+        const RdataFieldSpec& spec(spec_.fields[(spec_pos_++) %
+                                                spec_.field_count]);
+        if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
+            const LabelSequence sequence(data_ + data_pos_);
+            data_pos_ += sequence.getSerializedLength();
+            name_action(sequence, spec.name_attributes);
+        } else {
+            const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
+                                spec.fixeddata_len : lengths_[length_pos_++]);
+            const uint8_t* const pos = data_ + data_pos_;
+            data_pos_ += length;
+            data_action(pos, length);
+        }
+        return (spec_pos_ % spec_.field_count == 0 ?
+                RDATA_BOUNDARY : NO_BOUNDARY);
+    } else {
+        sigs_ = data_ + data_pos_;
+        return (RRSET_BOUNDARY);
+    }
+}
+
+RdataReader::Boundary
+RdataReader::next() {
+    return (nextInternal(name_action_, data_action_));
+}
+
+namespace {
+
+void
+emptyNameAction(const LabelSequence&, unsigned) {
+    // Do nothing here.
+}
+
+void
+emptyDataAction(const void*, size_t) {
+    // Do nothing here.
+}
+
+}
+
+RdataReader::Boundary
+RdataReader::nextSig() {
+    if (sig_pos_ < sig_count_) {
+        if (sigs_ == NULL) {
+            // We didn't find where the signatures start yet. We do it
+            // by iterating the whole data and then returning the state
+            // back.
+            const size_t data_pos = data_pos_;
+            const size_t spec_pos = spec_pos_;
+            const size_t length_pos = length_pos_;
+            // When the next() gets to the last item, it sets the sigs_
+            while (nextInternal(emptyNameAction, emptyDataAction) !=
+                   RRSET_BOUNDARY) {}
+            assert(sigs_ != NULL);
+            // Return the state
+            data_pos_ = data_pos;
+            spec_pos_ = spec_pos;
+            length_pos_ = length_pos;
+        }
+        // Extract the result
+        const size_t length = lengths_[var_count_total_ + sig_pos_];
+        const uint8_t* const pos = sigs_ + sig_data_pos_;
+        // Move the position of iterator.
+        sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
+        ++sig_pos_;
+        // Call the callback
+        data_action_(pos, length);
+        return (RDATA_BOUNDARY);
+    } else {
+        return (RRSET_BOUNDARY);
+    }
+}
+
+size_t
+RdataReader::getSize() const {
+    size_t storage_size = 0;    // this will be the end result
+    size_t data_pos = 0;
+    size_t length_pos = 0;
+
+    // Go over all data fields, adding their lengths to storage_size
+    for (size_t spec_pos = 0; spec_pos < spec_count_; ++spec_pos) {
+        const RdataFieldSpec& spec =
+            spec_.fields[spec_pos % spec_.field_count];
+        if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
+            const size_t seq_len =
+                LabelSequence(data_ + data_pos).getSerializedLength();
+            data_pos += seq_len;
+            storage_size += seq_len;
+        } else {
+            const size_t data_len =
+                (spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
+                 spec.fixeddata_len : lengths_[length_pos++]);
+            data_pos += data_len;
+            storage_size += data_len;
+        }
+    }
+    // Same for all RRSIG data
+    for (size_t sig_pos = 0; sig_pos < sig_count_; ++sig_pos) {
+        const size_t sig_data_len = lengths_[length_pos++];
+        storage_size += sig_data_len;
+    }
+
+    // Finally, add the size for 16-bit length fields
+    storage_size += (var_count_total_ * sizeof(uint16_t) +
+                     sig_count_ * sizeof(uint16_t));
+
+    return (storage_size);
+}
+
+} // namespace memory
+} // namespace datasrc
+} // datasrc isc
diff --git a/src/lib/datasrc/memory/rdata_serialization.h b/src/lib/datasrc/memory/rdata_serialization.h
new file mode 100644
index 0000000..4f65971
--- /dev/null
+++ b/src/lib/datasrc/memory/rdata_serialization.h
@@ -0,0 +1,423 @@
+// Copyright (C) 2012  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 DATASRC_MEMORY_RDATA_ENCODER_H
+#define DATASRC_MEMORY_RDATA_ENCODER_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <dns/labelsequence.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <vector>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief General error in RDATA encoding.
+///
+/// This is thrown when \c RdataEncoder encounters a rare, unsupported
+/// situation. a method is called for a name or RRset which
+/// is not in or below the zone.
+class RdataEncodingError : public Exception {
+public:
+    RdataEncodingError(const char* file, size_t line, const char* what) :
+        Exception(file, line, what) {}
+};
+
+/// \brief RDATA encoder.
+///
+/// This class provides interfaces to encode a set of RDATA of a specific
+/// RR class and type, possibly with their RRSIG RDATAs, in a memory-efficient
+/// format.  In many cases these sets of RDATA come from a specific (signed
+/// or unsigned) RRset.
+///
+/// It is expected for a single \c RdataEncoder object to be used multiple
+/// times for different sets of RDATA, such as in loading an entire zone
+/// into memory.  Each encoding session begins with the \c start() method,
+/// which sets the context for the specific RR class and type to be encoded.
+/// Any number of calls to \c addRdata() or \c addSIGRdata() follow, each
+/// of which updates the internal state of the encoder with the encoding
+/// information for the given RDATA or RRSIG RDATA, respectively.
+/// The \c addRdata() is expected to be called with an
+/// \c isc::dns::rdata::Rdata object
+/// of the specified class and type, and \c addRdata() checks the consistency
+/// for the purpose of encoding (but it's not completely type safe; for
+/// example, it wouldn't distinguish TXT RDATA and HINFO RDATA.
+/// Likewise, an \c isc::dns::rdata::Rdata given to \c addSIGRdata() is
+/// expected to be of RRSIG, but the method does not check the assumption).
+///
+/// After passing the complete set of RDATA and their RRSIG, the application
+/// is expected to call \c getStorageLength() to know the size of storage
+/// that is sufficient to store all encoded data.  Normally the application
+/// would allocate a memory region of that size, and then call \c encode()
+/// with the prepared region.  The \c encode() method dumps encoded data
+/// to the given memory region.
+///
+/// The caller can reuse the \c RdataEncoder object for another set of RDATA
+/// by repeating the session from \c start().
+class RdataEncoder : boost::noncopyable {
+public:
+    /// \brief Default constructor.
+    RdataEncoder();
+
+    /// \brief The destrcutor.
+    ~RdataEncoder();
+
+    /// \brief Start the encoding session.
+    ///
+    /// It re-initializes the internal encoder state for a new encoding
+    /// session.  The \c rrclass and \c rrtype parameters specify the
+    /// type of RDATA to be encoded in the new session.  Note that if the
+    /// set of RDATA is signed, \c rrtype always specifies the "signed" type;
+    /// it must not be RRSIG.
+    ///
+    /// \throw BadValue RRSIG is specified for rrtype.
+    ///
+    /// \param rrclass The RR class of RDATA to be encoded in the session.
+    /// \param rrtype The RR type of RDATA to be encoded in the session.
+    void start(dns::RRClass rrclass, dns::RRType rrtype);
+
+    /// \brief Add an RDATA for encoding.
+    ///
+    /// This method updates internal state of the \c RdataEncoder() with the
+    /// given RDATA so it will be part of the encoded data in a subsequent
+    /// call to \c encode().
+    ///
+    /// The given \c rdata must be of the RR class and type specified at
+    /// the prior call to \c start().  This method checks the assumption
+    /// to some extent, but the check is not complete; this is generally
+    /// the responsibility of the caller.
+    ///
+    /// The caller can destroy \c rdata after this call is completed.
+    ///
+    /// \note This implementation does not support RDATA (or any subfield of
+    /// it) whose size exceeds 65535 bytes (max uint16_t value).  Such RDATA
+    /// may not necessarily be considered invalid in terms of protocol
+    /// specification, but in practice it's mostly useless because the
+    /// corresponding RR won't fit in any valid DNS message.
+    ///
+    /// As long as the \c rdata is of the correct type and its size is normal,
+    /// this method should normally be exception free.  If it throws, however,
+    /// it doesn't always provide the strong exception guarantee.  In general,
+    /// the caller needs to either destroy the encoder object or restart a
+    /// new session from \c start() should this method throws an exception.
+    ///
+    /// \throw InvalidOperation called before start().
+    /// \throw BadValue inconsistent data found.
+    /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
+    /// \throw std::bad_alloc Internal memory allocation failure.
+    ///
+    /// \param rdata An RDATA to be encoded in the session.
+    void addRdata(const dns::rdata::Rdata& rdata);
+
+    /// \brief Add an RRSIG RDATA for encoding.
+    ///
+    /// This method updates internal state of the \c RdataEncoder() with the
+    /// given RDATA, which is assumed to be of type RRSIG that covers the
+    /// type specified at the time of \c start() for the encoding session.
+    /// The corresponding data for the RRSIG RDATA will be encoded in a
+    /// subsequent call to \c encode().
+    ///
+    /// The passed \c sig_rdata is expected to be of type RRSIG and cover
+    /// the RR type specified at the call to \c start() to this encoding
+    /// session.  But this method does not check if it is the case at all;
+    /// it could even accept any type of RDATA as opaque data.  It's caller's
+    /// responsibility to ensure the assumption.
+    ///
+    /// The caller can destroy \c rdata after this call is completed.
+    ///
+    /// \note Like addRdata(), this implementation does not support
+    /// RRSIG RDATA whose size (in the form of wire format) exceeds 65535
+    /// bytes.
+    ///
+    /// The same note about exception safety as \c addRdata() applies.
+    ///
+    /// \throw InvalidOperation called before start().
+    /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
+    /// \throw std::bad_alloc Internal memory allocation failure.
+    ///
+    /// \param sig_rdata An RDATA to be encoded in the session.  Supposed to
+    /// be of type RRSIG.
+    void addSIGRdata(const dns::rdata::Rdata& sig_rdata);
+
+    /// \brief Return the length of space for encoding for the session.
+    ///
+    /// It returns the size of the encoded data that would be generated for
+    /// the set of RDATA (and RRSIGs) in the encoder at the call of this
+    /// method.  It's ensured that a buffer of that size can be safely passed
+    /// to \c encode() unless there's no other "add" method is called by then.
+    ///
+    /// As long as this method is called after start(), it never throws.
+    ///
+    /// \throw InvalidOperation called before start().
+    ///
+    /// \return The expected size of the encoded data at the time of the call.
+    size_t getStorageLength() const;
+
+    /// \brief Encode RDATAs of the session to a buffer.
+    ///
+    /// This method dumps encoded data for the stored set of RDATA and
+    /// their RRSIGs to a given buffer.  The buffer must have a size
+    /// at least as large as the return value of a prior call to
+    /// \c getStorageLength() (it may be larger than that).
+    ///
+    /// The given buffer must be aligned at the natural boundary for
+    /// 16-bit integers.  The method doesn't check this condition; it's
+    /// caller's responsibility to ensure that.  Note: the alignment
+    /// requirement may change in a future version of this implementation.
+    ///
+    /// As long as this method is called after start() and the buffer is
+    /// valid with a sufficient size, this method never throws.
+    ///
+    /// \throw InvalidOperation called before start().
+    /// \throw BadValue buffer is NULL or it's too short for the encoded data.
+    ///
+    /// \param buf A pointer to the buffer to which encoded data are to be
+    /// dumped.
+    /// \param buf_len The size of the buffer in bytes.
+    void encode(void* buf, size_t buf_len) const;
+
+private:
+    struct RdataEncoderImpl;
+    RdataEncoderImpl* impl_;
+};
+
+/// \brief Attributes of domain name fields of encoded RDATA.
+///
+/// The enum values define special traits of the name that can affect how
+/// it should be handled in rendering or query processing.
+enum RdataNameAttributes {
+    NAMEATTR_NONE = 0,          ///< No special attributes
+    NAMEATTR_COMPRESSIBLE = 1,  ///< Name should be compressed when rendered
+    NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
+                                                      ///< Additional section
+                                                      ///< handling
+};
+
+class RdataEncodeSpec;
+
+/// \brief Class to read serialized rdata
+///
+/// This class allows you to read the data encoded by RdataEncoder.
+/// It is rather low-level -- it provides sequence of data fields.
+/// Each field is either opaque data, passed as a pointer and length,
+/// or a name, in the form of dns::LabelSequence (which is always
+/// absolute) and attributes.
+///
+/// Conceptually, these fields correspond to consecutive regions in
+/// wire-format representation of the RDATA, varying the type of above
+/// two cases depending on whether the region corresponds to a domain
+/// name or other data.  For example, for an MX RDATA the field
+/// sequence will be
+/// - 2 bytes of opaque data (which corresponds to the MX preference)
+/// - a domain name (which corresponds to the MX name)
+///
+/// If the encoded data contain multiple MX RDATAs, the same type of
+/// sequence continues for the number of RDATAs.  Note that the opaque
+/// data field does not always corresponds to a specific RDATA field
+/// as is the 2-byte preference field of MX.  For example, the field
+/// sequence for an SOA RDATA in terms of RdataEncoder will be:
+/// - a domain name (which corresponds to the SOA MNAME)
+/// - a domain name (which corresponds to the SOA RNAME)
+/// - 20 bytes of opaque data (for the rest of fields)
+///
+/// So, if you want to construct a general purpose dns::Rdata object
+/// from the field sequence, you'll need to build the complete
+/// wire-format data, and then construct a dns::Rdata object from it.
+///
+/// To use it, contstruct it with the data you got from RDataEncoder,
+/// provide it with callbacks and then iterate through the data.
+/// The callbacks are called with the data fields contained in the
+/// data.
+///
+/// \code
+/// void handleName(const dns::LabelSequence& labels, unsigned int flags) {
+///     ...
+/// }
+/// void handleData(const void* data, size_t size) {
+///     ...
+/// }
+///
+/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
+///                    &handleName, &handleData);
+/// reader.iterate();
+/// \endcode
+///
+/// \note It is caller's responsibility to pass valid data here. This means
+///     the data returned by RdataEncoder and the corresponding class and type.
+///     If this is not the case, all the kinds of pointer hell might get loose.
+class RdataReader {
+public:
+    /// \brief Function called on each name encountered in the data.
+    typedef boost::function<void(const dns::LabelSequence&,
+                                 RdataNameAttributes)> NameAction;
+    /// \brief Function called on each data field in the data.
+    typedef boost::function<void(const void*, size_t)> DataAction;
+
+    /// \brief Constructor
+    ///
+    /// This constructs the reader on top of some serialized data.
+    /// It does not copy the data, you have to make sure the data
+    /// is valid for the whole life of this object and that they
+    /// don't change.
+    ///
+    /// \param rrclass The class the encoded rdata belongs to.
+    /// \param rrtype The type of the encode rdata.
+    /// \param data The actual data.
+    /// \param rdata_count The number of Rdata encoded in the data.
+    /// \param sig_count The number of RRSig rdata bundled with the data.
+    /// \param name_action The callback to be called on each encountered name.
+    /// \param data_action The callback to be called on each data chunk.
+    RdataReader(const dns::RRClass& rrclass, const dns::RRType& rrtype,
+                const void* data, size_t rdata_count, size_t sig_count,
+                const NameAction& name_action, const DataAction& data_action);
+
+    /// \brief Result of next() and nextSig()
+    ///
+    /// This specifies if there's any boundary in the data at the
+    /// place where the corresponding call to next() or nextSig()
+    /// finished.
+    enum Boundary {
+        NO_BOUNDARY,    ///< It is in the middle of Rdata
+        RDATA_BOUNDARY, ///< At the end of single Rdata
+        RRSET_BOUNDARY  ///< At the end of the RRset (past the end)
+    };
+
+    /// \brief Step to next data field.
+    ///
+    /// Iterate over the next field and call appropriate hook (name_action
+    /// or data_action, depending on the type) as passed to the constructor.
+    ///
+    /// \return It returns NO_BOUNDARY if the next call to next() will process
+    ///     data of the same rdata as this one. RDATA_BOUNDARY is returned when
+    ///     this field is the last of the current rdata. If there are no more
+    ///     data to process, no hook is called and RRSET_BOUNDARY is returned.
+    ///     Therefore, at the end of the whole data, once it processes the last
+    ///     field and returns RDATA_BOUNDARY and then it returns RRSET_BOUNDARY
+    ///     on the next call.
+    Boundary next();
+
+    /// \brief Call next() until the end.
+    ///
+    /// This is just convenience method to iterate through all the data.
+    /// It calls next until it reaches the end (it does not rewind beforehand,
+    /// therefore if you already called next() yourself, it does not start
+    /// at the beginning).
+    void iterate() {
+        while (next() != RRSET_BOUNDARY) {}
+    }
+
+    /// \brief Call next() until the end of current rdata.
+    ///
+    /// This is a convenience method to iterate until the end of current
+    /// rdata. Notice this may cause more than one field being processed,
+    /// as some rrtypes are more complex.
+    ///
+    /// \return If there was Rdata to iterate through.
+    bool iterateRdata() {
+        while (true) {
+            switch (next()) {
+                case NO_BOUNDARY: break;
+                case RDATA_BOUNDARY: return (true);
+                case RRSET_BOUNDARY: return (false);
+            }
+        }
+    }
+
+    /// \brief Step to next field of RRSig data.
+    ///
+    /// This is almost the same as next(), but it iterates through the
+    /// associated RRSig data, not the data for the given RRType.
+    Boundary nextSig();
+
+    /// \brief Iterate through all RRSig data.
+    ///
+    /// This is almost the same as iterate(), but it iterates through the
+    /// RRSig data instead.
+    void iterateAllSigs() {
+        while (nextSig() != RRSET_BOUNDARY) {}
+    }
+
+    /// \brief Iterate through the current RRSig Rdata.
+    ///
+    /// This is almote the same as iterateRdata, except it is for single
+    /// signature Rdata.
+    ///
+    /// In practice, this should process one DATA field.
+    bool iterateSingleSig() {
+        while (true) {
+            switch (nextSig()) {
+                case NO_BOUNDARY: break;
+                case RDATA_BOUNDARY: return (true);
+                case RRSET_BOUNDARY: return (false);
+            }
+        }
+    }
+
+    /// \brief Rewind the iterator to the beginnig of data.
+    ///
+    /// The following next() and nextSig() will start iterating from the
+    /// beginning again.
+    void rewind();
+
+    /// \brief Returns the size of associated data.
+    ///
+    /// This should be the same as the return value of
+    /// RdataEncoder::getStorageLength() for the same set of data.
+    /// The intended use of this method is to tell the caller the size of
+    /// data that were possibly dynamically allocated so that the caller can
+    /// use it for deallocation.
+    ///
+    /// This method only uses the parameters given at the construction of the
+    /// object, and does not rely on or modify other mutable states.
+    /// In practice, when the caller wants to call this method, that would be
+    /// the only purpose of that RdataReader object (although it doesn't have
+    /// to be so).
+    size_t getSize() const;
+private:
+    const NameAction name_action_;
+    const DataAction data_action_;
+    const RdataEncodeSpec& spec_;
+    // Total number of var-length fields, count of signatures
+    const size_t var_count_total_, sig_count_, spec_count_;
+    // Pointer to the beginning of length fields
+    const uint16_t* const lengths_;
+    // Pointer to the beginning of the data (after the lengths)
+    const uint8_t* const data_;
+    // Pointer to the first data signature
+    // Will be computed during the normal RR iteration
+    const uint8_t* sigs_;
+    // The positions in data.
+    size_t data_pos_, spec_pos_, length_pos_;
+    size_t sig_pos_, sig_data_pos_;
+    Boundary nextInternal(const NameAction& name_action,
+                          const DataAction& data_action);
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_RDATA_ENCODER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/rdata_serialization_priv.cc b/src/lib/datasrc/memory/rdata_serialization_priv.cc
new file mode 100644
index 0000000..23bdf53
--- /dev/null
+++ b/src/lib/datasrc/memory/rdata_serialization_priv.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2012  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.
+
+// This file is directly included from the rdata_serialization.cc. It would
+// be part of the file if we didn't need to steal some definitions from here
+// for the tests (which include it too).
+
+struct RdataFieldSpec {
+    enum FieldType {
+        FIXEDLEN_DATA = 0,      // fixed-length data field
+        VARLEN_DATA,            // variable-length data field
+        DOMAIN_NAME             // domain name
+    };
+
+    const FieldType type;       // field type
+
+    // The length of fixed-length data field.  Only valid for FIXEDLEN_DATA.
+    // For type DOMAIN_NAME, set it to 0.
+    const uint16_t fixeddata_len;
+
+    // Attributes of the name.  Only valid for DOMAIN_NAME.
+    // For type _DATA, set it to NAMEATTR_NONE.
+    const RdataNameAttributes name_attributes;
+};
+
+/// Specification of RDATA in terms of internal encoding.
+///
+/// The fields must be a sequence of:
+/// <0 or 1 fixed/var-len data field>,
+/// <1 or more domain name fields>,
+/// <1 fixed/var-len data field>,
+/// <1 or more domain name fields>,
+/// <1 fixed/var-len data field>,
+/// ...and so on.
+/// There must not be more than one consecutive data fields (i.e., without
+/// interleaved by a domain name); it would just be inefficient in terms of
+/// memory footprint and iterating over the fields, and it would break
+/// some assumption within the encoder implementation.  For consecutive
+/// data fields in the DNS protocol, if all fields have fixed lengths, they
+/// should be combined into a single fixed-length field (like the last 20
+/// bytes of SOA RDATA).  If there's a variable length field, they should be
+/// combined into a single variable-length field (such as DNSKEY, which has
+/// 3 fixed-length fields followed by one variable-length field).
+struct RdataEncodeSpec {
+    const uint16_t field_count; // total number of fields (# of fields member)
+    const uint16_t name_count;  // number of domain name fields
+    const uint16_t varlen_count; // number of variable-length data fields
+    const RdataFieldSpec* const fields; // list of field specs
+};
+
+/// \brief Get the spec for given class and type
+const RdataEncodeSpec&
+getRdataEncodeSpec(const RRClass& rrclass, const RRType& rrtype);
diff --git a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc b/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
index b7a13d9..12b613a 100644
--- a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
+++ b/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
@@ -12,10 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// Note: This file tests both the rdata_encoder and rdata_reader. They are
-// tested together because they form kind the opposite sides of the same
-// functionality.
-
 #include <exceptions/exceptions.h>
 
 #include <util/buffer.h>
@@ -28,9 +24,7 @@
 #include <dns/rrclass.h>
 #include <dns/rrtype.h>
 
-#include <datasrc/memory/rdata_encoder.h>
-#include <datasrc/memory/rdata_field.h>
-#include <datasrc/memory/rdata_reader.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 #include <util/unittests/wiredata.h>
 
@@ -52,6 +46,18 @@ using isc::util::unittests::matchWireData;
 using std::string;
 using std::vector;
 
+// A trick to steal some private definitions of the implementation we use here
+
+namespace isc {
+namespace datasrc{
+namespace memory {
+
+#include "../rdata_serialization_priv.cc"
+
+}
+}
+}
+
 namespace {
 // This defines a tuple of test data used in test_rdata_list below.
 struct TestRdata {



More information about the bind10-changes mailing list