diff options
Diffstat (limited to 'src/unstable/json.cpp')
-rw-r--r-- | src/unstable/json.cpp | 316 |
1 files changed, 280 insertions, 36 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 | |||