]>
Commit | Line | Data |
---|---|---|
4192ca66 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
e4090157 | 3 | Copyright (C) 2005 - 2011 PowerDNS.COM BV |
4192ca66 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License version 2 as | |
7 | published by the Free Software Foundation | |
8 | ||
f782fe38 MH |
9 | Additionally, the license of this program contains a special |
10 | exception which allows to distribute the program in binary form when | |
11 | it is linked against OpenSSL. | |
12 | ||
4192ca66 BH |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
06bd9ccf | 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4192ca66 BH |
21 | */ |
22 | ||
23 | #include "rcpgenerator.hh" | |
20133c59 | 24 | #include "dnsparser.hh" |
cbf0e7f3 | 25 | #include "misc.hh" |
4192ca66 | 26 | #include <boost/lexical_cast.hpp> |
12b33ac2 | 27 | #include <boost/algorithm/string.hpp> |
4192ca66 | 28 | #include <iostream> |
1c4d88c5 | 29 | #include "base32.hh" |
8c1c9170 | 30 | #include "base64.hh" |
d2d6cf61 | 31 | #include "namespaces.hh" |
4192ca66 BH |
32 | |
33 | RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size()) | |
34 | { | |
35 | } | |
36 | ||
341930bb BH |
37 | void RecordTextReader::xfr48BitInt(uint64_t &val) |
38 | { | |
39 | xfr64BitInt(val); | |
40 | } | |
41 | ||
42 | void RecordTextReader::xfr64BitInt(uint64_t &val) | |
43 | { | |
44 | skipSpaces(); | |
45 | ||
46 | if(!isdigit(d_string.at(d_pos))) | |
47 | throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'"); | |
48 | ||
49 | char *endptr; | |
50 | unsigned long ret=strtoull(d_string.c_str() + d_pos, &endptr, 10); | |
51 | val=ret; | |
52 | ||
53 | d_pos = endptr - d_string.c_str(); | |
54 | } | |
55 | ||
56 | ||
cbf0e7f3 | 57 | void RecordTextReader::xfr32BitInt(uint32_t &val) |
4192ca66 BH |
58 | { |
59 | skipSpaces(); | |
60 | ||
61 | if(!isdigit(d_string.at(d_pos))) | |
62 | throw RecordTextException("expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'"); | |
63 | ||
64 | char *endptr; | |
f55691d1 | 65 | unsigned long ret=pdns_strtoui(d_string.c_str() + d_pos, &endptr, 10); |
58044407 | 66 | if (ret == UINT_MAX && errno == ERANGE) throw RecordTextException("serial number too large in '"+d_string+"'"); |
4192ca66 BH |
67 | val=ret; |
68 | ||
69 | d_pos = endptr - d_string.c_str(); | |
70 | } | |
71 | ||
8bf26468 BH |
72 | void RecordTextReader::xfrTime(uint32_t &val) |
73 | { | |
74 | struct tm tm; | |
75 | memset(&tm, 0, sizeof(tm)); | |
76 | ||
77 | string tmp; | |
78 | xfrLabel(tmp); // ends on number, so this works | |
79 | ||
80 | sscanf(tmp.c_str(), "%04d%02d%02d" "%02d%02d%02d", | |
4957a608 BH |
81 | &tm.tm_year, &tm.tm_mon, &tm.tm_mday, |
82 | &tm.tm_hour, &tm.tm_min, &tm.tm_sec); | |
8bf26468 BH |
83 | |
84 | tm.tm_year-=1900; | |
12b33ac2 | 85 | tm.tm_mon-=1; |
49f72da1 | 86 | val=(uint32_t)Utility::timegm(&tm); |
8bf26468 BH |
87 | } |
88 | ||
cbf0e7f3 BH |
89 | void RecordTextReader::xfrIP(uint32_t &val) |
90 | { | |
91 | skipSpaces(); | |
92 | ||
93 | if(!isdigit(d_string.at(d_pos))) | |
aab4adb0 | 94 | throw RecordTextException("while parsing IP address, expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'"); |
1149fa0b BH |
95 | |
96 | uint32_t octet=0; | |
97 | val=0; | |
98 | char count=0; | |
cbf0e7f3 | 99 | |
1149fa0b BH |
100 | for(;;) { |
101 | if(d_string.at(d_pos)=='.') { | |
102 | val<<=8; | |
103 | val+=octet; | |
104 | octet=0; | |
105 | count++; | |
106 | if(count > 3) | |
4957a608 | 107 | break; |
1149fa0b BH |
108 | } |
109 | else if(isdigit(d_string.at(d_pos))) { | |
110 | octet*=10; | |
111 | octet+=d_string.at(d_pos) - '0'; | |
112 | if(octet > 255) | |
4957a608 | 113 | throw RecordTextException("unable to parse IP address"); |
1149fa0b BH |
114 | } |
115 | else if(dns_isspace(d_string.at(d_pos))) | |
116 | break; | |
87c837a3 BH |
117 | else { |
118 | throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos)); | |
119 | } | |
1149fa0b BH |
120 | d_pos++; |
121 | if(d_pos == d_string.length()) | |
122 | break; | |
123 | } | |
124 | if(count<=3) { | |
125 | val<<=8; | |
126 | val+=octet; | |
127 | } | |
128 | val=ntohl(val); | |
cbf0e7f3 BH |
129 | } |
130 | ||
131 | ||
b9b28916 AT |
132 | void RecordTextReader::xfrIP6(std::string &val) |
133 | { | |
b9b28916 AT |
134 | struct in6_addr tmpbuf; |
135 | ||
136 | skipSpaces(); | |
b9b28916 AT |
137 | |
138 | size_t len; | |
cf90f8e1 | 139 | // lookup end of value - think of ::ffff encoding too, has dots in it! |
8d388c48 | 140 | for(len=0; |
cf90f8e1 | 141 | d_pos+len < d_string.length() && (isxdigit(d_string.at(d_pos+len)) || d_string.at(d_pos+len) == ':' || d_string.at(d_pos+len)=='.'); |
8d388c48 | 142 | len++); |
b9b28916 | 143 | |
8d388c48 | 144 | if(!len) |
145 | throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'"); | |
b9b28916 | 146 | |
8d388c48 | 147 | // end of value is here, try parse as IPv6 |
148 | string address=d_string.substr(d_pos, len); | |
149 | ||
150 | if (inet_pton(AF_INET6, address.c_str(), &tmpbuf) != 1) { | |
151 | throw RecordTextException("while parsing IPv6 address: '" + address + "' is invalid"); | |
b9b28916 AT |
152 | } |
153 | ||
154 | val = std::string((char*)tmpbuf.s6_addr, 16); | |
155 | ||
156 | d_pos += len; | |
157 | } | |
158 | ||
20133c59 BH |
159 | bool RecordTextReader::eof() |
160 | { | |
161 | return d_pos==d_end; | |
162 | } | |
163 | ||
cbf0e7f3 BH |
164 | void RecordTextReader::xfr16BitInt(uint16_t &val) |
165 | { | |
166 | uint32_t tmp; | |
167 | xfr32BitInt(tmp); | |
168 | val=tmp; | |
169 | if(val!=tmp) | |
170 | throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve | |
171 | } | |
172 | ||
8c1c9170 BH |
173 | void RecordTextReader::xfr8BitInt(uint8_t &val) |
174 | { | |
175 | uint32_t tmp; | |
176 | xfr32BitInt(tmp); | |
177 | val=tmp; | |
178 | if(val!=tmp) | |
179 | throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve | |
180 | } | |
181 | ||
7ecd3576 | 182 | // this code should leave all the escapes around |
35ce8576 | 183 | void RecordTextReader::xfrLabel(string& val, bool) |
4192ca66 BH |
184 | { |
185 | skipSpaces(); | |
29a14b24 BH |
186 | val.clear(); |
187 | val.reserve(d_end - d_pos); | |
188 | ||
d39704c0 | 189 | const char* strptr=d_string.c_str(); |
83b77f90 | 190 | string::size_type begin_pos = d_pos; |
29a14b24 | 191 | while(d_pos < d_end) { |
0a1825d6 | 192 | if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos])) |
29a14b24 | 193 | break; |
7ecd3576 | 194 | |
4192ca66 | 195 | d_pos++; |
29a14b24 | 196 | } |
83b77f90 BH |
197 | val.append(strptr+begin_pos, strptr+d_pos); |
198 | ||
4192ca66 BH |
199 | if(val.empty()) |
200 | val=d_zone; | |
bca6643b | 201 | else if(!d_zone.empty()) { |
cbf0e7f3 BH |
202 | char last=val[val.size()-1]; |
203 | ||
b0d4fb45 BH |
204 | if(last =='.') |
205 | val.resize(val.size()-1); | |
206 | else if(last != '.' && !isdigit(last)) // don't add zone to IP address | |
cbf0e7f3 BH |
207 | val+="."+d_zone; |
208 | } | |
4192ca66 BH |
209 | } |
210 | ||
2fe9d6f7 | 211 | static bool isbase64(char c, bool acceptspace) |
12b33ac2 BH |
212 | { |
213 | if(dns_isspace(c)) | |
2fe9d6f7 | 214 | return acceptspace; |
12b33ac2 BH |
215 | if(c >= '0' && c <= '9') |
216 | return true; | |
217 | if(c >= 'a' && c <= 'z') | |
218 | return true; | |
219 | if(c >= 'A' && c <= 'Z') | |
220 | return true; | |
221 | if(c=='+' || c=='/' || c=='=') | |
222 | return true; | |
223 | return false; | |
224 | } | |
225 | ||
2fe9d6f7 AT |
226 | void RecordTextReader::xfrBlobNoSpaces(string& val, int len) { |
227 | skipSpaces(); | |
228 | int pos=(int)d_pos; | |
229 | const char* strptr=d_string.c_str(); | |
230 | while(d_pos < d_end && isbase64(strptr[d_pos], false)) | |
231 | d_pos++; | |
232 | ||
233 | string tmp; | |
234 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
235 | boost::erase_all(tmp," "); | |
236 | val.clear(); | |
237 | B64Decode(tmp, val); | |
238 | ||
239 | if (len>-1 && val.size() != static_cast<size_t>(len)) | |
240 | throw RecordTextException("Record length "+lexical_cast<string>(val.size()) + " does not match expected length '"+lexical_cast<string>(len)); | |
241 | } | |
242 | ||
06ffdc52 | 243 | void RecordTextReader::xfrBlob(string& val, int) |
8c1c9170 BH |
244 | { |
245 | skipSpaces(); | |
705f31ae | 246 | int pos=(int)d_pos; |
d39704c0 | 247 | const char* strptr=d_string.c_str(); |
2fe9d6f7 | 248 | while(d_pos < d_end && isbase64(strptr[d_pos], true)) |
8c1c9170 | 249 | d_pos++; |
12b33ac2 | 250 | |
20133c59 BH |
251 | string tmp; |
252 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
12b33ac2 | 253 | boost::erase_all(tmp," "); |
20133c59 BH |
254 | val.clear(); |
255 | B64Decode(tmp, val); | |
8c1c9170 BH |
256 | } |
257 | ||
59a0f653 BH |
258 | |
259 | static inline uint8_t hextodec(uint8_t val) | |
260 | { | |
261 | if(val >= '0' && val<='9') | |
262 | return val-'0'; | |
263 | else if(val >= 'A' && val<='F') | |
264 | return 10+(val-'A'); | |
265 | else if(val >= 'a' && val<='f') | |
266 | return 10+(val-'a'); | |
267 | else | |
268 | throw RecordTextException("Unknown hexadecimal character '"+lexical_cast<string>(val)+"'"); | |
269 | } | |
270 | ||
271 | ||
4e75f84a | 272 | void HEXDecode(const char* begin, const char* end, string& out) |
59a0f653 | 273 | { |
3c873e66 | 274 | if(end - begin == 1 && *begin=='-') { |
4e75f84a | 275 | out.clear(); |
3c873e66 BH |
276 | return; |
277 | } | |
4e75f84a BH |
278 | out.clear(); |
279 | out.reserve((end-begin)/2); | |
280 | uint8_t mode=0, val=0; | |
281 | for(; begin != end; ++begin) { | |
282 | if(!isalnum(*begin)) | |
283 | continue; | |
284 | if(mode==0) { | |
285 | val = 16*hextodec(*begin); | |
286 | mode=1; | |
287 | } else { | |
288 | val += hextodec(*begin); | |
289 | out.append(1, (char) val); | |
290 | mode = 0; | |
291 | val = 0; | |
292 | } | |
59a0f653 | 293 | } |
4e75f84a BH |
294 | if(mode) |
295 | out.append(1, (char) val); | |
296 | ||
59a0f653 BH |
297 | } |
298 | ||
e4090157 | 299 | void RecordTextReader::xfrHexBlob(string& val, bool keepReading) |
59a0f653 BH |
300 | { |
301 | skipSpaces(); | |
705f31ae | 302 | int pos=(int)d_pos; |
e4090157 | 303 | while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) |
59a0f653 BH |
304 | d_pos++; |
305 | ||
306 | HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); | |
307 | } | |
308 | ||
8b606f6e BH |
309 | void RecordTextReader::xfrBase32HexBlob(string& val) |
310 | { | |
311 | skipSpaces(); | |
312 | int pos=(int)d_pos; | |
313 | while(d_pos < d_end && !dns_isspace(d_string[d_pos])) | |
314 | d_pos++; | |
315 | ||
316 | val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos)); | |
317 | } | |
318 | ||
319 | ||
1c4d88c5 BH |
320 | void RecordTextWriter::xfrBase32HexBlob(const string& val) |
321 | { | |
322 | if(!d_string.empty()) | |
323 | d_string.append(1,' '); | |
324 | ||
1bad4190 | 325 | d_string.append(toUpper(toBase32Hex(val))); |
1c4d88c5 BH |
326 | } |
327 | ||
328 | ||
ef6a78d5 | 329 | void RecordTextReader::xfrText(string& val, bool multi) |
4192ca66 | 330 | { |
4192ca66 BH |
331 | val.clear(); |
332 | val.reserve(d_end - d_pos); | |
ef6a78d5 BH |
333 | |
334 | while(d_pos != d_end) { | |
335 | if(!val.empty()) | |
336 | val.append(1, ' '); | |
337 | ||
338 | skipSpaces(); | |
2220e01f BH |
339 | if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes |
340 | string::size_type pos = d_pos; | |
341 | while(pos != d_end && isalnum(d_string[pos])) | |
342 | pos++; | |
343 | if(pos == d_end) { | |
344 | val.append(1, '"'); | |
345 | val.append(d_string.c_str() + d_pos, d_end - d_pos); | |
346 | val.append(1, '"'); | |
347 | d_pos = d_end; | |
348 | break; | |
349 | } | |
ef6a78d5 | 350 | throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'"); |
2220e01f | 351 | } |
ef6a78d5 BH |
352 | val.append(1, '"'); |
353 | while(++d_pos < d_end && d_string[d_pos]!='"') { | |
354 | if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { | |
4957a608 | 355 | val.append(1, d_string[d_pos++]); |
ef6a78d5 BH |
356 | } |
357 | val.append(1, d_string[d_pos]); | |
4192ca66 | 358 | } |
ef6a78d5 BH |
359 | val.append(1,'"'); |
360 | if(d_pos == d_end) | |
361 | throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); | |
362 | d_pos++; | |
363 | if(!multi) | |
364 | break; | |
4192ca66 | 365 | } |
4192ca66 BH |
366 | } |
367 | ||
20133c59 BH |
368 | void RecordTextReader::xfrType(uint16_t& val) |
369 | { | |
370 | skipSpaces(); | |
705f31ae | 371 | int pos=(int)d_pos; |
ec486449 | 372 | while(d_pos < d_end && !dns_isspace(d_string[d_pos])) |
20133c59 BH |
373 | d_pos++; |
374 | ||
375 | string tmp; | |
376 | tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); | |
377 | ||
378 | val=DNSRecordContent::TypeToNumber(tmp); | |
379 | } | |
4192ca66 | 380 | |
8c1c9170 | 381 | |
4192ca66 BH |
382 | void RecordTextReader::skipSpaces() |
383 | { | |
d39704c0 BH |
384 | const char* strptr = d_string.c_str(); |
385 | while(d_pos < d_end && dns_isspace(strptr[d_pos])) | |
4192ca66 | 386 | d_pos++; |
4192ca66 BH |
387 | if(d_pos == d_end) |
388 | throw RecordTextException("missing field at the end of record content '"+d_string+"'"); | |
389 | } | |
390 | ||
391 | ||
392 | RecordTextWriter::RecordTextWriter(string& str) : d_string(str) | |
393 | { | |
394 | d_string.clear(); | |
395 | } | |
396 | ||
341930bb | 397 | void RecordTextWriter::xfr48BitInt(const uint64_t& val) |
4192ca66 BH |
398 | { |
399 | if(!d_string.empty()) | |
400 | d_string.append(1,' '); | |
401 | d_string+=lexical_cast<string>(val); | |
402 | } | |
403 | ||
20133c59 | 404 | |
341930bb BH |
405 | void RecordTextWriter::xfr32BitInt(const uint32_t& val) |
406 | { | |
407 | if(!d_string.empty()) | |
408 | d_string.append(1,' '); | |
409 | d_string+=lexical_cast<string>(val); | |
410 | } | |
20133c59 BH |
411 | |
412 | void RecordTextWriter::xfrType(const uint16_t& val) | |
413 | { | |
414 | if(!d_string.empty()) | |
415 | d_string.append(1,' '); | |
416 | d_string+=DNSRecordContent::NumberToType(val); | |
417 | } | |
418 | ||
ec486449 | 419 | // this function is on the fast path for the pdns_recursor |
cbf0e7f3 BH |
420 | void RecordTextWriter::xfrIP(const uint32_t& val) |
421 | { | |
422 | if(!d_string.empty()) | |
423 | d_string.append(1,' '); | |
424 | ||
ec486449 | 425 | char tmp[17]; |
79a9e9ad | 426 | uint32_t ip=val; |
1149fa0b BH |
427 | uint8_t vals[4]; |
428 | ||
429 | memcpy(&vals[0], &ip, sizeof(ip)); | |
430 | ||
431 | char *pos=tmp; | |
432 | ||
433 | for(int n=0; n < 4; ++n) { | |
434 | if(vals[n]<10) { | |
435 | *(pos++)=vals[n]+'0'; | |
436 | } else if(vals[n] < 100) { | |
437 | *(pos++)=(vals[n]/10) +'0'; | |
438 | *(pos++)=(vals[n]%10) +'0'; | |
439 | } else { | |
440 | *(pos++)=(vals[n]/100) +'0'; | |
441 | vals[n]%=100; | |
442 | *(pos++)=(vals[n]/10) +'0'; | |
443 | *(pos++)=(vals[n]%10) +'0'; | |
444 | } | |
445 | if(n!=3) | |
446 | *(pos++)='.'; | |
447 | } | |
448 | *pos=0; | |
449 | d_string.append(tmp, pos); | |
cbf0e7f3 BH |
450 | } |
451 | ||
b9b28916 AT |
452 | void RecordTextWriter::xfrIP6(const std::string& val) |
453 | { | |
454 | char tmpbuf[16]; | |
455 | char addrbuf[40]; | |
456 | ||
457 | if(!d_string.empty()) | |
458 | d_string.append(1,' '); | |
459 | ||
460 | val.copy(tmpbuf,16); | |
461 | ||
462 | if (inet_ntop(AF_INET6, tmpbuf, addrbuf, sizeof addrbuf) == NULL) | |
463 | throw RecordTextException("Unable to convert to ipv6 address"); | |
464 | ||
465 | d_string += std::string(addrbuf); | |
466 | } | |
cbf0e7f3 | 467 | |
8bf26468 BH |
468 | void RecordTextWriter::xfrTime(const uint32_t& val) |
469 | { | |
470 | if(!d_string.empty()) | |
471 | d_string.append(1,' '); | |
472 | ||
473 | struct tm tm; | |
474 | time_t time=val; // Y2038 bug! | |
ab13b07b | 475 | Utility::gmtime_r(&time, &tm); |
76473b92 | 476 | |
8bf26468 BH |
477 | char tmp[16]; |
478 | snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d", | |
4957a608 BH |
479 | tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, |
480 | tm.tm_hour, tm.tm_min, tm.tm_sec); | |
8bf26468 BH |
481 | |
482 | d_string += tmp; | |
483 | } | |
484 | ||
485 | ||
cbf0e7f3 BH |
486 | void RecordTextWriter::xfr16BitInt(const uint16_t& val) |
487 | { | |
488 | xfr32BitInt(val); | |
489 | } | |
490 | ||
8c1c9170 BH |
491 | void RecordTextWriter::xfr8BitInt(const uint8_t& val) |
492 | { | |
493 | xfr32BitInt(val); | |
494 | } | |
495 | ||
7ecd3576 | 496 | // should not mess with the escapes |
bca6643b | 497 | void RecordTextWriter::xfrLabel(const string& val, bool) |
4192ca66 BH |
498 | { |
499 | if(!d_string.empty()) | |
500 | d_string.append(1,' '); | |
7ecd3576 BH |
501 | |
502 | d_string+=val; | |
4192ca66 BH |
503 | } |
504 | ||
2fe9d6f7 AT |
505 | void RecordTextWriter::xfrBlobNoSpaces(const string& val, int size) |
506 | { | |
507 | xfrBlob(val, size); | |
508 | } | |
509 | ||
06ffdc52 | 510 | void RecordTextWriter::xfrBlob(const string& val, int) |
8c1c9170 BH |
511 | { |
512 | if(!d_string.empty()) | |
513 | d_string.append(1,' '); | |
514 | ||
515 | d_string+=Base64Encode(val); | |
516 | } | |
517 | ||
e4090157 | 518 | void RecordTextWriter::xfrHexBlob(const string& val, bool) |
59a0f653 BH |
519 | { |
520 | if(!d_string.empty()) | |
521 | d_string.append(1,' '); | |
522 | ||
3c873e66 BH |
523 | if(val.empty()) { |
524 | d_string.append(1,'-'); | |
525 | return; | |
526 | } | |
527 | ||
59a0f653 BH |
528 | string::size_type limit=val.size(); |
529 | char tmp[5]; | |
530 | for(string::size_type n = 0; n < limit; ++n) { | |
531 | snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]); | |
532 | d_string+=tmp; | |
533 | } | |
534 | } | |
535 | ||
ef6a78d5 | 536 | void RecordTextWriter::xfrText(const string& val, bool multi) |
4192ca66 BH |
537 | { |
538 | if(!d_string.empty()) | |
539 | d_string.append(1,' '); | |
4192ca66 | 540 | |
ef6a78d5 | 541 | d_string.append(val); |
4192ca66 BH |
542 | } |
543 | ||
544 | ||
545 | #ifdef TESTING | |
546 | ||
547 | int main(int argc, char**argv) | |
548 | try | |
549 | { | |
550 | RecordTextReader rtr(argv[1], argv[2]); | |
551 | ||
552 | unsigned int order, pref; | |
553 | string flags, services, regexp, replacement; | |
554 | string mx; | |
555 | ||
556 | rtr.xfrInt(order); | |
557 | rtr.xfrInt(pref); | |
cbf0e7f3 BH |
558 | rtr.xfrText(flags); |
559 | rtr.xfrText(services); | |
560 | rtr.xfrText(regexp); | |
4192ca66 BH |
561 | rtr.xfrLabel(replacement); |
562 | ||
563 | cout<<"order: "<<order<<", pref: "<<pref<<"\n"; | |
564 | cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n"; | |
565 | ||
566 | string out; | |
567 | RecordTextWriter rtw(out); | |
568 | ||
569 | rtw.xfrInt(order); | |
570 | rtw.xfrInt(pref); | |
cbf0e7f3 BH |
571 | rtw.xfrText(flags); |
572 | rtw.xfrText(services); | |
573 | rtw.xfrText(regexp); | |
4192ca66 BH |
574 | rtw.xfrLabel(replacement); |
575 | ||
576 | cout<<"Regenerated: '"<<out<<"'\n"; | |
577 | ||
578 | } | |
adc10f99 | 579 | catch(std::exception& e) |
4192ca66 BH |
580 | { |
581 | cerr<<"Fatal: "<<e.what()<<endl; | |
582 | } | |
583 | ||
584 | #endif |