diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/unstable/json.cpp | 316 | ||||
| -rw-r--r-- | src/unstable/json.h | 113 |
2 files changed, 323 insertions, 106 deletions
diff --git a/src/unstable/json.cpp b/src/unstable/json.cpp index 0769836..c31c7f9 100644 --- a/src/unstable/json.cpp +++ b/src/unstable/json.cpp | |||
| @@ -1,87 +1,331 @@ | |||
| 1 | #include "bu/json.h" | 1 | #include "bu/json.h" |
| 2 | #include "bu/staticmembuf.h" | ||
| 2 | 3 | ||
| 3 | Bu::Json::Base::Base() | 4 | #include <stdlib.h> |
| 4 | { | ||
| 5 | } | ||
| 6 | 5 | ||
| 7 | Bu::Json::Base::~Base() | 6 | #define next( txt ) readChar( c, sInput, "Unexpected end of stream while reading " txt "." ) |
| 8 | { | ||
| 9 | } | ||
| 10 | 7 | ||
| 11 | Bu::Json::Object::Object() | 8 | Bu::Json::Json() : |
| 9 | eType( Invalid ) | ||
| 12 | { | 10 | { |
| 13 | } | 11 | } |
| 14 | 12 | ||
| 15 | Bu::Json::Object::~Object() | 13 | Bu::Json::Json( const Bu::String &sJson ) : |
| 14 | eType( Invalid ) | ||
| 16 | { | 15 | { |
| 16 | Bu::StaticMemBuf mIn( sJson.getStr(), sJson.getSize() ); | ||
| 17 | parse( mIn ); | ||
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | Bu::Json::Type Bu::Json::Object::getType() | 20 | Bu::Json::Json( Bu::Stream &sInput ) : |
| 21 | eType( Invalid ) | ||
| 20 | { | 22 | { |
| 21 | return tObject; | 23 | parse( sInput ); |
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | Bu::Json::Array::Array() | 26 | Bu::Json::~Json() |
| 25 | { | 27 | { |
| 28 | reset(); | ||
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | Bu::Json::Array::~Array() | 31 | void Bu::Json::parse( Bu::Stream &sInput ) |
| 29 | { | 32 | { |
| 30 | } | 33 | reset(); |
| 31 | 34 | ||
| 32 | Bu::Json::Type Bu::Json::Array::getType() | 35 | char c; |
| 33 | { | 36 | for(;;) |
| 34 | return tArray; | 37 | { |
| 38 | next( "json" ); | ||
| 39 | if( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) | ||
| 40 | continue; | ||
| 41 | if( c == '"' ) | ||
| 42 | { | ||
| 43 | // String | ||
| 44 | parseString( c, sInput ); | ||
| 45 | } | ||
| 46 | else if( c == '{' ) | ||
| 47 | { | ||
| 48 | // Object | ||
| 49 | parseObject( c, sInput ); | ||
| 50 | } | ||
| 51 | else if( c == '[' ) | ||
| 52 | { | ||
| 53 | // Array | ||
| 54 | parseArray( c, sInput ); | ||
| 55 | } | ||
| 56 | else if( c == '-' || (c >= '0' && c <= '9') ) | ||
| 57 | { | ||
| 58 | // Number -- apparently they can't start with a period | ||
| 59 | parseNumber( c, sInput ); | ||
| 60 | } | ||
| 61 | else if( c == 't' || c == 'f' || c == 'n' ) | ||
| 62 | { | ||
| 63 | // True / false / null | ||
| 64 | parseLiteral( c, sInput ); | ||
| 65 | } | ||
| 66 | } | ||
| 35 | } | 67 | } |
| 36 | 68 | ||
| 37 | Bu::Json::String::String() | 69 | void Bu::Json::reset() |
| 38 | { | 70 | { |
| 39 | } | 71 | switch( eType ) |
| 72 | { | ||
| 73 | case Object: | ||
| 74 | for( JsonHash::iterator i = uDat.pObject->begin(); i; i++ ) | ||
| 75 | { | ||
| 76 | delete i.getValue(); | ||
| 77 | } | ||
| 78 | delete uDat.pObject; | ||
| 79 | break; | ||
| 40 | 80 | ||
| 41 | Bu::Json::String::~String() | 81 | case Array: |
| 42 | { | 82 | for( JsonList::iterator i = uDat.pArray->begin(); i; i++ ) |
| 43 | } | 83 | { |
| 84 | delete *i; | ||
| 85 | } | ||
| 86 | delete uDat.pArray; | ||
| 87 | break; | ||
| 44 | 88 | ||
| 45 | Bu::Json::Type Bu::Json::String::getType() | 89 | case String: |
| 46 | { | 90 | delete uDat.pString; |
| 47 | return tString; | 91 | break; |
| 92 | |||
| 93 | case Invalid: | ||
| 94 | case Number: | ||
| 95 | case Boolean: | ||
| 96 | case Null: | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | uDat.pObject = NULL; | ||
| 48 | } | 100 | } |
| 49 | 101 | ||
| 50 | Bu::Json::Number::Number() | 102 | void Bu::Json::parseString( char &c, Bu::Stream &sInput, Bu::String &sOut ) |
| 51 | { | 103 | { |
| 104 | while( c != '"' ) | ||
| 105 | { | ||
| 106 | next( "string" ); | ||
| 107 | } | ||
| 108 | bool bEscape = false; | ||
| 109 | for(;;) | ||
| 110 | { | ||
| 111 | next( "string" ); | ||
| 112 | if( bEscape ) | ||
| 113 | { | ||
| 114 | switch( c ) | ||
| 115 | { | ||
| 116 | case '"': | ||
| 117 | case '\\': | ||
| 118 | case '/': | ||
| 119 | sOut += c; | ||
| 120 | break; | ||
| 121 | |||
| 122 | case 'b': | ||
| 123 | sOut += '\b'; | ||
| 124 | break; | ||
| 125 | |||
| 126 | case 'f': | ||
| 127 | sOut += '\f'; | ||
| 128 | break; | ||
| 129 | |||
| 130 | case 'n': | ||
| 131 | sOut += '\n'; | ||
| 132 | break; | ||
| 133 | |||
| 134 | case 'r': | ||
| 135 | sOut += '\r'; | ||
| 136 | break; | ||
| 137 | |||
| 138 | case 't': | ||
| 139 | sOut += '\t'; | ||
| 140 | break; | ||
| 141 | |||
| 142 | case 'u': | ||
| 143 | // Not implimented yet, followed by four hex diigts | ||
| 144 | break; | ||
| 145 | |||
| 146 | default: | ||
| 147 | throw Bu::ExceptionBase( | ||
| 148 | "Invalid escape sequence encountered in string." | ||
| 149 | ); | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | bEscape = false; | ||
| 153 | } | ||
| 154 | else | ||
| 155 | { | ||
| 156 | if( c == '\\' ) | ||
| 157 | bEscape = true; | ||
| 158 | if( c == '"' ) | ||
| 159 | { | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | sOut += c; | ||
| 163 | } | ||
| 164 | } | ||
| 52 | } | 165 | } |
| 53 | 166 | ||
| 54 | Bu::Json::Number::~Number() | 167 | void Bu::Json::parseString( char &c, Bu::Stream &sInput ) |
| 55 | { | 168 | { |
| 169 | eType = String; | ||
| 170 | uDat.pString = new Bu::String(); | ||
| 171 | parseString( c, sInput, *uDat.pString ); | ||
| 56 | } | 172 | } |
| 57 | 173 | ||
| 58 | Bu::Json::Type Bu::Json::Number::getType() | 174 | void Bu::Json::parseObject( char &c, Bu::Stream &sInput ) |
| 59 | { | 175 | { |
| 60 | return tNumber; | 176 | while( c != '{' ) |
| 177 | { | ||
| 178 | next( "object" ); | ||
| 179 | } | ||
| 180 | |||
| 181 | eType = Object; | ||
| 182 | uDat.pObject = new JsonHash(); | ||
| 183 | |||
| 184 | next( "object" ); | ||
| 185 | for(;;) | ||
| 186 | { | ||
| 187 | Bu::String sKey; | ||
| 188 | parseString( c, sInput, sKey ); | ||
| 189 | next( "object" ); | ||
| 190 | if( c != ':' ) | ||
| 191 | { | ||
| 192 | throw Bu::ExceptionBase( | ||
| 193 | "Invalid json, expected colon after key in object." | ||
| 194 | ); | ||
| 195 | } | ||
| 196 | uDat.pObject->insert( sKey, new Json( sInput ) ); | ||
| 197 | next( "object" ); | ||
| 198 | if( c == '}' ) | ||
| 199 | break; | ||
| 200 | else if( c == ',' ) | ||
| 201 | next( "object" ); | ||
| 202 | else | ||
| 203 | throw Bu::ExceptionBase( | ||
| 204 | "Invalid json, expected comma or } after value in object." | ||
| 205 | ); | ||
| 206 | } | ||
| 61 | } | 207 | } |
| 62 | 208 | ||
| 63 | Bu::Json::Boolean::Boolean() | 209 | void Bu::Json::parseArray( char &c, Bu::Stream &sInput ) |
| 64 | { | 210 | { |
| 211 | while( c != '[' ) | ||
| 212 | { | ||
| 213 | next( "array" ); | ||
| 214 | } | ||
| 215 | |||
| 216 | eType = Array; | ||
| 217 | uDat.pArray = new JsonList(); | ||
| 218 | |||
| 219 | next( "array" ); | ||
| 220 | for(;;) | ||
| 221 | { | ||
| 222 | uDat.pArray->append( new Json( sInput ) ); | ||
| 223 | next( "array" ); | ||
| 224 | if( c == ']' ) | ||
| 225 | break; | ||
| 226 | else if( c == ',' ) | ||
| 227 | continue; | ||
| 228 | else | ||
| 229 | { | ||
| 230 | throw Bu::ExceptionBase( | ||
| 231 | "Invalid json, expected comma or ] after value in array." | ||
| 232 | ); | ||
| 233 | } | ||
| 234 | } | ||
| 65 | } | 235 | } |
| 66 | 236 | ||
| 67 | Bu::Json::Boolean::~Boolean() | 237 | void Bu::Json::parseNumber( char &c, Bu::Stream &sInput ) |
| 68 | { | 238 | { |
| 239 | while( c != '-' && c < '0' && c > '9' ) | ||
| 240 | { | ||
| 241 | next( "number" ); | ||
| 242 | } | ||
| 243 | |||
| 244 | Bu::String sBuf; | ||
| 245 | if( c == '-' ) | ||
| 246 | { | ||
| 247 | sBuf += c; | ||
| 248 | next( "number" ); | ||
| 249 | } | ||
| 250 | bool bIntPart = true; | ||
| 251 | do | ||
| 252 | { | ||
| 253 | if( c >= '0' && c <= '9' ) | ||
| 254 | sBuf += c; | ||
| 255 | else if( c == '.' && bIntPart == true ) | ||
| 256 | { | ||
| 257 | bIntPart = false; | ||
| 258 | sBuf += c; | ||
| 259 | } | ||
| 260 | else if( c == ' ' || c == '\t' || c == '\n' || c == '\r' || | ||
| 261 | c == '}' || c == ']' || c == ',' ) | ||
| 262 | { | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | else | ||
| 266 | { | ||
| 267 | throw Bu::ExceptionBase("Invalid character in number."); | ||
| 268 | } | ||
| 269 | } while( readChar( c, sInput ) ); | ||
| 270 | |||
| 271 | eType = Number; | ||
| 272 | uDat.dNumber = atof( sBuf.getStr() ); | ||
| 69 | } | 273 | } |
| 70 | 274 | ||
| 71 | Bu::Json::Type Bu::Json::Boolean::getType() | 275 | void Bu::Json::parseLiteral( char &c, Bu::Stream &sInput ) |
| 72 | { | 276 | { |
| 73 | return tBoolean; | 277 | while( c != 'f' && c != 't' && c != 'n' ) |
| 278 | { | ||
| 279 | next( "literal" ); | ||
| 280 | } | ||
| 281 | |||
| 282 | Bu::String s; | ||
| 283 | do | ||
| 284 | { | ||
| 285 | if( isWs( c ) || c == ',' || c == '}' || c == ']' ) | ||
| 286 | break; | ||
| 287 | else | ||
| 288 | s += c; | ||
| 289 | } while( readChar( c, sInput ) ); | ||
| 290 | |||
| 291 | if( s == "true" ) | ||
| 292 | { | ||
| 293 | eType = Boolean; | ||
| 294 | uDat.bBoolean = true; | ||
| 295 | } | ||
| 296 | else if( s == "false" ) | ||
| 297 | { | ||
| 298 | eType = Boolean; | ||
| 299 | uDat.bBoolean = false; | ||
| 300 | } | ||
| 301 | else if( s == "null" ) | ||
| 302 | { | ||
| 303 | eType = Null; | ||
| 304 | uDat.pObject = NULL; | ||
| 305 | } | ||
| 306 | else | ||
| 307 | { | ||
| 308 | throw Bu::ExceptionBase("Invalid literal token found."); | ||
| 309 | } | ||
| 74 | } | 310 | } |
| 75 | 311 | ||
| 76 | Bu::Json::Null::Null() | 312 | bool Bu::Json::readChar( char &c, Bu::Stream &sInput ) |
| 77 | { | 313 | { |
| 314 | if( sInput.read( &c, 1 ) == 0 ) | ||
| 315 | return false; | ||
| 316 | return true; | ||
| 78 | } | 317 | } |
| 79 | 318 | ||
| 80 | Bu::Json::Null::~Null() | 319 | void Bu::Json::readChar( char &c, Bu::Stream &sInput, const char *sSection ) |
| 81 | { | 320 | { |
| 321 | if( sInput.read( &c, 1 ) == 0 ) | ||
| 322 | { | ||
| 323 | throw Bu::ExceptionBase( sSection ); | ||
| 324 | } | ||
| 82 | } | 325 | } |
| 83 | 326 | ||
| 84 | Bu::Json::Type Bu::Json::Null::getType() | 327 | bool Bu::Json::isWs( char c ) |
| 85 | { | 328 | { |
| 86 | return tNull; | 329 | return c == ' ' || c == '\t' || c == '\r' || c == '\n'; |
| 87 | } | 330 | } |
| 331 | |||
diff --git a/src/unstable/json.h b/src/unstable/json.h index 660d1c6..47009cb 100644 --- a/src/unstable/json.h +++ b/src/unstable/json.h | |||
| @@ -1,89 +1,62 @@ | |||
| 1 | #ifndef BU_JSON_H | 1 | #ifndef BU_JSON_H |
| 2 | #define BU_JSON_H | 2 | #define BU_JSON_H |
| 3 | 3 | ||
| 4 | #include "bu/hash.h" | ||
| 5 | #include "bu/list.h" | ||
| 6 | #include "bu/string.h" | ||
| 7 | |||
| 4 | namespace Bu | 8 | namespace Bu |
| 5 | { | 9 | { |
| 10 | class Stream; | ||
| 11 | |||
| 6 | class Json | 12 | class Json |
| 7 | { | 13 | { |
| 8 | public: | 14 | public: |
| 9 | Json(); | ||
| 10 | virtual ~Json(); | ||
| 11 | |||
| 12 | public: | ||
| 13 | enum Type | 15 | enum Type |
| 14 | { | 16 | { |
| 15 | tObject, | 17 | Invalid, |
| 16 | tArray, | 18 | Object, |
| 17 | tString, | 19 | Array, |
| 18 | tNumber, | 20 | String, |
| 19 | tBoolean, | 21 | Number, |
| 20 | tNull | 22 | Boolean, |
| 21 | }; | 23 | Null |
| 22 | |||
| 23 | class Base | ||
| 24 | { | ||
| 25 | public: | ||
| 26 | Base(); | ||
| 27 | virtual ~Base(); | ||
| 28 | |||
| 29 | virtual Type getType()=0; | ||
| 30 | }; | ||
| 31 | |||
| 32 | class Object : public Base | ||
| 33 | { | ||
| 34 | public: | ||
| 35 | Object(); | ||
| 36 | virtual ~Object(); | ||
| 37 | |||
| 38 | virtual Type getType(); | ||
| 39 | }; | ||
| 40 | |||
| 41 | class Array : public Base | ||
| 42 | { | ||
| 43 | public: | ||
| 44 | Array(); | ||
| 45 | virtual ~Array(); | ||
| 46 | |||
| 47 | virtual Type getType(); | ||
| 48 | }; | 24 | }; |
| 49 | 25 | ||
| 50 | class String : public Base | 26 | public: |
| 51 | { | 27 | Json(); |
| 52 | public: | 28 | Json( const Bu::String &sJson ); |
| 53 | String(); | 29 | Json( Bu::Stream &sInput ); |
| 54 | virtual ~String(); | 30 | virtual ~Json(); |
| 55 | |||
| 56 | virtual Type getType(); | ||
| 57 | }; | ||
| 58 | |||
| 59 | class Number : public Base | ||
| 60 | { | ||
| 61 | public: | ||
| 62 | Number(); | ||
| 63 | virtual ~Number(); | ||
| 64 | |||
| 65 | virtual Type getType(); | ||
| 66 | }; | ||
| 67 | |||
| 68 | class Boolean : public Base | ||
| 69 | { | ||
| 70 | public: | ||
| 71 | Boolean(); | ||
| 72 | virtual ~Boolean(); | ||
| 73 | |||
| 74 | virtual Type getType(); | ||
| 75 | }; | ||
| 76 | 31 | ||
| 77 | class Null : public Base | 32 | void parse( Bu::Stream &sInput ); |
| 78 | { | 33 | void reset(); |
| 79 | public: | ||
| 80 | Null(); | ||
| 81 | virtual ~Null(); | ||
| 82 | 34 | ||
| 83 | virtual Type getType(); | 35 | private: |
| 84 | }; | 36 | void parseString( char &c, Bu::Stream &sInput, Bu::String &sOut ); |
| 37 | void parseString( char &c, Bu::Stream &sInput ); | ||
| 38 | void parseObject( char &c, Bu::Stream &sInput ); | ||
| 39 | void parseArray( char &c, Bu::Stream &sInput ); | ||
| 40 | void parseNumber( char &c, Bu::Stream &sInput ); | ||
| 41 | void parseLiteral( char &c, Bu::Stream &sInput ); | ||
| 42 | bool readChar( char &c, Bu::Stream &sInput ); | ||
| 43 | void readChar( char &c, Bu::Stream &sInput, const char *sSection ); | ||
| 44 | bool isWs( char c ); | ||
| 85 | 45 | ||
| 86 | private: | 46 | private: |
| 47 | typedef Bu::Hash<Bu::String, Json *> JsonHash; | ||
| 48 | typedef Bu::List<Json *> JsonList; | ||
| 49 | |||
| 50 | Type eType; | ||
| 51 | union DatUnion | ||
| 52 | { | ||
| 53 | DatUnion() : pObject( NULL ) { } | ||
| 54 | JsonHash *pObject; | ||
| 55 | JsonList *pArray; | ||
| 56 | Bu::String *pString; | ||
| 57 | double dNumber; | ||
| 58 | bool bBoolean; | ||
| 59 | } uDat; | ||
| 87 | }; | 60 | }; |
| 88 | }; | 61 | }; |
| 89 | 62 | ||
