char_string.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (C) 2012 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. #include <exceptions/exceptions.h>
  15. #include <dns/rdata.h>
  16. #include <dns/master_lexer.h>
  17. #include <dns/rdata/generic/detail/char_string.h>
  18. #include <boost/lexical_cast.hpp>
  19. #include <cassert>
  20. #include <cctype>
  21. #include <cstring>
  22. #include <vector>
  23. #include <stdint.h>
  24. namespace isc {
  25. namespace dns {
  26. namespace rdata {
  27. namespace generic {
  28. namespace detail {
  29. namespace {
  30. // Convert a DDD form to the corresponding integer
  31. int
  32. decimalToNumber(const char* s, const char* s_end) {
  33. if (s_end - s < 3) {
  34. isc_throw(InvalidRdataText, "Escaped digits too short");
  35. }
  36. const std::string num_str(s, s + 3);
  37. try {
  38. const int i = boost::lexical_cast<int>(num_str);
  39. if (i > 255) {
  40. isc_throw(InvalidRdataText, "Escaped digits too large: "
  41. << num_str);
  42. }
  43. return (i);
  44. } catch (const boost::bad_lexical_cast&) {
  45. isc_throw(InvalidRdataText,
  46. "Invalid form for escaped digits: " << num_str);
  47. }
  48. }
  49. }
  50. void
  51. stringToCharString(const MasterToken::StringRegion& str_region,
  52. CharString& result)
  53. {
  54. // make a space for the 1-byte length field; filled in at the end
  55. result.push_back(0);
  56. bool escape = false;
  57. const char* s = str_region.beg;
  58. const char* const s_end = str_region.beg + str_region.len;
  59. for (size_t n = str_region.len; n != 0; --n, ++s) {
  60. int c = (*s & 0xff);
  61. if (escape && std::isdigit(c) != 0) {
  62. c = decimalToNumber(s, s_end);
  63. assert(n >= 3);
  64. n -= 2;
  65. s += 2;
  66. } else if (!escape && c == '\\') {
  67. escape = true;
  68. continue;
  69. }
  70. escape = false;
  71. result.push_back(c);
  72. }
  73. if (escape) { // terminated by non-escaped '\'
  74. isc_throw(InvalidRdataText, "character-string ends with '\\'");
  75. }
  76. if (result.size() > MAX_CHARSTRING_LEN + 1) { // '+ 1' due to the len field
  77. isc_throw(CharStringTooLong, "character-string is too long: " <<
  78. (result.size() - 1) << "(+1) characters");
  79. }
  80. result[0] = result.size() - 1;
  81. }
  82. std::string
  83. charStringToString(const CharString& char_string) {
  84. std::string s;
  85. for (CharString::const_iterator it = char_string.begin() + 1;
  86. it != char_string.end(); ++it) {
  87. const uint8_t ch = *it;
  88. if ((ch < 0x20) || (ch >= 0x7f)) {
  89. // convert to escaped \xxx (decimal) format
  90. s.push_back('\\');
  91. s.push_back('0' + ((ch / 100) % 10));
  92. s.push_back('0' + ((ch / 10) % 10));
  93. s.push_back('0' + (ch % 10));
  94. continue;
  95. }
  96. if ((ch == '"') || (ch == ';') || (ch == '\\')) {
  97. s.push_back('\\');
  98. }
  99. s.push_back(ch);
  100. }
  101. return (s);
  102. }
  103. } // end of detail
  104. } // end of generic
  105. } // end of rdata
  106. } // end of dns
  107. } // end of isc