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