1 /*- 2 * Copyright (c) 2013 David Chisnall 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 #include "string.hh" 34 35 namespace 36 { 37 /** 38 * The source files are ASCII, so we provide a non-locale-aware version of 39 * isalpha. This is a class so that it can be used with a template function 40 * for parsing strings. 41 */ 42 struct is_alpha 43 { 44 static inline bool check(const char c) 45 { 46 return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && 47 (c <= 'Z')); 48 } 49 }; 50 /** 51 * Check whether a character is in the set allowed for node names. This is a 52 * class so that it can be used with a template function for parsing strings. 53 */ 54 struct is_node_name_character 55 { 56 static inline bool check(const char c) 57 { 58 switch(c) 59 { 60 default: 61 return false; 62 case 'a'...'z': case 'A'...'Z': case '0'...'9': 63 case ',': case '.': case '+': case '-': 64 case '_': 65 return true; 66 } 67 } 68 }; 69 /** 70 * Check whether a character is in the set allowed for property names. This is 71 * a class so that it can be used with a template function for parsing strings. 72 */ 73 struct is_property_name_character 74 { 75 static inline bool check(const char c) 76 { 77 switch(c) 78 { 79 default: 80 return false; 81 case 'a'...'z': case 'A'...'Z': case '0'...'9': 82 case ',': case '.': case '+': case '-': 83 case '_': case '#': 84 return true; 85 } 86 } 87 }; 88 89 } 90 91 namespace dtc 92 { 93 94 template<class T> string 95 string::parse(input_buffer &s) 96 { 97 const char *start = s; 98 int l=0; 99 while (T::check(*s)) { l++; ++s; } 100 return string(start, l); 101 } 102 103 string::string(input_buffer &s) : start((const char*)s), length(0) 104 { 105 while(s[length] != '\0') 106 { 107 length++; 108 } 109 } 110 111 string 112 string::parse_node_name(input_buffer &s) 113 { 114 return parse<is_node_name_character>(s); 115 } 116 117 string 118 string::parse_property_name(input_buffer &s) 119 { 120 return parse<is_property_name_character>(s); 121 } 122 string 123 string::parse_node_or_property_name(input_buffer &s, bool &is_property) 124 { 125 if (is_property) 126 { 127 return parse_property_name(s); 128 } 129 const char *start = s; 130 int l=0; 131 while (is_node_name_character::check(*s)) 132 { 133 l++; 134 ++s; 135 } 136 while (is_property_name_character::check(*s)) 137 { 138 l++; 139 ++s; 140 is_property = true; 141 } 142 return string(start, l); 143 } 144 145 bool 146 string::operator==(const string& other) const 147 { 148 return (length == other.length) && 149 (memcmp(start, other.start, length) == 0); 150 } 151 152 bool 153 string::operator==(const char *other) const 154 { 155 return strncmp(other, start, length) == 0; 156 } 157 158 bool 159 string::operator<(const string& other) const 160 { 161 if (length < other.length) { return true; } 162 if (length > other.length) { return false; } 163 return memcmp(start, other.start, length) < 0; 164 } 165 166 void 167 string::push_to_buffer(byte_buffer &buffer, bool escapes) 168 { 169 for (int i=0 ; i<length ; ++i) 170 { 171 uint8_t c = start[i]; 172 if (escapes && c == '\\' && i+1 < length) 173 { 174 c = start[++i]; 175 switch (c) 176 { 177 // For now, we just ignore invalid escape sequences. 178 default: 179 case '"': 180 case '\'': 181 case '\\': 182 break; 183 case 'a': 184 c = '\a'; 185 break; 186 case 'b': 187 c = '\b'; 188 break; 189 case 't': 190 c = '\t'; 191 break; 192 case 'n': 193 c = '\n'; 194 break; 195 case 'v': 196 c = '\v'; 197 break; 198 case 'f': 199 c = '\f'; 200 break; 201 case 'r': 202 c = '\r'; 203 break; 204 case '0'...'7': 205 { 206 int v = digittoint(c); 207 if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 208 { 209 v <<= 3; 210 v |= digittoint(start[i+1]); 211 i++; 212 if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 213 { 214 v <<= 3; 215 v |= digittoint(start[i+1]); 216 } 217 } 218 c = (uint8_t)v; 219 break; 220 } 221 case 'x': 222 { 223 ++i; 224 if (i >= length) 225 { 226 break; 227 } 228 int v = digittoint(start[i]); 229 if (i+1 < length && ishexdigit(start[i+1])) 230 { 231 v <<= 4; 232 v |= digittoint(start[++i]); 233 } 234 c = (uint8_t)v; 235 break; 236 } 237 } 238 } 239 buffer.push_back(c); 240 } 241 } 242 243 void 244 string::print(FILE *file) 245 { 246 fwrite(start, length, 1, file); 247 } 248 249 void 250 string::dump() 251 { 252 print(stderr); 253 } 254 255 } // namespace dtc 256 257