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 #include <ctype.h> 35 #include <stdio.h> 36 37 namespace 38 { 39 /** 40 * The source files are ASCII, so we provide a non-locale-aware version of 41 * isalpha. This is a class so that it can be used with a template function 42 * for parsing strings. 43 */ 44 struct is_alpha 45 { 46 static inline bool check(const char c) 47 { 48 return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && 49 (c <= 'Z')); 50 } 51 }; 52 /** 53 * Check whether a character is in the set allowed for node names. This is a 54 * class so that it can be used with a template function for parsing strings. 55 */ 56 struct is_node_name_character 57 { 58 static inline bool check(const char c) 59 { 60 switch(c) 61 { 62 default: 63 return false; 64 case 'a'...'z': case 'A'...'Z': case '0'...'9': 65 case ',': case '.': case '+': case '-': 66 case '_': 67 return true; 68 } 69 } 70 }; 71 /** 72 * Check whether a character is in the set allowed for property names. This is 73 * a class so that it can be used with a template function for parsing strings. 74 */ 75 struct is_property_name_character 76 { 77 static inline bool check(const char c) 78 { 79 switch(c) 80 { 81 default: 82 return false; 83 case 'a'...'z': case 'A'...'Z': case '0'...'9': 84 case ',': case '.': case '+': case '-': 85 case '_': case '#': 86 return true; 87 } 88 } 89 }; 90 91 } 92 93 namespace dtc 94 { 95 96 template<class T> string 97 string::parse(input_buffer &s) 98 { 99 const char *start = s; 100 int l=0; 101 while (T::check(*s)) { l++; ++s; } 102 return string(start, l); 103 } 104 105 string::string(input_buffer &s) : start((const char*)s), length(0) 106 { 107 while(s[length] != '\0') 108 { 109 length++; 110 } 111 } 112 113 string 114 string::parse_node_name(input_buffer &s) 115 { 116 return parse<is_node_name_character>(s); 117 } 118 119 string 120 string::parse_property_name(input_buffer &s) 121 { 122 return parse<is_property_name_character>(s); 123 } 124 string 125 string::parse_node_or_property_name(input_buffer &s, bool &is_property) 126 { 127 if (is_property) 128 { 129 return parse_property_name(s); 130 } 131 const char *start = s; 132 int l=0; 133 while (is_node_name_character::check(*s)) 134 { 135 l++; 136 ++s; 137 } 138 while (is_property_name_character::check(*s)) 139 { 140 l++; 141 ++s; 142 is_property = true; 143 } 144 return string(start, l); 145 } 146 147 bool 148 string::operator==(const string& other) const 149 { 150 return (length == other.length) && 151 (memcmp(start, other.start, length) == 0); 152 } 153 154 bool 155 string::operator==(const char *other) const 156 { 157 return strncmp(other, start, length) == 0; 158 } 159 160 bool 161 string::operator<(const string& other) const 162 { 163 if (length < other.length) { return true; } 164 if (length > other.length) { return false; } 165 return memcmp(start, other.start, length) < 0; 166 } 167 168 void 169 string::push_to_buffer(byte_buffer &buffer, bool escapes) 170 { 171 for (int i=0 ; i<length ; ++i) 172 { 173 uint8_t c = start[i]; 174 if (escapes && c == '\\' && i+1 < length) 175 { 176 c = start[++i]; 177 switch (c) 178 { 179 // For now, we just ignore invalid escape sequences. 180 default: 181 case '"': 182 case '\'': 183 case '\\': 184 break; 185 case 'a': 186 c = '\a'; 187 break; 188 case 'b': 189 c = '\b'; 190 break; 191 case 't': 192 c = '\t'; 193 break; 194 case 'n': 195 c = '\n'; 196 break; 197 case 'v': 198 c = '\v'; 199 break; 200 case 'f': 201 c = '\f'; 202 break; 203 case 'r': 204 c = '\r'; 205 break; 206 case '0'...'7': 207 { 208 int v = digittoint(c); 209 if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 210 { 211 v <<= 3; 212 v |= digittoint(start[i+1]); 213 i++; 214 if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 215 { 216 v <<= 3; 217 v |= digittoint(start[i+1]); 218 } 219 } 220 c = (uint8_t)v; 221 break; 222 } 223 case 'x': 224 { 225 ++i; 226 if (i >= length) 227 { 228 break; 229 } 230 int v = digittoint(start[i]); 231 if (i+1 < length && ishexdigit(start[i+1])) 232 { 233 v <<= 4; 234 v |= digittoint(start[++i]); 235 } 236 c = (uint8_t)v; 237 break; 238 } 239 } 240 } 241 buffer.push_back(c); 242 } 243 } 244 245 void 246 string::print(FILE *file) 247 { 248 fwrite(start, length, 1, file); 249 } 250 251 void 252 string::dump() 253 { 254 print(stderr); 255 } 256 257 } // namespace dtc 258 259