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