Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __TXT_LIKE_H
16 : : #define __TXT_LIKE_H 1
17 : :
18 : : #include <stdint.h>
19 : :
20 : : #include <string>
21 : : #include <vector>
22 : :
23 : : using namespace std;
24 : : using namespace isc::util;
25 : :
26 : : /// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT
27 : : /// and SPF types.
28 : : ///
29 : : /// This class implements the basic interfaces inherited by the TXT and SPF
30 : : /// classes from the abstract \c rdata::Rdata class, and provides trivial
31 : : /// accessors to TXT-like RDATA.
32 : 7500 : template<class Type, uint16_t typeCode>class TXTLikeImpl {
33 : : public:
34 : : /// \brief Constructor from wire-format data.
35 : : ///
36 : : /// \param buffer A buffer storing the wire format data.
37 : : /// \param rdata_len The length of the RDATA in bytes, normally expected
38 : : /// to be the value of the RDLENGTH field of the corresponding RR.
39 : : ///
40 : : /// <b>Exceptions</b>
41 : : ///
42 : : /// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum.
43 : : /// \c DNSMessageFORMERR is thrown if the RR is misformed.
44 : 7 : TXTLikeImpl(InputBuffer& buffer, size_t rdata_len) {
45 [ + + ][ + + ]: 17 : if (rdata_len > MAX_RDLENGTH) {
46 [ + - ][ + - ]: 6 : isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
[ + - ][ + - ]
[ + - ][ + - ]
47 : : }
48 : :
49 [ + + ][ + + ]: 15 : if (rdata_len == 0) { // note that this couldn't happen in the loop.
50 [ + - ][ + - ]: 17 : isc_throw(DNSMessageFORMERR, "Error in parsing " <<
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
51 : : RRType(typeCode) << " RDATA: 0-length character string");
52 : : }
53 : :
54 [ + + + + ]: 524 : do {
55 [ + - ][ + - ]: 527 : const uint8_t len = buffer.readUint8();
56 [ + + ][ + + ]: 527 : if (rdata_len < len + 1) {
57 [ + - ][ + - ]: 6 : isc_throw(DNSMessageFORMERR, "Error in parsing " <<
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
58 : : RRType(typeCode) <<
59 : : " RDATA: character string length is too large: " <<
60 : : static_cast<int>(len));
61 : : }
62 [ + - ][ + - ]: 524 : vector<uint8_t> data(len + 1);
63 : 524 : data[0] = len;
64 [ + - ][ + - ]: 524 : buffer.readData(&data[0] + 1, len);
65 [ + - ][ + - ]: 524 : string_list_.push_back(data);
66 : :
67 : 524 : rdata_len -= (len + 1);
68 : : } while (rdata_len > 0);
69 : 10 : }
70 : :
71 : : /// \brief Constructor from string.
72 : : ///
73 : : /// <b>Exceptions</b>
74 : : ///
75 : : /// \c CharStringTooLong is thrown if the parameter string length exceeds
76 : : /// maximum.
77 : : /// \c InvalidRdataText is thrown if the method cannot process the
78 : : /// parameter data.
79 : 7 : explicit TXTLikeImpl(const std::string& txtstr) {
80 : : // TBD: this is a simple, incomplete implementation that only supports
81 : : // a single character-string.
82 : :
83 : 3877 : size_t length = txtstr.size();
84 : 3877 : size_t pos_begin = 0;
85 : :
86 [ + + ][ + + ]: 3877 : if (length > 1 && txtstr[0] == '"' && txtstr[length - 1] == '"') {
[ - + ][ + + ]
[ + + ][ + + ]
[ - + ][ + + ]
87 : 48 : pos_begin = 1;
88 : 48 : length -= 2;
89 : : }
90 : :
91 [ + + ][ + + ]: 3877 : if (length > MAX_CHARSTRING_LEN) {
92 [ + - ][ + - ]: 9 : isc_throw(CharStringTooLong, RRType(typeCode) <<
[ + - ][ + - ]
[ + - ][ + - ]
93 : : " RDATA construction from text:"
94 : : " string length is too long: " << length);
95 : : }
96 : :
97 : : // TBD: right now, we don't support escaped characters
98 [ + - ][ + + ]: 3874 : if (txtstr.find('\\') != string::npos) {
[ + - ][ + + ]
99 [ + - ][ + - ]: 8 : isc_throw(InvalidRdataText, RRType(typeCode) <<
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
100 : : " RDATA from text:"
101 : : " escaped character is currently not supported: " <<
102 : : txtstr);
103 : : }
104 : :
105 : : vector<uint8_t> data;
106 [ + - ][ + - ]: 3870 : data.reserve(length + 1);
107 [ + - ][ + - ]: 3870 : data.push_back(length);
108 [ + - ][ + - ]: 3870 : data.insert(data.end(), txtstr.begin() + pos_begin,
109 : : txtstr.begin() + pos_begin + length);
110 [ + - ][ + - ]: 3870 : string_list_.push_back(data);
111 : 3870 : }
112 : :
113 : : /// \brief The copy constructor.
114 : : ///
115 : : /// Trivial for now, we could've used the default one.
116 : : TXTLikeImpl(const TXTLikeImpl& other) :
117 [ + - + - ]: 3620 : string_list_(other.string_list_)
[ + - + - ]
118 : : {}
119 : :
120 : : /// \brief Render the TXT-like data in the wire format to an OutputBuffer
121 : : /// object.
122 : : ///
123 : : /// \param buffer An output buffer to store the wire data.
124 : : void
125 : 282 : toWire(OutputBuffer& buffer) const {
126 [ + + ][ + + ]: 1076 : for (vector<vector<uint8_t> >::const_iterator it =
127 : 1358 : string_list_.begin();
128 : : it != string_list_.end();
129 : : ++it)
130 : : {
131 : 794 : buffer.writeData(&(*it)[0], (*it).size());
132 : : }
133 : 282 : }
134 : :
135 : : /// \brief Render the TXT-like data in the wire format to an
136 : : /// AbstractMessageRenderer object.
137 : : ///
138 : : /// \param buffer An output AbstractMessageRenderer to send the wire data
139 : : /// to.
140 : : void
141 : : toWire(AbstractMessageRenderer& renderer) const {
142 [ + + ][ + + ]: 46 : for (vector<vector<uint8_t> >::const_iterator it =
143 : 22 : string_list_.begin();
144 : : it != string_list_.end();
145 : : ++it)
146 : : {
147 : 24 : renderer.writeData(&(*it)[0], (*it).size());
148 : : }
149 : : }
150 : :
151 : : /// \brief Convert the TXT-like data to a string.
152 : : ///
153 : : /// \return A \c string object that represents the TXT-like data.
154 : : string
155 : : toText() const {
156 : 0 : string s;
157 : :
158 : : // XXX: this implementation is not entirely correct. for example, it
159 : : // should escape double-quotes if they appear in the character string.
160 [ + + ][ + + ]: 80 : for (vector<vector<uint8_t> >::const_iterator it =
161 : 40 : string_list_.begin();
162 : : it != string_list_.end();
163 : : ++it)
164 : : {
165 [ - + ][ - + ]: 40 : if (!s.empty()) {
166 [ # # ][ # # ]: 0 : s.push_back(' ');
167 : : }
168 [ + - ][ + - ]: 40 : s.push_back('"');
169 [ + - ][ + - ]: 40 : s.insert(s.end(), (*it).begin() + 1, (*it).end());
[ + - ][ + - ]
170 [ + - ][ + - ]: 40 : s.push_back('"');
171 : : }
172 : :
173 : : return (s);
174 : : }
175 : :
176 : : /// \brief Compare two instances of TXT-like RDATA.
177 : : ///
178 : : /// It is up to the caller to make sure that \c other is an object of the
179 : : /// same \c TXTLikeImpl class.
180 : : ///
181 : : /// \param other the right-hand operand to compare against.
182 : : /// \return < 0 if \c this would be sorted before \c other.
183 : : /// \return 0 if \c this is identical to \c other in terms of sorting
184 : : /// order.
185 : : /// \return > 0 if \c this would be sorted after \c other.
186 : : int
187 : 135 : compare(const TXTLikeImpl& other) const {
188 : : // This implementation is not efficient. Revisit this (TBD).
189 : 135 : OutputBuffer this_buffer(0);
190 [ + - + - ]: 135 : toWire(this_buffer);
191 : 135 : uint8_t const* const this_data = (uint8_t const*)this_buffer.getData();
192 : 135 : size_t this_len = this_buffer.getLength();
193 : :
194 [ + - ][ + - ]: 135 : OutputBuffer other_buffer(0);
195 [ + - ][ + - ]: 135 : other.toWire(other_buffer);
196 : : uint8_t const* const other_data
197 : 135 : = (uint8_t const*)other_buffer.getData();
198 : 135 : const size_t other_len = other_buffer.getLength();
199 : :
200 : 135 : const size_t cmplen = min(this_len, other_len);
201 : 135 : const int cmp = memcmp(this_data, other_data, cmplen);
202 : :
203 [ + + ][ + + ]: 135 : if (cmp != 0) {
204 : : return (cmp);
205 : : } else {
206 : : return ((this_len == other_len) ? 0 :
207 [ - + ][ # # ]: 109 : (this_len < other_len) ? -1 : 1);
[ - + ][ # # ]
208 : : }
209 : : }
210 : :
211 : : private:
212 : : /// Note: this is a prototype version; we may reconsider
213 : : /// this representation later.
214 : : std::vector<std::vector<uint8_t> > string_list_;
215 : : };
216 : :
217 : : // END_RDATA_NAMESPACE
218 : : // END_ISC_NAMESPACE
219 : :
220 : : #endif // __TXT_LIKE_H
221 : :
222 : : // Local Variables:
223 : : // mode: c++
224 : : // End:
|