aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mbuland@penny-arcade.com>2017-06-06 12:30:52 -0700
committerMike Buland <mbuland@penny-arcade.com>2017-06-06 12:30:52 -0700
commitb7751f0136502592e9b1897b51859b1133339a93 (patch)
tree835b4a78c6b2322039d7b4b70652976bd539a06b
parent8e0f468e79263dc7f9a6364ca1a26036906642bc (diff)
downloadlibbu++-b7751f0136502592e9b1897b51859b1133339a93.tar.gz
libbu++-b7751f0136502592e9b1897b51859b1133339a93.tar.bz2
libbu++-b7751f0136502592e9b1897b51859b1133339a93.tar.xz
libbu++-b7751f0136502592e9b1897b51859b1133339a93.zip
Hey! This is a much better structure for the Json class.
This new setup is one class for everything, the values are kept in a union, and the instance knows what type it is. The tree of objects is a tree of instantiations of the same class. It's much simpler, it's much easier to write, and maybe even easier to use.
-rw-r--r--src/unstable/json.cpp316
-rw-r--r--src/unstable/json.h113
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
3Bu::Json::Base::Base() 4#include <stdlib.h>
4{
5}
6 5
7Bu::Json::Base::~Base() 6#define next( txt ) readChar( c, sInput, "Unexpected end of stream while reading " txt "." )
8{
9}
10 7
11Bu::Json::Object::Object() 8Bu::Json::Json() :
9 eType( Invalid )
12{ 10{
13} 11}
14 12
15Bu::Json::Object::~Object() 13Bu::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
19Bu::Json::Type Bu::Json::Object::getType() 20Bu::Json::Json( Bu::Stream &sInput ) :
21 eType( Invalid )
20{ 22{
21 return tObject; 23 parse( sInput );
22} 24}
23 25
24Bu::Json::Array::Array() 26Bu::Json::~Json()
25{ 27{
28 reset();
26} 29}
27 30
28Bu::Json::Array::~Array() 31void Bu::Json::parse( Bu::Stream &sInput )
29{ 32{
30} 33 reset();
31 34
32Bu::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
37Bu::Json::String::String() 69void 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
41Bu::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
45Bu::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
50Bu::Json::Number::Number() 102void 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
54Bu::Json::Number::~Number() 167void 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
58Bu::Json::Type Bu::Json::Number::getType() 174void 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
63Bu::Json::Boolean::Boolean() 209void 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
67Bu::Json::Boolean::~Boolean() 237void 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
71Bu::Json::Type Bu::Json::Boolean::getType() 275void 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
76Bu::Json::Null::Null() 312bool 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
80Bu::Json::Null::~Null() 319void 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
84Bu::Json::Type Bu::Json::Null::getType() 327bool 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
4namespace Bu 8namespace 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