}
RdataReader::Result
-RdataReader::next() {
+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);
+ name_action(sequence, spec.name_attributes);
return (Result(sequence, spec.name_attributes));
} else {
const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
spec.fixeddata_len : lengths_[length_pos_ ++]);
Result result(data_ + data_pos_, length);
data_pos_ += length;
- data_action_(result.data(), result.size());
+ data_action(result.data(), result.size());
return (result);
}
} else {
}
}
+RdataReader::Result
+RdataReader::next() {
+ return (nextInternal(name_action_, data_action_));
+}
+
RdataReader::Result
RdataReader::nextSig() {
if (sig_pos_ < sig_count_) {
size_t spec_pos = spec_pos_;
size_t length_pos = length_pos_;
// When the next() gets to the last item, it sets the sigs_
- iterate();
+ while (nextInternal(emptyNameAction, emptyDataAction)) {}
assert(sigs_ != NULL);
// Return the state
data_pos_ = data_pos;
}
};
+// Decode using reader with the return value of next, but after the reader
+// was used and rewund.
+class RewundDecoder {
+public:
+ static void decode(const isc::dns::RRClass& rrclass,
+ const isc::dns::RRType& rrtype,
+ size_t rdata_count, size_t sig_count, size_t,
+ const vector<uint8_t>& encoded_data,
+ MessageRenderer& renderer)
+ {
+ RdataReader reader(rrclass, rrtype, encoded_data.size(),
+ &encoded_data[0], rdata_count, sig_count);
+ // Use the reader first and rewind it
+ reader.iterateSig();
+ reader.iterate();
+ reader.rewind();
+ RdataReader::Result field;
+ while (field = reader.next()) {
+ switch (field.type()) {
+ case RdataReader::DATA:
+ renderer.writeData(field.data(), field.size());
+ break;
+ case RdataReader::NAME:
+ renderer.writeName(field.label(), field.compressible());
+ break;
+ default:
+ FAIL();
+ }
+ }
+
+ renderer.writeName(dummy_name2);
+
+ while (field = reader.nextSig()) {
+ switch (field.type()) {
+ case RdataReader::DATA:
+ renderer.writeData(field.data(), field.size());
+ break;
+ default: // There are also no NAME fields in RRSigs
+ FAIL();
+ }
+ }
+ }
+};
+
// Check using callbacks and calling next until the end.
class CallbackDecoder {
public:
}
};
-typedef ::testing::Types<ManualDecoderStyle, NextDecoder, CallbackDecoder,
- IterateDecoder> DecoderStyles;
+// This one does not adhere to the usual way the reader is used, trying
+// to confuse it. It iterates part of the data manually and then reads
+// the rest through iterate. It also reads the signatures in the middle
+// of rendering.
+template<bool start_data, bool start_sig>
+class HybridDecoder {
+private:
+ // Append data either to the renderer or to the vector passed.
+ // The double pointer is there so we can change the renderer to NULL
+ // and back during the test.
+ static void appendData(vector<uint8_t>* where, MessageRenderer** renderer,
+ const uint8_t* data, size_t size)
+ {
+ if (*renderer != NULL) {
+ (*renderer)->writeData(data, size);
+ } else {
+ where->insert(where->end(), data, data + size);
+ }
+ }
+public:
+ static void decode(const isc::dns::RRClass& rrclass,
+ const isc::dns::RRType& rrtype,
+ size_t rdata_count, size_t sig_count, size_t,
+ const vector<uint8_t>& encoded_data,
+ MessageRenderer& renderer)
+ {
+ vector<uint8_t> data;
+ MessageRenderer* current;
+ RdataReader reader(rrclass, rrtype, encoded_data.size(),
+ &encoded_data[0], rdata_count, sig_count,
+ boost::bind(renderNameField, &renderer,
+ additionalRequired(rrtype), _1, _2),
+ boost::bind(appendData, &data, ¤t, _1, _2));
+ if (start_sig) {
+ current = NULL;
+ reader.nextSig();
+ }
+ // Render first part of data. If there's none, return empty Result and
+ // do nothing.
+ if (start_data) {
+ current = &renderer;
+ reader.next();
+ }
+ // Now, we let all sigs to be copied to data. We disable the
+ // renderer for this.
+ current = NULL;
+ reader.iterateSig();
+ // Now return the renderer and render the rest of the data
+ current = &renderer;
+ reader.iterate();
+ // Now, this should not break anything and should be valid, but should
+ // return ends.
+ EXPECT_FALSE(reader.next());
+ EXPECT_FALSE(reader.nextSig());
+ // Render the name and the sigs
+ renderer.writeName(dummy_name2);
+ renderer.writeData(&data[0], data.size());
+ }
+};
+
+typedef ::testing::Types<ManualDecoderStyle, NextDecoder, RewundDecoder,
+ CallbackDecoder, IterateDecoder,
+ HybridDecoder<true, true>, HybridDecoder<true, false>,
+ HybridDecoder<false, true>,
+ HybridDecoder<false, false> >
+ DecoderStyles;
TYPED_TEST_CASE(RdataEncodeDecodeTest, DecoderStyles);
void