cstring.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* Copyright (c) 2001 Matej Pfajfar.
  2. * Copyright (c) 2001-2004, Roger Dingledine.
  3. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  4. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. /**
  7. * \file cstring.c
  8. *
  9. * \brief Decode data that has been written as a C literal.
  10. **/
  11. #include "lib/encoding/cstring.h"
  12. #include "lib/log/torlog.h"
  13. #include "lib/log/util_bug.h"
  14. #include "lib/malloc/util_malloc.h"
  15. #include "lib/string/compat_ctype.h"
  16. #include <string.h>
  17. #define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7')
  18. /** Given a c-style double-quoted escaped string in <b>s</b>, extract and
  19. * decode its contents into a newly allocated string. On success, assign this
  20. * string to *<b>result</b>, assign its length to <b>size_out</b> (if
  21. * provided), and return a pointer to the position in <b>s</b> immediately
  22. * after the string. On failure, return NULL.
  23. */
  24. const char *
  25. unescape_string(const char *s, char **result, size_t *size_out)
  26. {
  27. const char *cp;
  28. char *out;
  29. if (s[0] != '\"')
  30. return NULL;
  31. cp = s+1;
  32. while (1) {
  33. switch (*cp) {
  34. case '\0':
  35. case '\n':
  36. return NULL;
  37. case '\"':
  38. goto end_of_loop;
  39. case '\\':
  40. if (cp[1] == 'x' || cp[1] == 'X') {
  41. if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])))
  42. return NULL;
  43. cp += 4;
  44. } else if (TOR_ISODIGIT(cp[1])) {
  45. cp += 2;
  46. if (TOR_ISODIGIT(*cp)) ++cp;
  47. if (TOR_ISODIGIT(*cp)) ++cp;
  48. } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"'
  49. || cp[1] == '\\' || cp[1] == '\'') {
  50. cp += 2;
  51. } else {
  52. return NULL;
  53. }
  54. break;
  55. default:
  56. ++cp;
  57. break;
  58. }
  59. }
  60. end_of_loop:
  61. out = *result = tor_malloc(cp-s + 1);
  62. cp = s+1;
  63. while (1) {
  64. switch (*cp)
  65. {
  66. case '\"':
  67. *out = '\0';
  68. if (size_out) *size_out = out - *result;
  69. return cp+1;
  70. /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */
  71. case '\0':
  72. tor_fragile_assert();
  73. tor_free(*result);
  74. return NULL;
  75. /* LCOV_EXCL_STOP */
  76. case '\\':
  77. switch (cp[1])
  78. {
  79. case 'n': *out++ = '\n'; cp += 2; break;
  80. case 'r': *out++ = '\r'; cp += 2; break;
  81. case 't': *out++ = '\t'; cp += 2; break;
  82. case 'x': case 'X':
  83. {
  84. int x1, x2;
  85. x1 = hex_decode_digit(cp[2]);
  86. x2 = hex_decode_digit(cp[3]);
  87. if (x1 == -1 || x2 == -1) {
  88. /* LCOV_EXCL_START */
  89. /* we caught this above in the initial loop. */
  90. tor_assert_nonfatal_unreached();
  91. tor_free(*result);
  92. return NULL;
  93. /* LCOV_EXCL_STOP */
  94. }
  95. *out++ = ((x1<<4) + x2);
  96. cp += 4;
  97. }
  98. break;
  99. case '0': case '1': case '2': case '3': case '4': case '5':
  100. case '6': case '7':
  101. {
  102. int n = cp[1]-'0';
  103. cp += 2;
  104. if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
  105. if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
  106. if (n > 255) { tor_free(*result); return NULL; }
  107. *out++ = (char)n;
  108. }
  109. break;
  110. case '\'':
  111. case '\"':
  112. case '\\':
  113. case '\?':
  114. *out++ = cp[1];
  115. cp += 2;
  116. break;
  117. /* LCOV_EXCL_START */
  118. default:
  119. /* we caught this above in the initial loop. */
  120. tor_assert_nonfatal_unreached();
  121. tor_free(*result); return NULL;
  122. /* LCOV_EXCL_STOP */
  123. }
  124. break;
  125. default:
  126. *out++ = *cp++;
  127. }
  128. }
  129. }