Merge lp:~stewart/drizzle/json-interface into lp:~drizzle-trunk/drizzle/development
- json-interface
- Merge into development
Status: | Merged |
---|---|
Approved by: | Brian Aker |
Approved revision: | 2300 |
Merged at revision: | 2310 |
Proposed branch: | lp:~stewart/drizzle/json-interface |
Merge into: | lp:~drizzle-trunk/drizzle/development |
Diff against target: |
7884 lines (+7638/-3) 32 files modified
drizzled/plugin/client/cached.h (+1/-0) drizzled/sql/result_set.h (+5/-0) drizzled/sql/result_set_meta_data.h (+6/-1) plugin/http_functions/http_functions.cc (+199/-0) plugin/http_functions/plugin.ac (+4/-0) plugin/http_functions/plugin.cnf (+2/-0) plugin/http_functions/plugin.ini (+6/-0) plugin/json_server/json/autolink.h (+58/-0) plugin/json_server/json/config.h (+81/-0) plugin/json_server/json/features.h (+80/-0) plugin/json_server/json/forwards.h (+77/-0) plugin/json_server/json/json.h (+48/-0) plugin/json_server/json/json_batchallocator.h (+163/-0) plugin/json_server/json/json_internalarray.inl (+486/-0) plugin/json_server/json/json_internalmap.inl (+645/-0) plugin/json_server/json/json_reader.cpp (+921/-0) plugin/json_server/json/json_value.cpp (+1759/-0) plugin/json_server/json/json_valueiterator.inl (+330/-0) plugin/json_server/json/json_writer.cpp (+862/-0) plugin/json_server/json/reader.h (+234/-0) plugin/json_server/json/value.h (+1107/-0) plugin/json_server/json/writer.h (+212/-0) plugin/json_server/json_server.cc (+284/-0) plugin/json_server/plugin.ac (+1/-0) plugin/json_server/plugin.ini (+12/-0) plugin/json_server/tests/r/basic.result (+35/-0) plugin/json_server/tests/t/basic.test (+10/-0) plugin/json_server/tests/t/master.opt (+1/-0) po/POTFILES.in (+1/-0) tests/lib/drizzle_test_run/dtr_test_execution.py (+1/-0) tests/lib/server_mgmt/drizzled.py (+2/-2) tests/test-run.pl (+5/-0) |
To merge this branch: | bzr merge lp:~stewart/drizzle/json-interface |
Related bugs: | |
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mark Atwood | Needs Fixing | ||
Drizzle Merge Team | Pending | ||
Review via email: mp+59859@code.launchpad.net |
This proposal supersedes a proposal from 2011-04-21.
Commit message
Description of the change
Preliminary implementation of a HTTP interface to Drizzle.
Includes testing. Uses libevent http daemon. returns results as JSON.
includes brian's fixes.
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
so a problem with this branch currently is that the tests use 'curl' to test the interface. Not all systems have curl installed however, so I either need to (for example) add HTTP_GET(
Brian Aker (brianaker) wrote : Posted in a previous version of this proposal | # |
We should put a comment on the code so that we know where it came from (and either our own license, or put public domain headers on it).
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
now fixed to have http_() functions in the tree that are used to test json_server. Can also be used to fetch URLs and the like.
This change means param-build passes on every system.
http://
is the other thing we should work out how to have in the soure files.
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
Mark Atwood (fallenpegasus) wrote : | # |
fail in jenkins
http://
http://
http://
http://
http://
http://
Some sort of issue with flex?
please fix and resubmit
Stewart Smith (stewart) wrote : | # |
On Thu, 12 May 2011 23:42:27 -0000, Mark Atwood <email address hidden> wrote:
> Review: Needs Fixing
> fail in jenkins
>
> http://
> http://
> http://
> http://
> http://
> http://
>
> Some sort of issue with flex?
>
looks like something from vj's sp branch, not mine.
--
Stewart Smith
Mark Atwood (fallenpegasus) wrote : | # |
>>
>
> looks like something from vj's sp branch, not mine.
Brian and I are looking at it.
Preview Diff
1 | === modified file 'drizzled/plugin/client/cached.h' |
2 | --- drizzled/plugin/client/cached.h 2011-03-15 23:55:01 +0000 |
3 | +++ drizzled/plugin/client/cached.h 2011-05-04 01:52:37 +0000 |
4 | @@ -57,6 +57,7 @@ |
5 | item->make_field(&field); |
6 | max_column++; |
7 | } |
8 | + _result_set->setColumnCount(max_column); |
9 | _result_set->createRow(); |
10 | |
11 | return false; |
12 | |
13 | === modified file 'drizzled/sql/result_set.h' |
14 | --- drizzled/sql/result_set.h 2011-03-29 12:45:08 +0000 |
15 | +++ drizzled/sql/result_set.h 2011-05-04 01:52:37 +0000 |
16 | @@ -101,6 +101,11 @@ |
17 | { |
18 | } |
19 | |
20 | + void setColumnCount(size_t fields) |
21 | + { |
22 | + _meta_data.setColumnCount(fields); |
23 | + } |
24 | + |
25 | ~ResultSet(); |
26 | |
27 | void createRow(); |
28 | |
29 | === modified file 'drizzled/sql/result_set_meta_data.h' |
30 | --- drizzled/sql/result_set_meta_data.h 2011-03-29 12:45:08 +0000 |
31 | +++ drizzled/sql/result_set_meta_data.h 2011-05-04 01:52:37 +0000 |
32 | @@ -53,10 +53,15 @@ |
33 | { |
34 | } |
35 | |
36 | + void setColumnCount(size_t fields) |
37 | + { |
38 | + _columns= fields; |
39 | + } |
40 | + |
41 | private: // Member methods |
42 | |
43 | private: // Member variables |
44 | - const size_t _columns; |
45 | + size_t _columns; |
46 | }; |
47 | |
48 | std::ostream& operator<<(std::ostream& output, const ResultSetMetaData &result_set); |
49 | |
50 | === added directory 'plugin/http_functions' |
51 | === added file 'plugin/http_functions/http_functions.cc' |
52 | --- plugin/http_functions/http_functions.cc 1970-01-01 00:00:00 +0000 |
53 | +++ plugin/http_functions/http_functions.cc 2011-05-04 01:52:37 +0000 |
54 | @@ -0,0 +1,199 @@ |
55 | +/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- |
56 | + * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
57 | + * |
58 | + * Copyright (C) 2011 Stewart Smith |
59 | + * |
60 | + * This program is free software; you can redistribute it and/or modify |
61 | + * it under the terms of the GNU General Public License as published by |
62 | + * the Free Software Foundation; version 2 of the License. |
63 | + * |
64 | + * This program is distributed in the hope that it will be useful, |
65 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
66 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
67 | + * GNU General Public License for more details. |
68 | + * |
69 | + * You should have received a copy of the GNU General Public License |
70 | + * along with this program; if not, write to the Free Software |
71 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
72 | + */ |
73 | + |
74 | +#include <config.h> |
75 | + |
76 | +#include <drizzled/plugin/function.h> |
77 | +#include <drizzled/function/str/strfunc.h> |
78 | +#include <drizzled/charset.h> |
79 | +#include <drizzled/error.h> |
80 | + |
81 | +#include <curl/curl.h> |
82 | + |
83 | +using namespace drizzled; |
84 | + |
85 | +class HttpGetFunction :public Item_str_func |
86 | +{ |
87 | + String result; |
88 | +public: |
89 | + HttpGetFunction() :Item_str_func() {} |
90 | + String *val_str(String *); |
91 | + void fix_length_and_dec(); |
92 | + const char *func_name() const { return "http_get"; } |
93 | + |
94 | + bool check_argument_count(int n) |
95 | + { |
96 | + return n == 1; |
97 | + } |
98 | +}; |
99 | + |
100 | +extern "C" size_t |
101 | +http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data); |
102 | + |
103 | +extern "C" size_t |
104 | +http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data) |
105 | +{ |
106 | + size_t realsize= size * nmemb; |
107 | + String *result= (String *)data; |
108 | + |
109 | + result->reserve(realsize + 1); |
110 | + result->append((const char*)ptr, realsize); |
111 | + |
112 | + return realsize; |
113 | +} |
114 | + |
115 | + |
116 | +String *HttpGetFunction::val_str(String *str) |
117 | +{ |
118 | + assert(fixed == 1); |
119 | + String *url = args[0]->val_str(str); |
120 | + CURL *curl; |
121 | + CURLcode retref; |
122 | + |
123 | + if ((null_value=args[0]->null_value)) |
124 | + return NULL; |
125 | + |
126 | + curl= curl_easy_init(); |
127 | + curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe()); |
128 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb); |
129 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result); |
130 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0"); |
131 | + retref= curl_easy_perform(curl); |
132 | + curl_easy_cleanup(curl); |
133 | + |
134 | + if (retref != 0) |
135 | + my_error(ER_GET_ERRMSG, MYF(0), retref, curl_easy_strerror(retref), |
136 | + "http_get"); |
137 | + |
138 | + return &result; |
139 | +} |
140 | + |
141 | +void HttpGetFunction::fix_length_and_dec() |
142 | +{ |
143 | + collation.set(args[0]->collation); |
144 | + max_length = ~0; |
145 | +} |
146 | + |
147 | +class HttpPostFunction :public Item_str_func |
148 | +{ |
149 | + String result; |
150 | +public: |
151 | + HttpPostFunction() :Item_str_func() {} |
152 | + String *val_str(String *); |
153 | + void fix_length_and_dec(); |
154 | + const char *func_name() const { return "http_post"; } |
155 | + |
156 | + bool check_argument_count(int n) |
157 | + { |
158 | + return n == 2; |
159 | + } |
160 | +}; |
161 | + |
162 | +class HttpPostData |
163 | +{ |
164 | +private: |
165 | + String *data; |
166 | + size_t progress; |
167 | + |
168 | +public: |
169 | + HttpPostData(String* d) : data(d), progress(0) {} |
170 | + |
171 | + size_t length() { return data->length(); } |
172 | + |
173 | + size_t write(void* dest, size_t size) |
174 | + { |
175 | + size_t to_write= size; |
176 | + |
177 | + if ((data->length() - progress) < to_write) |
178 | + to_write= data->length() - progress; |
179 | + |
180 | + memcpy(dest, data->ptr() + progress, to_write); |
181 | + |
182 | + progress+= to_write; |
183 | + |
184 | + return to_write; |
185 | + } |
186 | +}; |
187 | + |
188 | +extern "C" size_t |
189 | +http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data); |
190 | + |
191 | +extern "C" size_t |
192 | +http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data) |
193 | +{ |
194 | + size_t realsize= size * nmemb; |
195 | + HttpPostData *post_data= (HttpPostData *)data; |
196 | + |
197 | + return post_data->write(ptr, realsize); |
198 | +} |
199 | + |
200 | +String *HttpPostFunction::val_str(String *str) |
201 | +{ |
202 | + assert(fixed == 1); |
203 | + String *url = args[0]->val_str(str); |
204 | + CURL *curl; |
205 | + CURLcode retref; |
206 | + String post_storage; |
207 | + HttpPostData post_data(args[1]->val_str(&post_storage)); |
208 | + |
209 | + if ((null_value=args[0]->null_value)) |
210 | + return NULL; |
211 | + |
212 | + curl= curl_easy_init(); |
213 | + curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe()); |
214 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb); |
215 | + curl_easy_setopt(curl, CURLOPT_POST, 1L); |
216 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_data.length()); |
217 | + curl_easy_setopt(curl, CURLOPT_READDATA, &post_data); |
218 | + curl_easy_setopt(curl, CURLOPT_READFUNCTION, http_post_readfunc); |
219 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result); |
220 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0"); |
221 | + retref= curl_easy_perform(curl); |
222 | + curl_easy_cleanup(curl); |
223 | + |
224 | + return &result; |
225 | +} |
226 | + |
227 | +void HttpPostFunction::fix_length_and_dec() |
228 | +{ |
229 | + collation.set(args[0]->collation); |
230 | + max_length = ~0; |
231 | +} |
232 | + |
233 | +static int initialize(drizzled::module::Context &context) |
234 | +{ |
235 | + curl_global_init(CURL_GLOBAL_ALL); |
236 | + context.add(new plugin::Create_function<HttpGetFunction>("http_get")); |
237 | + context.add(new plugin::Create_function<HttpPostFunction>("http_post")); |
238 | + return 0; |
239 | +} |
240 | + |
241 | +DRIZZLE_DECLARE_PLUGIN |
242 | +{ |
243 | + DRIZZLE_VERSION_ID, |
244 | + "http_functions", |
245 | + "1.0", |
246 | + "Stewart Smith", |
247 | + "HTTP functions", |
248 | + PLUGIN_LICENSE_GPL, |
249 | + initialize, /* Plugin Init */ |
250 | + NULL, /* depends */ |
251 | + NULL /* config options */ |
252 | +} |
253 | +DRIZZLE_DECLARE_PLUGIN_END; |
254 | |
255 | === added file 'plugin/http_functions/plugin.ac' |
256 | --- plugin/http_functions/plugin.ac 1970-01-01 00:00:00 +0000 |
257 | +++ plugin/http_functions/plugin.ac 2011-05-04 01:52:37 +0000 |
258 | @@ -0,0 +1,4 @@ |
259 | +PANDORA_HAVE_LIBCURL |
260 | +AS_IF([test "x$ac_cv_libcurl" = "xno"], |
261 | + AC_MSG_WARN([libcurl not found: not building http_functions])) |
262 | +PANDORA_ADD_PLUGIN_DEP_LIB([${LIBCURL}]) |
263 | |
264 | === added file 'plugin/http_functions/plugin.cnf' |
265 | --- plugin/http_functions/plugin.cnf 1970-01-01 00:00:00 +0000 |
266 | +++ plugin/http_functions/plugin.cnf 2011-05-04 01:52:37 +0000 |
267 | @@ -0,0 +1,2 @@ |
268 | +plugin-add=http_functions |
269 | + |
270 | |
271 | === added file 'plugin/http_functions/plugin.ini' |
272 | --- plugin/http_functions/plugin.ini 1970-01-01 00:00:00 +0000 |
273 | +++ plugin/http_functions/plugin.ini 2011-05-04 01:52:37 +0000 |
274 | @@ -0,0 +1,6 @@ |
275 | +[plugin] |
276 | +title=HTTP functions |
277 | +description=HTTP functions: HTTP_GET() etc |
278 | +sources=http_functions.cc |
279 | +build_conditional="${ac_cv_libcurl}" = "yes" |
280 | +ldflags=${LTLIBCURL} |
281 | |
282 | === added directory 'plugin/json_server' |
283 | === added directory 'plugin/json_server/json' |
284 | === added file 'plugin/json_server/json/autolink.h' |
285 | --- plugin/json_server/json/autolink.h 1970-01-01 00:00:00 +0000 |
286 | +++ plugin/json_server/json/autolink.h 2011-05-04 01:52:37 +0000 |
287 | @@ -0,0 +1,58 @@ |
288 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
289 | + * |
290 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
291 | + * |
292 | + * Copyright (C) 2011 Stewart Smith |
293 | + * All rights reserved. |
294 | + * |
295 | + * Redistribution and use in source and binary forms, with or without |
296 | + * modification, are permitted provided that the following conditions are |
297 | + * met: |
298 | + * |
299 | + * * Redistributions of source code must retain the above copyright |
300 | + * notice, this list of conditions and the following disclaimer. |
301 | + * |
302 | + * * Redistributions in binary form must reproduce the above |
303 | + * copyright notice, this list of conditions and the following disclaimer |
304 | + * in the documentation and/or other materials provided with the |
305 | + * distribution. |
306 | + * |
307 | + * * The names of its contributors may not be used to endorse or |
308 | + * promote products derived from this software without specific prior |
309 | + * written permission. |
310 | + * |
311 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
312 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
313 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
314 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
315 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
316 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
317 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
318 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
319 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
320 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
321 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
322 | + * |
323 | + */ |
324 | + |
325 | +#pragma once |
326 | + |
327 | +#ifndef JSON_AUTOLINK_H_INCLUDED |
328 | +# define JSON_AUTOLINK_H_INCLUDED |
329 | + |
330 | +# include "config.h" |
331 | + |
332 | +# ifdef JSON_IN_CPPTL |
333 | +# include <cpptl/cpptl_autolink.h> |
334 | +# endif |
335 | + |
336 | +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) |
337 | +# define CPPTL_AUTOLINK_NAME "json" |
338 | +# undef CPPTL_AUTOLINK_DLL |
339 | +# ifdef JSON_DLL |
340 | +# define CPPTL_AUTOLINK_DLL |
341 | +# endif |
342 | +# include "autolink.h" |
343 | +# endif |
344 | + |
345 | +#endif // JSON_AUTOLINK_H_INCLUDED |
346 | |
347 | === added file 'plugin/json_server/json/config.h' |
348 | --- plugin/json_server/json/config.h 1970-01-01 00:00:00 +0000 |
349 | +++ plugin/json_server/json/config.h 2011-05-04 01:52:37 +0000 |
350 | @@ -0,0 +1,81 @@ |
351 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
352 | + * |
353 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
354 | + * |
355 | + * Copyright (C) 2011 Stewart Smith |
356 | + * All rights reserved. |
357 | + * |
358 | + * Redistribution and use in source and binary forms, with or without |
359 | + * modification, are permitted provided that the following conditions are |
360 | + * met: |
361 | + * |
362 | + * * Redistributions of source code must retain the above copyright |
363 | + * notice, this list of conditions and the following disclaimer. |
364 | + * |
365 | + * * Redistributions in binary form must reproduce the above |
366 | + * copyright notice, this list of conditions and the following disclaimer |
367 | + * in the documentation and/or other materials provided with the |
368 | + * distribution. |
369 | + * |
370 | + * * The names of its contributors may not be used to endorse or |
371 | + * promote products derived from this software without specific prior |
372 | + * written permission. |
373 | + * |
374 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
375 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
376 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
377 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
378 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
379 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
380 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
381 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
382 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
383 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
384 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
385 | + * |
386 | + */ |
387 | + |
388 | +#pragma once |
389 | +#ifndef JSON_CONFIG_H_INCLUDED |
390 | +# define JSON_CONFIG_H_INCLUDED |
391 | + |
392 | +/// If defined, indicates that json library is embedded in CppTL library. |
393 | +//# define JSON_IN_CPPTL 1 |
394 | + |
395 | +/// If defined, indicates that json may leverage CppTL library |
396 | +//# define JSON_USE_CPPTL 1 |
397 | +/// If defined, indicates that cpptl vector based map should be used instead of std::map |
398 | +/// as Value container. |
399 | +//# define JSON_USE_CPPTL_SMALLMAP 1 |
400 | +/// If defined, indicates that Json specific container should be used |
401 | +/// (hash table & simple deque container with customizable allocator). |
402 | +/// THIS FEATURE IS STILL EXPERIMENTAL! |
403 | +//# define JSON_VALUE_USE_INTERNAL_MAP 1 |
404 | +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. |
405 | +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink |
406 | +/// as if it was a POD) that may cause some validation tool to report errors. |
407 | +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. |
408 | +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 |
409 | + |
410 | +/// If defined, indicates that Json use exception to report invalid type manipulation |
411 | +/// instead of C assert macro. |
412 | +# define JSON_USE_EXCEPTION 1 |
413 | + |
414 | +# ifdef JSON_IN_CPPTL |
415 | +# include <cpptl/config.h> |
416 | +# ifndef JSON_USE_CPPTL |
417 | +# define JSON_USE_CPPTL 1 |
418 | +# endif |
419 | +# endif |
420 | + |
421 | +# ifdef JSON_IN_CPPTL |
422 | +# define JSON_API CPPTL_API |
423 | +# elif defined(JSON_DLL_BUILD) |
424 | +# define JSON_API __declspec(dllexport) |
425 | +# elif defined(JSON_DLL) |
426 | +# define JSON_API __declspec(dllimport) |
427 | +# else |
428 | +# define JSON_API |
429 | +# endif |
430 | + |
431 | +#endif // JSON_CONFIG_H_INCLUDED |
432 | |
433 | === added file 'plugin/json_server/json/features.h' |
434 | --- plugin/json_server/json/features.h 1970-01-01 00:00:00 +0000 |
435 | +++ plugin/json_server/json/features.h 2011-05-04 01:52:37 +0000 |
436 | @@ -0,0 +1,80 @@ |
437 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
438 | + * |
439 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
440 | + * |
441 | + * Copyright (C) 2011 Stewart Smith |
442 | + * All rights reserved. |
443 | + * |
444 | + * Redistribution and use in source and binary forms, with or without |
445 | + * modification, are permitted provided that the following conditions are |
446 | + * met: |
447 | + * |
448 | + * * Redistributions of source code must retain the above copyright |
449 | + * notice, this list of conditions and the following disclaimer. |
450 | + * |
451 | + * * Redistributions in binary form must reproduce the above |
452 | + * copyright notice, this list of conditions and the following disclaimer |
453 | + * in the documentation and/or other materials provided with the |
454 | + * distribution. |
455 | + * |
456 | + * * The names of its contributors may not be used to endorse or |
457 | + * promote products derived from this software without specific prior |
458 | + * written permission. |
459 | + * |
460 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
461 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
462 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
463 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
464 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
465 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
466 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
467 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
468 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
469 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
470 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
471 | + * |
472 | + */ |
473 | + |
474 | +#pragma once |
475 | +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED |
476 | +# define CPPTL_JSON_FEATURES_H_INCLUDED |
477 | + |
478 | +# include "forwards.h" |
479 | + |
480 | +namespace Json { |
481 | + |
482 | + /** \brief Configuration passed to reader and writer. |
483 | + * This configuration object can be used to force the Reader or Writer |
484 | + * to behave in a standard conforming way. |
485 | + */ |
486 | + class JSON_API Features |
487 | + { |
488 | + public: |
489 | + /** \brief A configuration that allows all features and assumes all strings are UTF-8. |
490 | + * - C & C++ comments are allowed |
491 | + * - Root object can be any JSON value |
492 | + * - Assumes Value strings are encoded in UTF-8 |
493 | + */ |
494 | + static Features all(); |
495 | + |
496 | + /** \brief A configuration that is strictly compatible with the JSON specification. |
497 | + * - Comments are forbidden. |
498 | + * - Root object must be either an array or an object value. |
499 | + * - Assumes Value strings are encoded in UTF-8 |
500 | + */ |
501 | + static Features strictMode(); |
502 | + |
503 | + /** \brief Initialize the configuration like JsonConfig::allFeatures; |
504 | + */ |
505 | + Features(); |
506 | + |
507 | + /// \c true if comments are allowed. Default: \c true. |
508 | + bool allowComments_; |
509 | + |
510 | + /// \c true if root must be either an array or an object value. Default: \c false. |
511 | + bool strictRoot_; |
512 | + }; |
513 | + |
514 | +} // namespace Json |
515 | + |
516 | +#endif // CPPTL_JSON_FEATURES_H_INCLUDED |
517 | |
518 | === added file 'plugin/json_server/json/forwards.h' |
519 | --- plugin/json_server/json/forwards.h 1970-01-01 00:00:00 +0000 |
520 | +++ plugin/json_server/json/forwards.h 2011-05-04 01:52:37 +0000 |
521 | @@ -0,0 +1,77 @@ |
522 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
523 | + * |
524 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
525 | + * |
526 | + * Copyright (C) 2011 Stewart Smith |
527 | + * All rights reserved. |
528 | + * |
529 | + * Redistribution and use in source and binary forms, with or without |
530 | + * modification, are permitted provided that the following conditions are |
531 | + * met: |
532 | + * |
533 | + * * Redistributions of source code must retain the above copyright |
534 | + * notice, this list of conditions and the following disclaimer. |
535 | + * |
536 | + * * Redistributions in binary form must reproduce the above |
537 | + * copyright notice, this list of conditions and the following disclaimer |
538 | + * in the documentation and/or other materials provided with the |
539 | + * distribution. |
540 | + * |
541 | + * * The names of its contributors may not be used to endorse or |
542 | + * promote products derived from this software without specific prior |
543 | + * written permission. |
544 | + * |
545 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
546 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
547 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
548 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
549 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
550 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
551 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
552 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
553 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
554 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
555 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
556 | + * |
557 | + */ |
558 | + |
559 | +#pragma once |
560 | +#ifndef JSON_FORWARDS_H_INCLUDED |
561 | +# define JSON_FORWARDS_H_INCLUDED |
562 | + |
563 | +# include "config.h" |
564 | + |
565 | +namespace Json { |
566 | + |
567 | + // writer.h |
568 | + class FastWriter; |
569 | + class StyledWriter; |
570 | + |
571 | + // reader.h |
572 | + class Reader; |
573 | + |
574 | + // features.h |
575 | + class Features; |
576 | + |
577 | + // value.h |
578 | + typedef int Int; |
579 | + typedef unsigned int UInt; |
580 | + class StaticString; |
581 | + class Path; |
582 | + class PathArgument; |
583 | + class Value; |
584 | + class ValueIteratorBase; |
585 | + class ValueIterator; |
586 | + class ValueConstIterator; |
587 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
588 | + class ValueAllocator; |
589 | + class ValueMapAllocator; |
590 | + class ValueInternalLink; |
591 | + class ValueInternalArray; |
592 | + class ValueInternalMap; |
593 | +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP |
594 | + |
595 | +} // namespace Json |
596 | + |
597 | + |
598 | +#endif // JSON_FORWARDS_H_INCLUDED |
599 | |
600 | === added file 'plugin/json_server/json/json.h' |
601 | --- plugin/json_server/json/json.h 1970-01-01 00:00:00 +0000 |
602 | +++ plugin/json_server/json/json.h 2011-05-04 01:52:37 +0000 |
603 | @@ -0,0 +1,48 @@ |
604 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
605 | + * |
606 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
607 | + * |
608 | + * Copyright (C) 2011 Stewart Smith |
609 | + * All rights reserved. |
610 | + * |
611 | + * Redistribution and use in source and binary forms, with or without |
612 | + * modification, are permitted provided that the following conditions are |
613 | + * met: |
614 | + * |
615 | + * * Redistributions of source code must retain the above copyright |
616 | + * notice, this list of conditions and the following disclaimer. |
617 | + * |
618 | + * * Redistributions in binary form must reproduce the above |
619 | + * copyright notice, this list of conditions and the following disclaimer |
620 | + * in the documentation and/or other materials provided with the |
621 | + * distribution. |
622 | + * |
623 | + * * The names of its contributors may not be used to endorse or |
624 | + * promote products derived from this software without specific prior |
625 | + * written permission. |
626 | + * |
627 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
628 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
629 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
630 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
631 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
632 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
633 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
634 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
635 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
636 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
637 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
638 | + * |
639 | + */ |
640 | + |
641 | +#pragma once |
642 | +#ifndef JSON_JSON_H_INCLUDED |
643 | +# define JSON_JSON_H_INCLUDED |
644 | + |
645 | +# include "autolink.h" |
646 | +# include "value.h" |
647 | +# include "reader.h" |
648 | +# include "writer.h" |
649 | +# include "features.h" |
650 | + |
651 | +#endif // JSON_JSON_H_INCLUDED |
652 | |
653 | === added file 'plugin/json_server/json/json_batchallocator.h' |
654 | --- plugin/json_server/json/json_batchallocator.h 1970-01-01 00:00:00 +0000 |
655 | +++ plugin/json_server/json/json_batchallocator.h 2011-05-04 01:52:37 +0000 |
656 | @@ -0,0 +1,163 @@ |
657 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
658 | + * |
659 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
660 | + * |
661 | + * Copyright (C) 2011 Stewart Smith |
662 | + * All rights reserved. |
663 | + * |
664 | + * Redistribution and use in source and binary forms, with or without |
665 | + * modification, are permitted provided that the following conditions are |
666 | + * met: |
667 | + * |
668 | + * * Redistributions of source code must retain the above copyright |
669 | + * notice, this list of conditions and the following disclaimer. |
670 | + * |
671 | + * * Redistributions in binary form must reproduce the above |
672 | + * copyright notice, this list of conditions and the following disclaimer |
673 | + * in the documentation and/or other materials provided with the |
674 | + * distribution. |
675 | + * |
676 | + * * The names of its contributors may not be used to endorse or |
677 | + * promote products derived from this software without specific prior |
678 | + * written permission. |
679 | + * |
680 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
681 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
682 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
683 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
684 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
685 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
686 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
687 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
688 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
689 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
690 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
691 | + * |
692 | + */ |
693 | + |
694 | +#pragma once |
695 | +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED |
696 | +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED |
697 | + |
698 | +# include <stdlib.h> |
699 | +# include <assert.h> |
700 | + |
701 | +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION |
702 | + |
703 | +namespace Json { |
704 | + |
705 | +/* Fast memory allocator. |
706 | + * |
707 | + * This memory allocator allocates memory for a batch of object (specified by |
708 | + * the page size, the number of object in each page). |
709 | + * |
710 | + * It does not allow the destruction of a single object. All the allocated objects |
711 | + * can be destroyed at once. The memory can be either released or reused for future |
712 | + * allocation. |
713 | + * |
714 | + * The in-place new operator must be used to construct the object using the pointer |
715 | + * returned by allocate. |
716 | + */ |
717 | +template<typename AllocatedType |
718 | + ,const unsigned int objectPerAllocation> |
719 | +class BatchAllocator |
720 | +{ |
721 | +public: |
722 | + typedef AllocatedType Type; |
723 | + |
724 | + BatchAllocator( unsigned int objectsPerPage = 255 ) |
725 | + : freeHead_( 0 ) |
726 | + , objectsPerPage_( objectsPerPage ) |
727 | + { |
728 | +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); |
729 | + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. |
730 | + assert( objectsPerPage >= 16 ); |
731 | + batches_ = allocateBatch( 0 ); // allocated a dummy page |
732 | + currentBatch_ = batches_; |
733 | + } |
734 | + |
735 | + ~BatchAllocator() |
736 | + { |
737 | + for ( BatchInfo *batch = batches_; batch; ) |
738 | + { |
739 | + BatchInfo *nextBatch = batch->next_; |
740 | + free( batch ); |
741 | + batch = nextBatch; |
742 | + } |
743 | + } |
744 | + |
745 | + /// allocate space for an array of objectPerAllocation object. |
746 | + /// @warning it is the responsability of the caller to call objects constructors. |
747 | + AllocatedType *allocate() |
748 | + { |
749 | + if ( freeHead_ ) // returns node from free list. |
750 | + { |
751 | + AllocatedType *object = freeHead_; |
752 | + freeHead_ = *(AllocatedType **)object; |
753 | + return object; |
754 | + } |
755 | + if ( currentBatch_->used_ == currentBatch_->end_ ) |
756 | + { |
757 | + currentBatch_ = currentBatch_->next_; |
758 | + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) |
759 | + currentBatch_ = currentBatch_->next_; |
760 | + |
761 | + if ( !currentBatch_ ) // no free batch found, allocate a new one |
762 | + { |
763 | + currentBatch_ = allocateBatch( objectsPerPage_ ); |
764 | + currentBatch_->next_ = batches_; // insert at the head of the list |
765 | + batches_ = currentBatch_; |
766 | + } |
767 | + } |
768 | + AllocatedType *allocated = currentBatch_->used_; |
769 | + currentBatch_->used_ += objectPerAllocation; |
770 | + return allocated; |
771 | + } |
772 | + |
773 | + /// Release the object. |
774 | + /// @warning it is the responsability of the caller to actually destruct the object. |
775 | + void release( AllocatedType *object ) |
776 | + { |
777 | + assert( object != 0 ); |
778 | + *(AllocatedType **)object = freeHead_; |
779 | + freeHead_ = object; |
780 | + } |
781 | + |
782 | +private: |
783 | + struct BatchInfo |
784 | + { |
785 | + BatchInfo *next_; |
786 | + AllocatedType *used_; |
787 | + AllocatedType *end_; |
788 | + AllocatedType buffer_[objectPerAllocation]; |
789 | + }; |
790 | + |
791 | + // disabled copy constructor and assignement operator. |
792 | + BatchAllocator( const BatchAllocator & ); |
793 | + void operator =( const BatchAllocator &); |
794 | + |
795 | + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) |
796 | + { |
797 | + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation |
798 | + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; |
799 | + BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); |
800 | + batch->next_ = 0; |
801 | + batch->used_ = batch->buffer_; |
802 | + batch->end_ = batch->buffer_ + objectsPerPage; |
803 | + return batch; |
804 | + } |
805 | + |
806 | + BatchInfo *batches_; |
807 | + BatchInfo *currentBatch_; |
808 | + /// Head of a single linked list within the allocated space of freeed object |
809 | + AllocatedType *freeHead_; |
810 | + unsigned int objectsPerPage_; |
811 | +}; |
812 | + |
813 | + |
814 | +} // namespace Json |
815 | + |
816 | +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION |
817 | + |
818 | +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED |
819 | + |
820 | |
821 | === added file 'plugin/json_server/json/json_internalarray.inl' |
822 | --- plugin/json_server/json/json_internalarray.inl 1970-01-01 00:00:00 +0000 |
823 | +++ plugin/json_server/json/json_internalarray.inl 2011-05-04 01:52:37 +0000 |
824 | @@ -0,0 +1,486 @@ |
825 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
826 | + * |
827 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
828 | + * |
829 | + * Copyright (C) 2011 Stewart Smith |
830 | + * All rights reserved. |
831 | + * |
832 | + * Redistribution and use in source and binary forms, with or without |
833 | + * modification, are permitted provided that the following conditions are |
834 | + * met: |
835 | + * |
836 | + * * Redistributions of source code must retain the above copyright |
837 | + * notice, this list of conditions and the following disclaimer. |
838 | + * |
839 | + * * Redistributions in binary form must reproduce the above |
840 | + * copyright notice, this list of conditions and the following disclaimer |
841 | + * in the documentation and/or other materials provided with the |
842 | + * distribution. |
843 | + * |
844 | + * * The names of its contributors may not be used to endorse or |
845 | + * promote products derived from this software without specific prior |
846 | + * written permission. |
847 | + * |
848 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
849 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
850 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
851 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
852 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
853 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
854 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
855 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
856 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
857 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
858 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
859 | + * |
860 | + */ |
861 | + |
862 | +#pragma once |
863 | +// included by json_value.cpp |
864 | +// everything is within Json namespace |
865 | + |
866 | +// ////////////////////////////////////////////////////////////////// |
867 | +// ////////////////////////////////////////////////////////////////// |
868 | +// ////////////////////////////////////////////////////////////////// |
869 | +// class ValueInternalArray |
870 | +// ////////////////////////////////////////////////////////////////// |
871 | +// ////////////////////////////////////////////////////////////////// |
872 | +// ////////////////////////////////////////////////////////////////// |
873 | + |
874 | +ValueArrayAllocator::~ValueArrayAllocator() |
875 | +{ |
876 | +} |
877 | + |
878 | +// ////////////////////////////////////////////////////////////////// |
879 | +// class DefaultValueArrayAllocator |
880 | +// ////////////////////////////////////////////////////////////////// |
881 | +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
882 | +class DefaultValueArrayAllocator : public ValueArrayAllocator |
883 | +{ |
884 | +public: // overridden from ValueArrayAllocator |
885 | + virtual ~DefaultValueArrayAllocator() |
886 | + { |
887 | + } |
888 | + |
889 | + virtual ValueInternalArray *newArray() |
890 | + { |
891 | + return new ValueInternalArray(); |
892 | + } |
893 | + |
894 | + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) |
895 | + { |
896 | + return new ValueInternalArray( other ); |
897 | + } |
898 | + |
899 | + virtual void destructArray( ValueInternalArray *array ) |
900 | + { |
901 | + delete array; |
902 | + } |
903 | + |
904 | + virtual void reallocateArrayPageIndex( Value **&indexes, |
905 | + ValueInternalArray::PageIndex &indexCount, |
906 | + ValueInternalArray::PageIndex minNewIndexCount ) |
907 | + { |
908 | + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; |
909 | + if ( minNewIndexCount > newIndexCount ) |
910 | + newIndexCount = minNewIndexCount; |
911 | + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); |
912 | + if ( !newIndexes ) |
913 | + throw std::bad_alloc(); |
914 | + indexCount = newIndexCount; |
915 | + indexes = static_cast<Value **>( newIndexes ); |
916 | + } |
917 | + virtual void releaseArrayPageIndex( Value **indexes, |
918 | + ValueInternalArray::PageIndex indexCount ) |
919 | + { |
920 | + if ( indexes ) |
921 | + free( indexes ); |
922 | + } |
923 | + |
924 | + virtual Value *allocateArrayPage() |
925 | + { |
926 | + return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); |
927 | + } |
928 | + |
929 | + virtual void releaseArrayPage( Value *value ) |
930 | + { |
931 | + if ( value ) |
932 | + free( value ); |
933 | + } |
934 | +}; |
935 | + |
936 | +#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
937 | +/// @todo make this thread-safe (lock when accessign batch allocator) |
938 | +class DefaultValueArrayAllocator : public ValueArrayAllocator |
939 | +{ |
940 | +public: // overridden from ValueArrayAllocator |
941 | + virtual ~DefaultValueArrayAllocator() |
942 | + { |
943 | + } |
944 | + |
945 | + virtual ValueInternalArray *newArray() |
946 | + { |
947 | + ValueInternalArray *array = arraysAllocator_.allocate(); |
948 | + new (array) ValueInternalArray(); // placement new |
949 | + return array; |
950 | + } |
951 | + |
952 | + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) |
953 | + { |
954 | + ValueInternalArray *array = arraysAllocator_.allocate(); |
955 | + new (array) ValueInternalArray( other ); // placement new |
956 | + return array; |
957 | + } |
958 | + |
959 | + virtual void destructArray( ValueInternalArray *array ) |
960 | + { |
961 | + if ( array ) |
962 | + { |
963 | + array->~ValueInternalArray(); |
964 | + arraysAllocator_.release( array ); |
965 | + } |
966 | + } |
967 | + |
968 | + virtual void reallocateArrayPageIndex( Value **&indexes, |
969 | + ValueInternalArray::PageIndex &indexCount, |
970 | + ValueInternalArray::PageIndex minNewIndexCount ) |
971 | + { |
972 | + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; |
973 | + if ( minNewIndexCount > newIndexCount ) |
974 | + newIndexCount = minNewIndexCount; |
975 | + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); |
976 | + if ( !newIndexes ) |
977 | + throw std::bad_alloc(); |
978 | + indexCount = newIndexCount; |
979 | + indexes = static_cast<Value **>( newIndexes ); |
980 | + } |
981 | + virtual void releaseArrayPageIndex( Value **indexes, |
982 | + ValueInternalArray::PageIndex indexCount ) |
983 | + { |
984 | + if ( indexes ) |
985 | + free( indexes ); |
986 | + } |
987 | + |
988 | + virtual Value *allocateArrayPage() |
989 | + { |
990 | + return static_cast<Value *>( pagesAllocator_.allocate() ); |
991 | + } |
992 | + |
993 | + virtual void releaseArrayPage( Value *value ) |
994 | + { |
995 | + if ( value ) |
996 | + pagesAllocator_.release( value ); |
997 | + } |
998 | +private: |
999 | + BatchAllocator<ValueInternalArray,1> arraysAllocator_; |
1000 | + BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_; |
1001 | +}; |
1002 | +#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
1003 | + |
1004 | +static ValueArrayAllocator *&arrayAllocator() |
1005 | +{ |
1006 | + static DefaultValueArrayAllocator defaultAllocator; |
1007 | + static ValueArrayAllocator *arrayAllocator = &defaultAllocator; |
1008 | + return arrayAllocator; |
1009 | +} |
1010 | + |
1011 | +static struct DummyArrayAllocatorInitializer { |
1012 | + DummyArrayAllocatorInitializer() |
1013 | + { |
1014 | + arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). |
1015 | + } |
1016 | +} dummyArrayAllocatorInitializer; |
1017 | + |
1018 | +// ////////////////////////////////////////////////////////////////// |
1019 | +// class ValueInternalArray |
1020 | +// ////////////////////////////////////////////////////////////////// |
1021 | +bool |
1022 | +ValueInternalArray::equals( const IteratorState &x, |
1023 | + const IteratorState &other ) |
1024 | +{ |
1025 | + return x.array_ == other.array_ |
1026 | + && x.currentItemIndex_ == other.currentItemIndex_ |
1027 | + && x.currentPageIndex_ == other.currentPageIndex_; |
1028 | +} |
1029 | + |
1030 | + |
1031 | +void |
1032 | +ValueInternalArray::increment( IteratorState &it ) |
1033 | +{ |
1034 | + JSON_ASSERT_MESSAGE( it.array_ && |
1035 | + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ |
1036 | + != it.array_->size_, |
1037 | + "ValueInternalArray::increment(): moving iterator beyond end" ); |
1038 | + ++(it.currentItemIndex_); |
1039 | + if ( it.currentItemIndex_ == itemsPerPage ) |
1040 | + { |
1041 | + it.currentItemIndex_ = 0; |
1042 | + ++(it.currentPageIndex_); |
1043 | + } |
1044 | +} |
1045 | + |
1046 | + |
1047 | +void |
1048 | +ValueInternalArray::decrement( IteratorState &it ) |
1049 | +{ |
1050 | + JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ |
1051 | + && it.currentItemIndex_ == 0, |
1052 | + "ValueInternalArray::decrement(): moving iterator beyond end" ); |
1053 | + if ( it.currentItemIndex_ == 0 ) |
1054 | + { |
1055 | + it.currentItemIndex_ = itemsPerPage-1; |
1056 | + --(it.currentPageIndex_); |
1057 | + } |
1058 | + else |
1059 | + { |
1060 | + --(it.currentItemIndex_); |
1061 | + } |
1062 | +} |
1063 | + |
1064 | + |
1065 | +Value & |
1066 | +ValueInternalArray::unsafeDereference( const IteratorState &it ) |
1067 | +{ |
1068 | + return (*(it.currentPageIndex_))[it.currentItemIndex_]; |
1069 | +} |
1070 | + |
1071 | + |
1072 | +Value & |
1073 | +ValueInternalArray::dereference( const IteratorState &it ) |
1074 | +{ |
1075 | + JSON_ASSERT_MESSAGE( it.array_ && |
1076 | + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ |
1077 | + < it.array_->size_, |
1078 | + "ValueInternalArray::dereference(): dereferencing invalid iterator" ); |
1079 | + return unsafeDereference( it ); |
1080 | +} |
1081 | + |
1082 | +void |
1083 | +ValueInternalArray::makeBeginIterator( IteratorState &it ) const |
1084 | +{ |
1085 | + it.array_ = const_cast<ValueInternalArray *>( this ); |
1086 | + it.currentItemIndex_ = 0; |
1087 | + it.currentPageIndex_ = pages_; |
1088 | +} |
1089 | + |
1090 | + |
1091 | +void |
1092 | +ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const |
1093 | +{ |
1094 | + it.array_ = const_cast<ValueInternalArray *>( this ); |
1095 | + it.currentItemIndex_ = index % itemsPerPage; |
1096 | + it.currentPageIndex_ = pages_ + index / itemsPerPage; |
1097 | +} |
1098 | + |
1099 | + |
1100 | +void |
1101 | +ValueInternalArray::makeEndIterator( IteratorState &it ) const |
1102 | +{ |
1103 | + makeIterator( it, size_ ); |
1104 | +} |
1105 | + |
1106 | + |
1107 | +ValueInternalArray::ValueInternalArray() |
1108 | + : pages_( 0 ) |
1109 | + , size_( 0 ) |
1110 | + , pageCount_( 0 ) |
1111 | +{ |
1112 | +} |
1113 | + |
1114 | + |
1115 | +ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) |
1116 | + : pages_( 0 ) |
1117 | + , pageCount_( 0 ) |
1118 | + , size_( other.size_ ) |
1119 | +{ |
1120 | + PageIndex minNewPages = other.size_ / itemsPerPage; |
1121 | + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); |
1122 | + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, |
1123 | + "ValueInternalArray::reserve(): bad reallocation" ); |
1124 | + IteratorState itOther; |
1125 | + other.makeBeginIterator( itOther ); |
1126 | + Value *value; |
1127 | + for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) |
1128 | + { |
1129 | + if ( index % itemsPerPage == 0 ) |
1130 | + { |
1131 | + PageIndex pageIndex = index / itemsPerPage; |
1132 | + value = arrayAllocator()->allocateArrayPage(); |
1133 | + pages_[pageIndex] = value; |
1134 | + } |
1135 | + new (value) Value( dereference( itOther ) ); |
1136 | + } |
1137 | +} |
1138 | + |
1139 | + |
1140 | +ValueInternalArray & |
1141 | +ValueInternalArray::operator =( const ValueInternalArray &other ) |
1142 | +{ |
1143 | + ValueInternalArray temp( other ); |
1144 | + swap( temp ); |
1145 | + return *this; |
1146 | +} |
1147 | + |
1148 | + |
1149 | +ValueInternalArray::~ValueInternalArray() |
1150 | +{ |
1151 | + // destroy all constructed items |
1152 | + IteratorState it; |
1153 | + IteratorState itEnd; |
1154 | + makeBeginIterator( it); |
1155 | + makeEndIterator( itEnd ); |
1156 | + for ( ; !equals(it,itEnd); increment(it) ) |
1157 | + { |
1158 | + Value *value = &dereference(it); |
1159 | + value->~Value(); |
1160 | + } |
1161 | + // release all pages |
1162 | + PageIndex lastPageIndex = size_ / itemsPerPage; |
1163 | + for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) |
1164 | + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); |
1165 | + // release pages index |
1166 | + arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); |
1167 | +} |
1168 | + |
1169 | + |
1170 | +void |
1171 | +ValueInternalArray::swap( ValueInternalArray &other ) |
1172 | +{ |
1173 | + Value **tempPages = pages_; |
1174 | + pages_ = other.pages_; |
1175 | + other.pages_ = tempPages; |
1176 | + ArrayIndex tempSize = size_; |
1177 | + size_ = other.size_; |
1178 | + other.size_ = tempSize; |
1179 | + PageIndex tempPageCount = pageCount_; |
1180 | + pageCount_ = other.pageCount_; |
1181 | + other.pageCount_ = tempPageCount; |
1182 | +} |
1183 | + |
1184 | +void |
1185 | +ValueInternalArray::clear() |
1186 | +{ |
1187 | + ValueInternalArray dummy; |
1188 | + swap( dummy ); |
1189 | +} |
1190 | + |
1191 | + |
1192 | +void |
1193 | +ValueInternalArray::resize( ArrayIndex newSize ) |
1194 | +{ |
1195 | + if ( newSize == 0 ) |
1196 | + clear(); |
1197 | + else if ( newSize < size_ ) |
1198 | + { |
1199 | + IteratorState it; |
1200 | + IteratorState itEnd; |
1201 | + makeIterator( it, newSize ); |
1202 | + makeIterator( itEnd, size_ ); |
1203 | + for ( ; !equals(it,itEnd); increment(it) ) |
1204 | + { |
1205 | + Value *value = &dereference(it); |
1206 | + value->~Value(); |
1207 | + } |
1208 | + PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; |
1209 | + PageIndex lastPageIndex = size_ / itemsPerPage; |
1210 | + for ( ; pageIndex < lastPageIndex; ++pageIndex ) |
1211 | + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); |
1212 | + size_ = newSize; |
1213 | + } |
1214 | + else if ( newSize > size_ ) |
1215 | + resolveReference( newSize ); |
1216 | +} |
1217 | + |
1218 | + |
1219 | +void |
1220 | +ValueInternalArray::makeIndexValid( ArrayIndex index ) |
1221 | +{ |
1222 | + // Need to enlarge page index ? |
1223 | + if ( index >= pageCount_ * itemsPerPage ) |
1224 | + { |
1225 | + PageIndex minNewPages = (index + 1) / itemsPerPage; |
1226 | + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); |
1227 | + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); |
1228 | + } |
1229 | + |
1230 | + // Need to allocate new pages ? |
1231 | + ArrayIndex nextPageIndex = |
1232 | + (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage |
1233 | + : size_; |
1234 | + if ( nextPageIndex <= index ) |
1235 | + { |
1236 | + PageIndex pageIndex = nextPageIndex / itemsPerPage; |
1237 | + PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; |
1238 | + for ( ; pageToAllocate-- > 0; ++pageIndex ) |
1239 | + pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); |
1240 | + } |
1241 | + |
1242 | + // Initialize all new entries |
1243 | + IteratorState it; |
1244 | + IteratorState itEnd; |
1245 | + makeIterator( it, size_ ); |
1246 | + size_ = index + 1; |
1247 | + makeIterator( itEnd, size_ ); |
1248 | + for ( ; !equals(it,itEnd); increment(it) ) |
1249 | + { |
1250 | + Value *value = &dereference(it); |
1251 | + new (value) Value(); // Construct a default value using placement new |
1252 | + } |
1253 | +} |
1254 | + |
1255 | +Value & |
1256 | +ValueInternalArray::resolveReference( ArrayIndex index ) |
1257 | +{ |
1258 | + if ( index >= size_ ) |
1259 | + makeIndexValid( index ); |
1260 | + return pages_[index/itemsPerPage][index%itemsPerPage]; |
1261 | +} |
1262 | + |
1263 | +Value * |
1264 | +ValueInternalArray::find( ArrayIndex index ) const |
1265 | +{ |
1266 | + if ( index >= size_ ) |
1267 | + return 0; |
1268 | + return &(pages_[index/itemsPerPage][index%itemsPerPage]); |
1269 | +} |
1270 | + |
1271 | +ValueInternalArray::ArrayIndex |
1272 | +ValueInternalArray::size() const |
1273 | +{ |
1274 | + return size_; |
1275 | +} |
1276 | + |
1277 | +int |
1278 | +ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) |
1279 | +{ |
1280 | + return indexOf(y) - indexOf(x); |
1281 | +} |
1282 | + |
1283 | + |
1284 | +ValueInternalArray::ArrayIndex |
1285 | +ValueInternalArray::indexOf( const IteratorState &iterator ) |
1286 | +{ |
1287 | + if ( !iterator.array_ ) |
1288 | + return ArrayIndex(-1); |
1289 | + return ArrayIndex( |
1290 | + (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage |
1291 | + + iterator.currentItemIndex_ ); |
1292 | +} |
1293 | + |
1294 | + |
1295 | +int |
1296 | +ValueInternalArray::compare( const ValueInternalArray &other ) const |
1297 | +{ |
1298 | + int sizeDiff( size_ - other.size_ ); |
1299 | + if ( sizeDiff != 0 ) |
1300 | + return sizeDiff; |
1301 | + |
1302 | + for ( ArrayIndex index =0; index < size_; ++index ) |
1303 | + { |
1304 | + int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( |
1305 | + other.pages_[index/itemsPerPage][index%itemsPerPage] ); |
1306 | + if ( diff != 0 ) |
1307 | + return diff; |
1308 | + } |
1309 | + return 0; |
1310 | +} |
1311 | |
1312 | === added file 'plugin/json_server/json/json_internalmap.inl' |
1313 | --- plugin/json_server/json/json_internalmap.inl 1970-01-01 00:00:00 +0000 |
1314 | +++ plugin/json_server/json/json_internalmap.inl 2011-05-04 01:52:37 +0000 |
1315 | @@ -0,0 +1,645 @@ |
1316 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
1317 | + * |
1318 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
1319 | + * |
1320 | + * Copyright (C) 2011 Stewart Smith |
1321 | + * All rights reserved. |
1322 | + * |
1323 | + * Redistribution and use in source and binary forms, with or without |
1324 | + * modification, are permitted provided that the following conditions are |
1325 | + * met: |
1326 | + * |
1327 | + * * Redistributions of source code must retain the above copyright |
1328 | + * notice, this list of conditions and the following disclaimer. |
1329 | + * |
1330 | + * * Redistributions in binary form must reproduce the above |
1331 | + * copyright notice, this list of conditions and the following disclaimer |
1332 | + * in the documentation and/or other materials provided with the |
1333 | + * distribution. |
1334 | + * |
1335 | + * * The names of its contributors may not be used to endorse or |
1336 | + * promote products derived from this software without specific prior |
1337 | + * written permission. |
1338 | + * |
1339 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
1340 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
1341 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
1342 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
1343 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
1344 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
1345 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
1346 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
1347 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
1348 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
1349 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
1350 | + * |
1351 | + */ |
1352 | + |
1353 | +#pragma once |
1354 | +// included by json_value.cpp |
1355 | +// everything is within Json namespace |
1356 | + |
1357 | +// ////////////////////////////////////////////////////////////////// |
1358 | +// ////////////////////////////////////////////////////////////////// |
1359 | +// ////////////////////////////////////////////////////////////////// |
1360 | +// class ValueInternalMap |
1361 | +// ////////////////////////////////////////////////////////////////// |
1362 | +// ////////////////////////////////////////////////////////////////// |
1363 | +// ////////////////////////////////////////////////////////////////// |
1364 | + |
1365 | +/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); |
1366 | + * This optimization is used by the fast allocator. |
1367 | + */ |
1368 | +ValueInternalLink::ValueInternalLink() |
1369 | + : previous_( 0 ) |
1370 | + , next_( 0 ) |
1371 | +{ |
1372 | +} |
1373 | + |
1374 | +ValueInternalLink::~ValueInternalLink() |
1375 | +{ |
1376 | + for ( int index =0; index < itemPerLink; ++index ) |
1377 | + { |
1378 | + if ( !items_[index].isItemAvailable() ) |
1379 | + { |
1380 | + if ( !items_[index].isMemberNameStatic() ) |
1381 | + free( keys_[index] ); |
1382 | + } |
1383 | + else |
1384 | + break; |
1385 | + } |
1386 | +} |
1387 | + |
1388 | + |
1389 | + |
1390 | +ValueMapAllocator::~ValueMapAllocator() |
1391 | +{ |
1392 | +} |
1393 | + |
1394 | +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
1395 | +class DefaultValueMapAllocator : public ValueMapAllocator |
1396 | +{ |
1397 | +public: // overridden from ValueMapAllocator |
1398 | + virtual ValueInternalMap *newMap() |
1399 | + { |
1400 | + return new ValueInternalMap(); |
1401 | + } |
1402 | + |
1403 | + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) |
1404 | + { |
1405 | + return new ValueInternalMap( other ); |
1406 | + } |
1407 | + |
1408 | + virtual void destructMap( ValueInternalMap *map ) |
1409 | + { |
1410 | + delete map; |
1411 | + } |
1412 | + |
1413 | + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) |
1414 | + { |
1415 | + return new ValueInternalLink[size]; |
1416 | + } |
1417 | + |
1418 | + virtual void releaseMapBuckets( ValueInternalLink *links ) |
1419 | + { |
1420 | + delete [] links; |
1421 | + } |
1422 | + |
1423 | + virtual ValueInternalLink *allocateMapLink() |
1424 | + { |
1425 | + return new ValueInternalLink(); |
1426 | + } |
1427 | + |
1428 | + virtual void releaseMapLink( ValueInternalLink *link ) |
1429 | + { |
1430 | + delete link; |
1431 | + } |
1432 | +}; |
1433 | +#else |
1434 | +/// @todo make this thread-safe (lock when accessign batch allocator) |
1435 | +class DefaultValueMapAllocator : public ValueMapAllocator |
1436 | +{ |
1437 | +public: // overridden from ValueMapAllocator |
1438 | + virtual ValueInternalMap *newMap() |
1439 | + { |
1440 | + ValueInternalMap *map = mapsAllocator_.allocate(); |
1441 | + new (map) ValueInternalMap(); // placement new |
1442 | + return map; |
1443 | + } |
1444 | + |
1445 | + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) |
1446 | + { |
1447 | + ValueInternalMap *map = mapsAllocator_.allocate(); |
1448 | + new (map) ValueInternalMap( other ); // placement new |
1449 | + return map; |
1450 | + } |
1451 | + |
1452 | + virtual void destructMap( ValueInternalMap *map ) |
1453 | + { |
1454 | + if ( map ) |
1455 | + { |
1456 | + map->~ValueInternalMap(); |
1457 | + mapsAllocator_.release( map ); |
1458 | + } |
1459 | + } |
1460 | + |
1461 | + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) |
1462 | + { |
1463 | + return new ValueInternalLink[size]; |
1464 | + } |
1465 | + |
1466 | + virtual void releaseMapBuckets( ValueInternalLink *links ) |
1467 | + { |
1468 | + delete [] links; |
1469 | + } |
1470 | + |
1471 | + virtual ValueInternalLink *allocateMapLink() |
1472 | + { |
1473 | + ValueInternalLink *link = linksAllocator_.allocate(); |
1474 | + memset( link, 0, sizeof(ValueInternalLink) ); |
1475 | + return link; |
1476 | + } |
1477 | + |
1478 | + virtual void releaseMapLink( ValueInternalLink *link ) |
1479 | + { |
1480 | + link->~ValueInternalLink(); |
1481 | + linksAllocator_.release( link ); |
1482 | + } |
1483 | +private: |
1484 | + BatchAllocator<ValueInternalMap,1> mapsAllocator_; |
1485 | + BatchAllocator<ValueInternalLink,1> linksAllocator_; |
1486 | +}; |
1487 | +#endif |
1488 | + |
1489 | +static ValueMapAllocator *&mapAllocator() |
1490 | +{ |
1491 | + static DefaultValueMapAllocator defaultAllocator; |
1492 | + static ValueMapAllocator *mapAllocator = &defaultAllocator; |
1493 | + return mapAllocator; |
1494 | +} |
1495 | + |
1496 | +static struct DummyMapAllocatorInitializer { |
1497 | + DummyMapAllocatorInitializer() |
1498 | + { |
1499 | + mapAllocator(); // ensure mapAllocator() statics are initialized before main(). |
1500 | + } |
1501 | +} dummyMapAllocatorInitializer; |
1502 | + |
1503 | + |
1504 | + |
1505 | +// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. |
1506 | + |
1507 | +/* |
1508 | +use linked list hash map. |
1509 | +buckets array is a container. |
1510 | +linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) |
1511 | +value have extra state: valid, available, deleted |
1512 | +*/ |
1513 | + |
1514 | + |
1515 | +ValueInternalMap::ValueInternalMap() |
1516 | + : buckets_( 0 ) |
1517 | + , tailLink_( 0 ) |
1518 | + , bucketsSize_( 0 ) |
1519 | + , itemCount_( 0 ) |
1520 | +{ |
1521 | +} |
1522 | + |
1523 | + |
1524 | +ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) |
1525 | + : buckets_( 0 ) |
1526 | + , tailLink_( 0 ) |
1527 | + , bucketsSize_( 0 ) |
1528 | + , itemCount_( 0 ) |
1529 | +{ |
1530 | + reserve( other.itemCount_ ); |
1531 | + IteratorState it; |
1532 | + IteratorState itEnd; |
1533 | + other.makeBeginIterator( it ); |
1534 | + other.makeEndIterator( itEnd ); |
1535 | + for ( ; !equals(it,itEnd); increment(it) ) |
1536 | + { |
1537 | + bool isStatic; |
1538 | + const char *memberName = key( it, isStatic ); |
1539 | + const Value &aValue = value( it ); |
1540 | + resolveReference(memberName, isStatic) = aValue; |
1541 | + } |
1542 | +} |
1543 | + |
1544 | + |
1545 | +ValueInternalMap & |
1546 | +ValueInternalMap::operator =( const ValueInternalMap &other ) |
1547 | +{ |
1548 | + ValueInternalMap dummy( other ); |
1549 | + swap( dummy ); |
1550 | + return *this; |
1551 | +} |
1552 | + |
1553 | + |
1554 | +ValueInternalMap::~ValueInternalMap() |
1555 | +{ |
1556 | + if ( buckets_ ) |
1557 | + { |
1558 | + for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) |
1559 | + { |
1560 | + ValueInternalLink *link = buckets_[bucketIndex].next_; |
1561 | + while ( link ) |
1562 | + { |
1563 | + ValueInternalLink *linkToRelease = link; |
1564 | + link = link->next_; |
1565 | + mapAllocator()->releaseMapLink( linkToRelease ); |
1566 | + } |
1567 | + } |
1568 | + mapAllocator()->releaseMapBuckets( buckets_ ); |
1569 | + } |
1570 | +} |
1571 | + |
1572 | + |
1573 | +void |
1574 | +ValueInternalMap::swap( ValueInternalMap &other ) |
1575 | +{ |
1576 | + ValueInternalLink *tempBuckets = buckets_; |
1577 | + buckets_ = other.buckets_; |
1578 | + other.buckets_ = tempBuckets; |
1579 | + ValueInternalLink *tempTailLink = tailLink_; |
1580 | + tailLink_ = other.tailLink_; |
1581 | + other.tailLink_ = tempTailLink; |
1582 | + BucketIndex tempBucketsSize = bucketsSize_; |
1583 | + bucketsSize_ = other.bucketsSize_; |
1584 | + other.bucketsSize_ = tempBucketsSize; |
1585 | + BucketIndex tempItemCount = itemCount_; |
1586 | + itemCount_ = other.itemCount_; |
1587 | + other.itemCount_ = tempItemCount; |
1588 | +} |
1589 | + |
1590 | + |
1591 | +void |
1592 | +ValueInternalMap::clear() |
1593 | +{ |
1594 | + ValueInternalMap dummy; |
1595 | + swap( dummy ); |
1596 | +} |
1597 | + |
1598 | + |
1599 | +ValueInternalMap::BucketIndex |
1600 | +ValueInternalMap::size() const |
1601 | +{ |
1602 | + return itemCount_; |
1603 | +} |
1604 | + |
1605 | +bool |
1606 | +ValueInternalMap::reserveDelta( BucketIndex growth ) |
1607 | +{ |
1608 | + return reserve( itemCount_ + growth ); |
1609 | +} |
1610 | + |
1611 | +bool |
1612 | +ValueInternalMap::reserve( BucketIndex newItemCount ) |
1613 | +{ |
1614 | + if ( !buckets_ && newItemCount > 0 ) |
1615 | + { |
1616 | + buckets_ = mapAllocator()->allocateMapBuckets( 1 ); |
1617 | + bucketsSize_ = 1; |
1618 | + tailLink_ = &buckets_[0]; |
1619 | + } |
1620 | +// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; |
1621 | + return true; |
1622 | +} |
1623 | + |
1624 | + |
1625 | +const Value * |
1626 | +ValueInternalMap::find( const char *key ) const |
1627 | +{ |
1628 | + if ( !bucketsSize_ ) |
1629 | + return 0; |
1630 | + HashKey hashedKey = hash( key ); |
1631 | + BucketIndex bucketIndex = hashedKey % bucketsSize_; |
1632 | + for ( const ValueInternalLink *current = &buckets_[bucketIndex]; |
1633 | + current != 0; |
1634 | + current = current->next_ ) |
1635 | + { |
1636 | + for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) |
1637 | + { |
1638 | + if ( current->items_[index].isItemAvailable() ) |
1639 | + return 0; |
1640 | + if ( strcmp( key, current->keys_[index] ) == 0 ) |
1641 | + return ¤t->items_[index]; |
1642 | + } |
1643 | + } |
1644 | + return 0; |
1645 | +} |
1646 | + |
1647 | + |
1648 | +Value * |
1649 | +ValueInternalMap::find( const char *key ) |
1650 | +{ |
1651 | + const ValueInternalMap *constThis = this; |
1652 | + return const_cast<Value *>( constThis->find( key ) ); |
1653 | +} |
1654 | + |
1655 | + |
1656 | +Value & |
1657 | +ValueInternalMap::resolveReference( const char *key, |
1658 | + bool isStatic ) |
1659 | +{ |
1660 | + HashKey hashedKey = hash( key ); |
1661 | + if ( bucketsSize_ ) |
1662 | + { |
1663 | + BucketIndex bucketIndex = hashedKey % bucketsSize_; |
1664 | + ValueInternalLink **previous = 0; |
1665 | + BucketIndex index; |
1666 | + for ( ValueInternalLink *current = &buckets_[bucketIndex]; |
1667 | + current != 0; |
1668 | + previous = ¤t->next_, current = current->next_ ) |
1669 | + { |
1670 | + for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) |
1671 | + { |
1672 | + if ( current->items_[index].isItemAvailable() ) |
1673 | + return setNewItem( key, isStatic, current, index ); |
1674 | + if ( strcmp( key, current->keys_[index] ) == 0 ) |
1675 | + return current->items_[index]; |
1676 | + } |
1677 | + } |
1678 | + } |
1679 | + |
1680 | + reserveDelta( 1 ); |
1681 | + return unsafeAdd( key, isStatic, hashedKey ); |
1682 | +} |
1683 | + |
1684 | + |
1685 | +void |
1686 | +ValueInternalMap::remove( const char *key ) |
1687 | +{ |
1688 | + HashKey hashedKey = hash( key ); |
1689 | + if ( !bucketsSize_ ) |
1690 | + return; |
1691 | + BucketIndex bucketIndex = hashedKey % bucketsSize_; |
1692 | + for ( ValueInternalLink *link = &buckets_[bucketIndex]; |
1693 | + link != 0; |
1694 | + link = link->next_ ) |
1695 | + { |
1696 | + BucketIndex index; |
1697 | + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) |
1698 | + { |
1699 | + if ( link->items_[index].isItemAvailable() ) |
1700 | + return; |
1701 | + if ( strcmp( key, link->keys_[index] ) == 0 ) |
1702 | + { |
1703 | + doActualRemove( link, index, bucketIndex ); |
1704 | + return; |
1705 | + } |
1706 | + } |
1707 | + } |
1708 | +} |
1709 | + |
1710 | +void |
1711 | +ValueInternalMap::doActualRemove( ValueInternalLink *link, |
1712 | + BucketIndex index, |
1713 | + BucketIndex bucketIndex ) |
1714 | +{ |
1715 | + // find last item of the bucket and swap it with the 'removed' one. |
1716 | + // set removed items flags to 'available'. |
1717 | + // if last page only contains 'available' items, then desallocate it (it's empty) |
1718 | + ValueInternalLink *&lastLink = getLastLinkInBucket( index ); |
1719 | + BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 |
1720 | + for ( ; |
1721 | + lastItemIndex < ValueInternalLink::itemPerLink; |
1722 | + ++lastItemIndex ) // may be optimized with dicotomic search |
1723 | + { |
1724 | + if ( lastLink->items_[lastItemIndex].isItemAvailable() ) |
1725 | + break; |
1726 | + } |
1727 | + |
1728 | + BucketIndex lastUsedIndex = lastItemIndex - 1; |
1729 | + Value *valueToDelete = &link->items_[index]; |
1730 | + Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; |
1731 | + if ( valueToDelete != valueToPreserve ) |
1732 | + valueToDelete->swap( *valueToPreserve ); |
1733 | + if ( lastUsedIndex == 0 ) // page is now empty |
1734 | + { // remove it from bucket linked list and delete it. |
1735 | + ValueInternalLink *linkPreviousToLast = lastLink->previous_; |
1736 | + if ( linkPreviousToLast != 0 ) // can not deleted bucket link. |
1737 | + { |
1738 | + mapAllocator()->releaseMapLink( lastLink ); |
1739 | + linkPreviousToLast->next_ = 0; |
1740 | + lastLink = linkPreviousToLast; |
1741 | + } |
1742 | + } |
1743 | + else |
1744 | + { |
1745 | + Value dummy; |
1746 | + valueToPreserve->swap( dummy ); // restore deleted to default Value. |
1747 | + valueToPreserve->setItemUsed( false ); |
1748 | + } |
1749 | + --itemCount_; |
1750 | +} |
1751 | + |
1752 | + |
1753 | +ValueInternalLink *& |
1754 | +ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) |
1755 | +{ |
1756 | + if ( bucketIndex == bucketsSize_ - 1 ) |
1757 | + return tailLink_; |
1758 | + ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; |
1759 | + if ( !previous ) |
1760 | + previous = &buckets_[bucketIndex]; |
1761 | + return previous; |
1762 | +} |
1763 | + |
1764 | + |
1765 | +Value & |
1766 | +ValueInternalMap::setNewItem( const char *key, |
1767 | + bool isStatic, |
1768 | + ValueInternalLink *link, |
1769 | + BucketIndex index ) |
1770 | +{ |
1771 | + char *duplicatedKey = valueAllocator()->makeMemberName( key ); |
1772 | + ++itemCount_; |
1773 | + link->keys_[index] = duplicatedKey; |
1774 | + link->items_[index].setItemUsed(); |
1775 | + link->items_[index].setMemberNameIsStatic( isStatic ); |
1776 | + return link->items_[index]; // items already default constructed. |
1777 | +} |
1778 | + |
1779 | + |
1780 | +Value & |
1781 | +ValueInternalMap::unsafeAdd( const char *key, |
1782 | + bool isStatic, |
1783 | + HashKey hashedKey ) |
1784 | +{ |
1785 | + JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); |
1786 | + BucketIndex bucketIndex = hashedKey % bucketsSize_; |
1787 | + ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); |
1788 | + ValueInternalLink *link = previousLink; |
1789 | + BucketIndex index; |
1790 | + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) |
1791 | + { |
1792 | + if ( link->items_[index].isItemAvailable() ) |
1793 | + break; |
1794 | + } |
1795 | + if ( index == ValueInternalLink::itemPerLink ) // need to add a new page |
1796 | + { |
1797 | + ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); |
1798 | + index = 0; |
1799 | + link->next_ = newLink; |
1800 | + previousLink = newLink; |
1801 | + link = newLink; |
1802 | + } |
1803 | + return setNewItem( key, isStatic, link, index ); |
1804 | +} |
1805 | + |
1806 | + |
1807 | +ValueInternalMap::HashKey |
1808 | +ValueInternalMap::hash( const char *key ) const |
1809 | +{ |
1810 | + HashKey hash = 0; |
1811 | + while ( *key ) |
1812 | + hash += *key++ * 37; |
1813 | + return hash; |
1814 | +} |
1815 | + |
1816 | + |
1817 | +int |
1818 | +ValueInternalMap::compare( const ValueInternalMap &other ) const |
1819 | +{ |
1820 | + int sizeDiff( itemCount_ - other.itemCount_ ); |
1821 | + if ( sizeDiff != 0 ) |
1822 | + return sizeDiff; |
1823 | + // Strict order guaranty is required. Compare all keys FIRST, then compare values. |
1824 | + IteratorState it; |
1825 | + IteratorState itEnd; |
1826 | + makeBeginIterator( it ); |
1827 | + makeEndIterator( itEnd ); |
1828 | + for ( ; !equals(it,itEnd); increment(it) ) |
1829 | + { |
1830 | + if ( !other.find( key( it ) ) ) |
1831 | + return 1; |
1832 | + } |
1833 | + |
1834 | + // All keys are equals, let's compare values |
1835 | + makeBeginIterator( it ); |
1836 | + for ( ; !equals(it,itEnd); increment(it) ) |
1837 | + { |
1838 | + const Value *otherValue = other.find( key( it ) ); |
1839 | + int valueDiff = value(it).compare( *otherValue ); |
1840 | + if ( valueDiff != 0 ) |
1841 | + return valueDiff; |
1842 | + } |
1843 | + return 0; |
1844 | +} |
1845 | + |
1846 | + |
1847 | +void |
1848 | +ValueInternalMap::makeBeginIterator( IteratorState &it ) const |
1849 | +{ |
1850 | + it.map_ = const_cast<ValueInternalMap *>( this ); |
1851 | + it.bucketIndex_ = 0; |
1852 | + it.itemIndex_ = 0; |
1853 | + it.link_ = buckets_; |
1854 | +} |
1855 | + |
1856 | + |
1857 | +void |
1858 | +ValueInternalMap::makeEndIterator( IteratorState &it ) const |
1859 | +{ |
1860 | + it.map_ = const_cast<ValueInternalMap *>( this ); |
1861 | + it.bucketIndex_ = bucketsSize_; |
1862 | + it.itemIndex_ = 0; |
1863 | + it.link_ = 0; |
1864 | +} |
1865 | + |
1866 | + |
1867 | +bool |
1868 | +ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) |
1869 | +{ |
1870 | + return x.map_ == other.map_ |
1871 | + && x.bucketIndex_ == other.bucketIndex_ |
1872 | + && x.link_ == other.link_ |
1873 | + && x.itemIndex_ == other.itemIndex_; |
1874 | +} |
1875 | + |
1876 | + |
1877 | +void |
1878 | +ValueInternalMap::incrementBucket( IteratorState &iterator ) |
1879 | +{ |
1880 | + ++iterator.bucketIndex_; |
1881 | + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, |
1882 | + "ValueInternalMap::increment(): attempting to iterate beyond end." ); |
1883 | + if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) |
1884 | + iterator.link_ = 0; |
1885 | + else |
1886 | + iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); |
1887 | + iterator.itemIndex_ = 0; |
1888 | +} |
1889 | + |
1890 | + |
1891 | +void |
1892 | +ValueInternalMap::increment( IteratorState &iterator ) |
1893 | +{ |
1894 | + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); |
1895 | + ++iterator.itemIndex_; |
1896 | + if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) |
1897 | + { |
1898 | + JSON_ASSERT_MESSAGE( iterator.link_ != 0, |
1899 | + "ValueInternalMap::increment(): attempting to iterate beyond end." ); |
1900 | + iterator.link_ = iterator.link_->next_; |
1901 | + if ( iterator.link_ == 0 ) |
1902 | + incrementBucket( iterator ); |
1903 | + } |
1904 | + else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) |
1905 | + { |
1906 | + incrementBucket( iterator ); |
1907 | + } |
1908 | +} |
1909 | + |
1910 | + |
1911 | +void |
1912 | +ValueInternalMap::decrement( IteratorState &iterator ) |
1913 | +{ |
1914 | + if ( iterator.itemIndex_ == 0 ) |
1915 | + { |
1916 | + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); |
1917 | + if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) |
1918 | + { |
1919 | + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); |
1920 | + --(iterator.bucketIndex_); |
1921 | + } |
1922 | + iterator.link_ = iterator.link_->previous_; |
1923 | + iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; |
1924 | + } |
1925 | +} |
1926 | + |
1927 | + |
1928 | +const char * |
1929 | +ValueInternalMap::key( const IteratorState &iterator ) |
1930 | +{ |
1931 | + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); |
1932 | + return iterator.link_->keys_[iterator.itemIndex_]; |
1933 | +} |
1934 | + |
1935 | +const char * |
1936 | +ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) |
1937 | +{ |
1938 | + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); |
1939 | + isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); |
1940 | + return iterator.link_->keys_[iterator.itemIndex_]; |
1941 | +} |
1942 | + |
1943 | + |
1944 | +Value & |
1945 | +ValueInternalMap::value( const IteratorState &iterator ) |
1946 | +{ |
1947 | + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); |
1948 | + return iterator.link_->items_[iterator.itemIndex_]; |
1949 | +} |
1950 | + |
1951 | + |
1952 | +int |
1953 | +ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) |
1954 | +{ |
1955 | + int offset = 0; |
1956 | + IteratorState it = x; |
1957 | + while ( !equals( it, y ) ) |
1958 | + increment( it ); |
1959 | + return offset; |
1960 | +} |
1961 | |
1962 | === added file 'plugin/json_server/json/json_reader.cpp' |
1963 | --- plugin/json_server/json/json_reader.cpp 1970-01-01 00:00:00 +0000 |
1964 | +++ plugin/json_server/json/json_reader.cpp 2011-05-04 01:52:37 +0000 |
1965 | @@ -0,0 +1,921 @@ |
1966 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
1967 | + * |
1968 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
1969 | + * |
1970 | + * Copyright (C) 2011 Stewart Smith |
1971 | + * All rights reserved. |
1972 | + * |
1973 | + * Redistribution and use in source and binary forms, with or without |
1974 | + * modification, are permitted provided that the following conditions are |
1975 | + * met: |
1976 | + * |
1977 | + * * Redistributions of source code must retain the above copyright |
1978 | + * notice, this list of conditions and the following disclaimer. |
1979 | + * |
1980 | + * * Redistributions in binary form must reproduce the above |
1981 | + * copyright notice, this list of conditions and the following disclaimer |
1982 | + * in the documentation and/or other materials provided with the |
1983 | + * distribution. |
1984 | + * |
1985 | + * * The names of its contributors may not be used to endorse or |
1986 | + * promote products derived from this software without specific prior |
1987 | + * written permission. |
1988 | + * |
1989 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
1990 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
1991 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
1992 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
1993 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
1994 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
1995 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
1996 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
1997 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
1998 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
1999 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
2000 | + * |
2001 | + */ |
2002 | + |
2003 | +#include <config.h> |
2004 | + |
2005 | +#include <plugin/json_server/json/reader.h> |
2006 | +#include <plugin/json_server/json/value.h> |
2007 | + |
2008 | +#include <cassert> |
2009 | +#include <cstdio> |
2010 | +#include <cstring> |
2011 | +#include <iostream> |
2012 | +#include <stdexcept> |
2013 | +#include <utility> |
2014 | + |
2015 | +namespace Json { |
2016 | + |
2017 | +// Implementation of class Features |
2018 | +// //////////////////////////////// |
2019 | + |
2020 | +Features::Features() |
2021 | + : allowComments_( true ) |
2022 | + , strictRoot_( false ) |
2023 | +{ |
2024 | +} |
2025 | + |
2026 | + |
2027 | +Features |
2028 | +Features::all() |
2029 | +{ |
2030 | + return Features(); |
2031 | +} |
2032 | + |
2033 | + |
2034 | +Features |
2035 | +Features::strictMode() |
2036 | +{ |
2037 | + Features features; |
2038 | + features.allowComments_ = false; |
2039 | + features.strictRoot_ = true; |
2040 | + return features; |
2041 | +} |
2042 | + |
2043 | +// Implementation of class Reader |
2044 | +// //////////////////////////////// |
2045 | + |
2046 | + |
2047 | +static inline bool |
2048 | +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) |
2049 | +{ |
2050 | + return c == c1 || c == c2 || c == c3 || c == c4; |
2051 | +} |
2052 | + |
2053 | +static inline bool |
2054 | +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) |
2055 | +{ |
2056 | + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; |
2057 | +} |
2058 | + |
2059 | + |
2060 | +static bool |
2061 | +containsNewLine( Reader::Location begin, |
2062 | + Reader::Location end ) |
2063 | +{ |
2064 | + for ( ;begin < end; ++begin ) |
2065 | + if ( *begin == '\n' || *begin == '\r' ) |
2066 | + return true; |
2067 | + return false; |
2068 | +} |
2069 | + |
2070 | +static std::string codePointToUTF8(unsigned int cp) |
2071 | +{ |
2072 | + std::string result; |
2073 | + |
2074 | + // based on description from http://en.wikipedia.org/wiki/UTF-8 |
2075 | + |
2076 | + if (cp <= 0x7f) |
2077 | + { |
2078 | + result.resize(1); |
2079 | + result[0] = static_cast<char>(cp); |
2080 | + } |
2081 | + else if (cp <= 0x7FF) |
2082 | + { |
2083 | + result.resize(2); |
2084 | + result[1] = static_cast<char>(0x80 | (0x3f & cp)); |
2085 | + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); |
2086 | + } |
2087 | + else if (cp <= 0xFFFF) |
2088 | + { |
2089 | + result.resize(3); |
2090 | + result[2] = static_cast<char>(0x80 | (0x3f & cp)); |
2091 | + result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); |
2092 | + result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); |
2093 | + } |
2094 | + else if (cp <= 0x10FFFF) |
2095 | + { |
2096 | + result.resize(4); |
2097 | + result[3] = static_cast<char>(0x80 | (0x3f & cp)); |
2098 | + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); |
2099 | + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); |
2100 | + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); |
2101 | + } |
2102 | + |
2103 | + return result; |
2104 | +} |
2105 | + |
2106 | + |
2107 | +// Class Reader |
2108 | +// ////////////////////////////////////////////////////////////////// |
2109 | + |
2110 | +Reader::Reader() |
2111 | + : features_( Features::all() ) |
2112 | +{ |
2113 | +} |
2114 | + |
2115 | + |
2116 | +Reader::Reader( const Features &features ) |
2117 | + : features_( features ) |
2118 | +{ |
2119 | +} |
2120 | + |
2121 | + |
2122 | +bool |
2123 | +Reader::parse( const std::string &document, |
2124 | + Value &root, |
2125 | + bool collectComments ) |
2126 | +{ |
2127 | + document_ = document; |
2128 | + const char *begin = document_.c_str(); |
2129 | + const char *end = begin + document_.length(); |
2130 | + return parse( begin, end, root, collectComments ); |
2131 | +} |
2132 | + |
2133 | + |
2134 | +bool |
2135 | +Reader::parse( std::istream& sin, |
2136 | + Value &root, |
2137 | + bool collectComments ) |
2138 | +{ |
2139 | + //std::istream_iterator<char> begin(sin); |
2140 | + //std::istream_iterator<char> end; |
2141 | + // Those would allow streamed input from a file, if parse() were a |
2142 | + // template function. |
2143 | + |
2144 | + // Since std::string is reference-counted, this at least does not |
2145 | + // create an extra copy. |
2146 | + std::string doc; |
2147 | + std::getline(sin, doc, (char)EOF); |
2148 | + return parse( doc, root, collectComments ); |
2149 | +} |
2150 | + |
2151 | +bool |
2152 | +Reader::parse( const char *beginDoc, const char *endDoc, |
2153 | + Value &root, |
2154 | + bool collectComments ) |
2155 | +{ |
2156 | + if ( !features_.allowComments_ ) |
2157 | + { |
2158 | + collectComments = false; |
2159 | + } |
2160 | + |
2161 | + begin_ = beginDoc; |
2162 | + end_ = endDoc; |
2163 | + collectComments_ = collectComments; |
2164 | + current_ = begin_; |
2165 | + lastValueEnd_ = 0; |
2166 | + lastValue_ = 0; |
2167 | + commentsBefore_ = ""; |
2168 | + errors_.clear(); |
2169 | + while ( !nodes_.empty() ) |
2170 | + nodes_.pop(); |
2171 | + nodes_.push( &root ); |
2172 | + |
2173 | + bool successful = readValue(); |
2174 | + Token token; |
2175 | + skipCommentTokens( token ); |
2176 | + if ( collectComments_ && !commentsBefore_.empty() ) |
2177 | + root.setComment( commentsBefore_, commentAfter ); |
2178 | + if ( features_.strictRoot_ ) |
2179 | + { |
2180 | + if ( !root.isArray() && !root.isObject() ) |
2181 | + { |
2182 | + // Set error location to start of doc, ideally should be first token found in doc |
2183 | + token.type_ = tokenError; |
2184 | + token.start_ = beginDoc; |
2185 | + token.end_ = endDoc; |
2186 | + addError( "A valid JSON document must be either an array or an object value.", |
2187 | + token ); |
2188 | + return false; |
2189 | + } |
2190 | + } |
2191 | + return successful; |
2192 | +} |
2193 | + |
2194 | + |
2195 | +bool |
2196 | +Reader::readValue() |
2197 | +{ |
2198 | + Token token; |
2199 | + skipCommentTokens( token ); |
2200 | + bool successful = true; |
2201 | + |
2202 | + if ( collectComments_ && !commentsBefore_.empty() ) |
2203 | + { |
2204 | + currentValue().setComment( commentsBefore_, commentBefore ); |
2205 | + commentsBefore_ = ""; |
2206 | + } |
2207 | + |
2208 | + |
2209 | + switch ( token.type_ ) |
2210 | + { |
2211 | + case tokenObjectBegin: |
2212 | + successful = readObject( token ); |
2213 | + break; |
2214 | + case tokenArrayBegin: |
2215 | + successful = readArray( token ); |
2216 | + break; |
2217 | + case tokenNumber: |
2218 | + successful = decodeNumber( token ); |
2219 | + break; |
2220 | + case tokenString: |
2221 | + successful = decodeString( token ); |
2222 | + break; |
2223 | + case tokenTrue: |
2224 | + currentValue() = true; |
2225 | + break; |
2226 | + case tokenFalse: |
2227 | + currentValue() = false; |
2228 | + break; |
2229 | + case tokenNull: |
2230 | + currentValue() = Value(); |
2231 | + break; |
2232 | + default: |
2233 | + return addError( "Syntax error: value, object or array expected.", token ); |
2234 | + } |
2235 | + |
2236 | + if ( collectComments_ ) |
2237 | + { |
2238 | + lastValueEnd_ = current_; |
2239 | + lastValue_ = ¤tValue(); |
2240 | + } |
2241 | + |
2242 | + return successful; |
2243 | +} |
2244 | + |
2245 | + |
2246 | +void |
2247 | +Reader::skipCommentTokens( Token &token ) |
2248 | +{ |
2249 | + if ( features_.allowComments_ ) |
2250 | + { |
2251 | + do |
2252 | + { |
2253 | + readToken( token ); |
2254 | + } |
2255 | + while ( token.type_ == tokenComment ); |
2256 | + } |
2257 | + else |
2258 | + { |
2259 | + readToken( token ); |
2260 | + } |
2261 | +} |
2262 | + |
2263 | + |
2264 | +bool |
2265 | +Reader::expectToken( TokenType type, Token &token, const char *message ) |
2266 | +{ |
2267 | + readToken( token ); |
2268 | + if ( token.type_ != type ) |
2269 | + return addError( message, token ); |
2270 | + return true; |
2271 | +} |
2272 | + |
2273 | + |
2274 | +bool |
2275 | +Reader::readToken( Token &token ) |
2276 | +{ |
2277 | + skipSpaces(); |
2278 | + token.start_ = current_; |
2279 | + Char c = getNextChar(); |
2280 | + bool ok = true; |
2281 | + switch ( c ) |
2282 | + { |
2283 | + case '{': |
2284 | + token.type_ = tokenObjectBegin; |
2285 | + break; |
2286 | + case '}': |
2287 | + token.type_ = tokenObjectEnd; |
2288 | + break; |
2289 | + case '[': |
2290 | + token.type_ = tokenArrayBegin; |
2291 | + break; |
2292 | + case ']': |
2293 | + token.type_ = tokenArrayEnd; |
2294 | + break; |
2295 | + case '"': |
2296 | + token.type_ = tokenString; |
2297 | + ok = readString(); |
2298 | + break; |
2299 | + case '/': |
2300 | + token.type_ = tokenComment; |
2301 | + ok = readComment(); |
2302 | + break; |
2303 | + case '0': |
2304 | + case '1': |
2305 | + case '2': |
2306 | + case '3': |
2307 | + case '4': |
2308 | + case '5': |
2309 | + case '6': |
2310 | + case '7': |
2311 | + case '8': |
2312 | + case '9': |
2313 | + case '-': |
2314 | + token.type_ = tokenNumber; |
2315 | + readNumber(); |
2316 | + break; |
2317 | + case 't': |
2318 | + token.type_ = tokenTrue; |
2319 | + ok = match( "rue", 3 ); |
2320 | + break; |
2321 | + case 'f': |
2322 | + token.type_ = tokenFalse; |
2323 | + ok = match( "alse", 4 ); |
2324 | + break; |
2325 | + case 'n': |
2326 | + token.type_ = tokenNull; |
2327 | + ok = match( "ull", 3 ); |
2328 | + break; |
2329 | + case ',': |
2330 | + token.type_ = tokenArraySeparator; |
2331 | + break; |
2332 | + case ':': |
2333 | + token.type_ = tokenMemberSeparator; |
2334 | + break; |
2335 | + case 0: |
2336 | + token.type_ = tokenEndOfStream; |
2337 | + break; |
2338 | + default: |
2339 | + ok = false; |
2340 | + break; |
2341 | + } |
2342 | + if ( !ok ) |
2343 | + token.type_ = tokenError; |
2344 | + token.end_ = current_; |
2345 | + return true; |
2346 | +} |
2347 | + |
2348 | + |
2349 | +void |
2350 | +Reader::skipSpaces() |
2351 | +{ |
2352 | + while ( current_ != end_ ) |
2353 | + { |
2354 | + Char c = *current_; |
2355 | + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) |
2356 | + ++current_; |
2357 | + else |
2358 | + break; |
2359 | + } |
2360 | +} |
2361 | + |
2362 | + |
2363 | +bool |
2364 | +Reader::match( Location pattern, |
2365 | + int patternLength ) |
2366 | +{ |
2367 | + if ( end_ - current_ < patternLength ) |
2368 | + return false; |
2369 | + int index = patternLength; |
2370 | + while ( index-- ) |
2371 | + if ( current_[index] != pattern[index] ) |
2372 | + return false; |
2373 | + current_ += patternLength; |
2374 | + return true; |
2375 | +} |
2376 | + |
2377 | + |
2378 | +bool |
2379 | +Reader::readComment() |
2380 | +{ |
2381 | + Location commentBegin = current_ - 1; |
2382 | + Char c = getNextChar(); |
2383 | + bool successful = false; |
2384 | + if ( c == '*' ) |
2385 | + successful = readCStyleComment(); |
2386 | + else if ( c == '/' ) |
2387 | + successful = readCppStyleComment(); |
2388 | + if ( !successful ) |
2389 | + return false; |
2390 | + |
2391 | + if ( collectComments_ ) |
2392 | + { |
2393 | + CommentPlacement placement = commentBefore; |
2394 | + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) |
2395 | + { |
2396 | + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) |
2397 | + placement = commentAfterOnSameLine; |
2398 | + } |
2399 | + |
2400 | + addComment( commentBegin, current_, placement ); |
2401 | + } |
2402 | + return true; |
2403 | +} |
2404 | + |
2405 | + |
2406 | +void |
2407 | +Reader::addComment( Location begin, |
2408 | + Location end, |
2409 | + CommentPlacement placement ) |
2410 | +{ |
2411 | + assert( collectComments_ ); |
2412 | + if ( placement == commentAfterOnSameLine ) |
2413 | + { |
2414 | + assert( lastValue_ != 0 ); |
2415 | + lastValue_->setComment( std::string( begin, end ), placement ); |
2416 | + } |
2417 | + else |
2418 | + { |
2419 | + if ( !commentsBefore_.empty() ) |
2420 | + commentsBefore_ += "\n"; |
2421 | + commentsBefore_ += std::string( begin, end ); |
2422 | + } |
2423 | +} |
2424 | + |
2425 | + |
2426 | +bool |
2427 | +Reader::readCStyleComment() |
2428 | +{ |
2429 | + while ( current_ != end_ ) |
2430 | + { |
2431 | + Char c = getNextChar(); |
2432 | + if ( c == '*' && *current_ == '/' ) |
2433 | + break; |
2434 | + } |
2435 | + return getNextChar() == '/'; |
2436 | +} |
2437 | + |
2438 | + |
2439 | +bool |
2440 | +Reader::readCppStyleComment() |
2441 | +{ |
2442 | + while ( current_ != end_ ) |
2443 | + { |
2444 | + Char c = getNextChar(); |
2445 | + if ( c == '\r' || c == '\n' ) |
2446 | + break; |
2447 | + } |
2448 | + return true; |
2449 | +} |
2450 | + |
2451 | + |
2452 | +void |
2453 | +Reader::readNumber() |
2454 | +{ |
2455 | + while ( current_ != end_ ) |
2456 | + { |
2457 | + if ( !(*current_ >= '0' && *current_ <= '9') && |
2458 | + !in( *current_, '.', 'e', 'E', '+', '-' ) ) |
2459 | + break; |
2460 | + ++current_; |
2461 | + } |
2462 | +} |
2463 | + |
2464 | +bool |
2465 | +Reader::readString() |
2466 | +{ |
2467 | + Char c = 0; |
2468 | + while ( current_ != end_ ) |
2469 | + { |
2470 | + c = getNextChar(); |
2471 | + if ( c == '\\' ) |
2472 | + getNextChar(); |
2473 | + else if ( c == '"' ) |
2474 | + break; |
2475 | + } |
2476 | + return c == '"'; |
2477 | +} |
2478 | + |
2479 | + |
2480 | +bool |
2481 | +Reader::readObject( Token & ) |
2482 | +{ |
2483 | + Token tokenName; |
2484 | + std::string name; |
2485 | + currentValue() = Value( objectValue ); |
2486 | + while ( readToken( tokenName ) ) |
2487 | + { |
2488 | + bool initialTokenOk = true; |
2489 | + while ( tokenName.type_ == tokenComment && initialTokenOk ) |
2490 | + initialTokenOk = readToken( tokenName ); |
2491 | + if ( !initialTokenOk ) |
2492 | + break; |
2493 | + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object |
2494 | + return true; |
2495 | + if ( tokenName.type_ != tokenString ) |
2496 | + break; |
2497 | + |
2498 | + name = ""; |
2499 | + if ( !decodeString( tokenName, name ) ) |
2500 | + return recoverFromError( tokenObjectEnd ); |
2501 | + |
2502 | + Token colon; |
2503 | + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) |
2504 | + { |
2505 | + return addErrorAndRecover( "Missing ':' after object member name", |
2506 | + colon, |
2507 | + tokenObjectEnd ); |
2508 | + } |
2509 | + Value &value = currentValue()[ name ]; |
2510 | + nodes_.push( &value ); |
2511 | + bool ok = readValue(); |
2512 | + nodes_.pop(); |
2513 | + if ( !ok ) // error already set |
2514 | + return recoverFromError( tokenObjectEnd ); |
2515 | + |
2516 | + Token comma; |
2517 | + if ( !readToken( comma ) |
2518 | + || ( comma.type_ != tokenObjectEnd && |
2519 | + comma.type_ != tokenArraySeparator && |
2520 | + comma.type_ != tokenComment ) ) |
2521 | + { |
2522 | + return addErrorAndRecover( "Missing ',' or '}' in object declaration", |
2523 | + comma, |
2524 | + tokenObjectEnd ); |
2525 | + } |
2526 | + bool finalizeTokenOk = true; |
2527 | + while ( comma.type_ == tokenComment && |
2528 | + finalizeTokenOk ) |
2529 | + finalizeTokenOk = readToken( comma ); |
2530 | + if ( comma.type_ == tokenObjectEnd ) |
2531 | + return true; |
2532 | + } |
2533 | + return addErrorAndRecover( "Missing '}' or object member name", |
2534 | + tokenName, |
2535 | + tokenObjectEnd ); |
2536 | +} |
2537 | + |
2538 | + |
2539 | +bool |
2540 | +Reader::readArray( Token & ) |
2541 | +{ |
2542 | + currentValue() = Value( arrayValue ); |
2543 | + skipSpaces(); |
2544 | + if ( *current_ == ']' ) // empty array |
2545 | + { |
2546 | + Token endArray; |
2547 | + readToken( endArray ); |
2548 | + return true; |
2549 | + } |
2550 | + int index = 0; |
2551 | + while ( true ) |
2552 | + { |
2553 | + Value &value = currentValue()[ index++ ]; |
2554 | + nodes_.push( &value ); |
2555 | + bool ok = readValue(); |
2556 | + nodes_.pop(); |
2557 | + if ( !ok ) // error already set |
2558 | + return recoverFromError( tokenArrayEnd ); |
2559 | + |
2560 | + Token token; |
2561 | + // Accept Comment after last item in the array. |
2562 | + ok = readToken( token ); |
2563 | + while ( token.type_ == tokenComment && ok ) |
2564 | + { |
2565 | + ok = readToken( token ); |
2566 | + } |
2567 | + bool badTokenType = ( token.type_ == tokenArraySeparator && |
2568 | + token.type_ == tokenArrayEnd ); |
2569 | + if ( !ok || badTokenType ) |
2570 | + { |
2571 | + return addErrorAndRecover( "Missing ',' or ']' in array declaration", |
2572 | + token, |
2573 | + tokenArrayEnd ); |
2574 | + } |
2575 | + if ( token.type_ == tokenArrayEnd ) |
2576 | + break; |
2577 | + } |
2578 | + return true; |
2579 | +} |
2580 | + |
2581 | + |
2582 | +bool |
2583 | +Reader::decodeNumber( Token &token ) |
2584 | +{ |
2585 | + bool isDouble = false; |
2586 | + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) |
2587 | + { |
2588 | + isDouble = isDouble |
2589 | + || in( *inspect, '.', 'e', 'E', '+' ) |
2590 | + || ( *inspect == '-' && inspect != token.start_ ); |
2591 | + } |
2592 | + if ( isDouble ) |
2593 | + return decodeDouble( token ); |
2594 | + Location current = token.start_; |
2595 | + bool isNegative = *current == '-'; |
2596 | + if ( isNegative ) |
2597 | + ++current; |
2598 | + Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) |
2599 | + : Value::maxUInt) / 10; |
2600 | + Value::UInt value = 0; |
2601 | + while ( current < token.end_ ) |
2602 | + { |
2603 | + Char c = *current++; |
2604 | + if ( c < '0' || c > '9' ) |
2605 | + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); |
2606 | + if ( value >= threshold ) |
2607 | + return decodeDouble( token ); |
2608 | + value = value * 10 + Value::UInt(c - '0'); |
2609 | + } |
2610 | + if ( isNegative ) |
2611 | + currentValue() = -Value::Int( value ); |
2612 | + else if ( value <= Value::UInt(Value::maxInt) ) |
2613 | + currentValue() = Value::Int( value ); |
2614 | + else |
2615 | + currentValue() = value; |
2616 | + return true; |
2617 | +} |
2618 | + |
2619 | + |
2620 | +bool |
2621 | +Reader::decodeDouble( Token &token ) |
2622 | +{ |
2623 | + double value = 0; |
2624 | + const int bufferSize = 32; |
2625 | + int count; |
2626 | + int length = int(token.end_ - token.start_); |
2627 | + if ( length <= bufferSize ) |
2628 | + { |
2629 | + Char buffer[bufferSize]; |
2630 | + memcpy( buffer, token.start_, length ); |
2631 | + buffer[length] = 0; |
2632 | + count = sscanf( buffer, "%lf", &value ); |
2633 | + } |
2634 | + else |
2635 | + { |
2636 | + std::string buffer( token.start_, token.end_ ); |
2637 | + count = sscanf( buffer.c_str(), "%lf", &value ); |
2638 | + } |
2639 | + |
2640 | + if ( count != 1 ) |
2641 | + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); |
2642 | + currentValue() = value; |
2643 | + return true; |
2644 | +} |
2645 | + |
2646 | + |
2647 | +bool |
2648 | +Reader::decodeString( Token &token ) |
2649 | +{ |
2650 | + std::string decoded; |
2651 | + if ( !decodeString( token, decoded ) ) |
2652 | + return false; |
2653 | + currentValue() = decoded; |
2654 | + return true; |
2655 | +} |
2656 | + |
2657 | + |
2658 | +bool |
2659 | +Reader::decodeString( Token &token, std::string &decoded ) |
2660 | +{ |
2661 | + decoded.reserve( token.end_ - token.start_ - 2 ); |
2662 | + Location current = token.start_ + 1; // skip '"' |
2663 | + Location end = token.end_ - 1; // do not include '"' |
2664 | + while ( current != end ) |
2665 | + { |
2666 | + Char c = *current++; |
2667 | + if ( c == '"' ) |
2668 | + break; |
2669 | + else if ( c == '\\' ) |
2670 | + { |
2671 | + if ( current == end ) |
2672 | + return addError( "Empty escape sequence in string", token, current ); |
2673 | + Char escape = *current++; |
2674 | + switch ( escape ) |
2675 | + { |
2676 | + case '"': decoded += '"'; break; |
2677 | + case '/': decoded += '/'; break; |
2678 | + case '\\': decoded += '\\'; break; |
2679 | + case 'b': decoded += '\b'; break; |
2680 | + case 'f': decoded += '\f'; break; |
2681 | + case 'n': decoded += '\n'; break; |
2682 | + case 'r': decoded += '\r'; break; |
2683 | + case 't': decoded += '\t'; break; |
2684 | + case 'u': |
2685 | + { |
2686 | + unsigned int unicode; |
2687 | + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) |
2688 | + return false; |
2689 | + decoded += codePointToUTF8(unicode); |
2690 | + } |
2691 | + break; |
2692 | + default: |
2693 | + return addError( "Bad escape sequence in string", token, current ); |
2694 | + } |
2695 | + } |
2696 | + else |
2697 | + { |
2698 | + decoded += c; |
2699 | + } |
2700 | + } |
2701 | + return true; |
2702 | +} |
2703 | + |
2704 | +bool |
2705 | +Reader::decodeUnicodeCodePoint( Token &token, |
2706 | + Location ¤t, |
2707 | + Location end, |
2708 | + unsigned int &unicode ) |
2709 | +{ |
2710 | + |
2711 | + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) |
2712 | + return false; |
2713 | + if (unicode >= 0xD800 && unicode <= 0xDBFF) |
2714 | + { |
2715 | + // surrogate pairs |
2716 | + if (end - current < 6) |
2717 | + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); |
2718 | + unsigned int surrogatePair; |
2719 | + if (*(current++) == '\\' && *(current++)== 'u') |
2720 | + { |
2721 | + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) |
2722 | + { |
2723 | + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); |
2724 | + } |
2725 | + else |
2726 | + return false; |
2727 | + } |
2728 | + else |
2729 | + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); |
2730 | + } |
2731 | + return true; |
2732 | +} |
2733 | + |
2734 | +bool |
2735 | +Reader::decodeUnicodeEscapeSequence( Token &token, |
2736 | + Location ¤t, |
2737 | + Location end, |
2738 | + unsigned int &unicode ) |
2739 | +{ |
2740 | + if ( end - current < 4 ) |
2741 | + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); |
2742 | + unicode = 0; |
2743 | + for ( int index =0; index < 4; ++index ) |
2744 | + { |
2745 | + Char c = *current++; |
2746 | + unicode *= 16; |
2747 | + if ( c >= '0' && c <= '9' ) |
2748 | + unicode += c - '0'; |
2749 | + else if ( c >= 'a' && c <= 'f' ) |
2750 | + unicode += c - 'a' + 10; |
2751 | + else if ( c >= 'A' && c <= 'F' ) |
2752 | + unicode += c - 'A' + 10; |
2753 | + else |
2754 | + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); |
2755 | + } |
2756 | + return true; |
2757 | +} |
2758 | + |
2759 | + |
2760 | +bool |
2761 | +Reader::addError( const std::string &message, |
2762 | + Token &token, |
2763 | + Location extra ) |
2764 | +{ |
2765 | + ErrorInfo info; |
2766 | + info.token_ = token; |
2767 | + info.message_ = message; |
2768 | + info.extra_ = extra; |
2769 | + errors_.push_back( info ); |
2770 | + return false; |
2771 | +} |
2772 | + |
2773 | + |
2774 | +bool |
2775 | +Reader::recoverFromError( TokenType skipUntilToken ) |
2776 | +{ |
2777 | + int errorCount = int(errors_.size()); |
2778 | + Token skip; |
2779 | + while ( true ) |
2780 | + { |
2781 | + if ( !readToken(skip) ) |
2782 | + errors_.resize( errorCount ); // discard errors caused by recovery |
2783 | + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) |
2784 | + break; |
2785 | + } |
2786 | + errors_.resize( errorCount ); |
2787 | + return false; |
2788 | +} |
2789 | + |
2790 | + |
2791 | +bool |
2792 | +Reader::addErrorAndRecover( const std::string &message, |
2793 | + Token &token, |
2794 | + TokenType skipUntilToken ) |
2795 | +{ |
2796 | + addError( message, token ); |
2797 | + return recoverFromError( skipUntilToken ); |
2798 | +} |
2799 | + |
2800 | + |
2801 | +Value & |
2802 | +Reader::currentValue() |
2803 | +{ |
2804 | + return *(nodes_.top()); |
2805 | +} |
2806 | + |
2807 | + |
2808 | +Reader::Char |
2809 | +Reader::getNextChar() |
2810 | +{ |
2811 | + if ( current_ == end_ ) |
2812 | + return 0; |
2813 | + return *current_++; |
2814 | +} |
2815 | + |
2816 | + |
2817 | +void |
2818 | +Reader::getLocationLineAndColumn( Location location, |
2819 | + int &line, |
2820 | + int &column ) const |
2821 | +{ |
2822 | + Location current = begin_; |
2823 | + Location lastLineStart = current; |
2824 | + line = 0; |
2825 | + while ( current < location && current != end_ ) |
2826 | + { |
2827 | + Char c = *current++; |
2828 | + if ( c == '\r' ) |
2829 | + { |
2830 | + if ( *current == '\n' ) |
2831 | + ++current; |
2832 | + lastLineStart = current; |
2833 | + ++line; |
2834 | + } |
2835 | + else if ( c == '\n' ) |
2836 | + { |
2837 | + lastLineStart = current; |
2838 | + ++line; |
2839 | + } |
2840 | + } |
2841 | + // column & line start at 1 |
2842 | + column = int(location - lastLineStart) + 1; |
2843 | + ++line; |
2844 | +} |
2845 | + |
2846 | + |
2847 | +std::string |
2848 | +Reader::getLocationLineAndColumn( Location location ) const |
2849 | +{ |
2850 | + int line, column; |
2851 | + getLocationLineAndColumn( location, line, column ); |
2852 | + char buffer[18+16+16+1]; |
2853 | + sprintf( buffer, "Line %d, Column %d", line, column ); |
2854 | + return buffer; |
2855 | +} |
2856 | + |
2857 | + |
2858 | +std::string |
2859 | +Reader::getFormatedErrorMessages() const |
2860 | +{ |
2861 | + std::string formattedMessage; |
2862 | + for ( Errors::const_iterator itError = errors_.begin(); |
2863 | + itError != errors_.end(); |
2864 | + ++itError ) |
2865 | + { |
2866 | + const ErrorInfo &error = *itError; |
2867 | + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; |
2868 | + formattedMessage += " " + error.message_ + "\n"; |
2869 | + if ( error.extra_ ) |
2870 | + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; |
2871 | + } |
2872 | + return formattedMessage; |
2873 | +} |
2874 | + |
2875 | + |
2876 | +std::istream& operator>>( std::istream &sin, Value &root ) |
2877 | +{ |
2878 | + Json::Reader reader; |
2879 | + bool ok = reader.parse(sin, root, true); |
2880 | + //JSON_ASSERT( ok ); |
2881 | + if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); |
2882 | + return sin; |
2883 | +} |
2884 | + |
2885 | + |
2886 | +} // namespace Json |
2887 | |
2888 | === added file 'plugin/json_server/json/json_value.cpp' |
2889 | --- plugin/json_server/json/json_value.cpp 1970-01-01 00:00:00 +0000 |
2890 | +++ plugin/json_server/json/json_value.cpp 2011-05-04 01:52:37 +0000 |
2891 | @@ -0,0 +1,1759 @@ |
2892 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
2893 | + * |
2894 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
2895 | + * |
2896 | + * Copyright (C) 2011 Stewart Smith |
2897 | + * All rights reserved. |
2898 | + * |
2899 | + * Redistribution and use in source and binary forms, with or without |
2900 | + * modification, are permitted provided that the following conditions are |
2901 | + * met: |
2902 | + * |
2903 | + * * Redistributions of source code must retain the above copyright |
2904 | + * notice, this list of conditions and the following disclaimer. |
2905 | + * |
2906 | + * * Redistributions in binary form must reproduce the above |
2907 | + * copyright notice, this list of conditions and the following disclaimer |
2908 | + * in the documentation and/or other materials provided with the |
2909 | + * distribution. |
2910 | + * |
2911 | + * * The names of its contributors may not be used to endorse or |
2912 | + * promote products derived from this software without specific prior |
2913 | + * written permission. |
2914 | + * |
2915 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
2916 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
2917 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
2918 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
2919 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
2920 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
2921 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
2922 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
2923 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
2924 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
2925 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
2926 | + * |
2927 | + */ |
2928 | + |
2929 | +#include <config.h> |
2930 | + |
2931 | +#include <plugin/json_server/json/value.h> |
2932 | +#include <plugin/json_server/json/writer.h> |
2933 | + |
2934 | +#include <cassert> |
2935 | +#include <cstring> |
2936 | +#include <iostream> |
2937 | +#include <stdexcept> |
2938 | +#include <utility> |
2939 | + |
2940 | +#ifdef JSON_USE_CPPTL |
2941 | +# include <cpptl/conststring.h> |
2942 | +#endif |
2943 | +#include <cstddef> // size_t |
2944 | +#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
2945 | +# include "json_batchallocator.h" |
2946 | +#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR |
2947 | + |
2948 | +#define JSON_ASSERT_UNREACHABLE assert( false ) |
2949 | +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw |
2950 | +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); |
2951 | + |
2952 | +namespace Json { |
2953 | + |
2954 | +const Value Value::null; |
2955 | +const Int Value::minInt = Int( ~(UInt(-1)/2) ); |
2956 | +const Int Value::maxInt = Int( UInt(-1)/2 ); |
2957 | +const UInt Value::maxUInt = UInt(-1); |
2958 | + |
2959 | +// A "safe" implementation of strdup. Allow null pointer to be passed. |
2960 | +// Also avoid warning on msvc80. |
2961 | +// |
2962 | +//inline char *safeStringDup( const char *czstring ) |
2963 | +//{ |
2964 | +// if ( czstring ) |
2965 | +// { |
2966 | +// const size_t length = (unsigned int)( strlen(czstring) + 1 ); |
2967 | +// char *newString = static_cast<char *>( malloc( length ) ); |
2968 | +// memcpy( newString, czstring, length ); |
2969 | +// return newString; |
2970 | +// } |
2971 | +// return 0; |
2972 | +//} |
2973 | +// |
2974 | +//inline char *safeStringDup( const std::string &str ) |
2975 | +//{ |
2976 | +// if ( !str.empty() ) |
2977 | +// { |
2978 | +// const size_t length = str.length(); |
2979 | +// char *newString = static_cast<char *>( malloc( length + 1 ) ); |
2980 | +// memcpy( newString, str.c_str(), length ); |
2981 | +// newString[length] = 0; |
2982 | +// return newString; |
2983 | +// } |
2984 | +// return 0; |
2985 | +//} |
2986 | + |
2987 | +ValueAllocator::~ValueAllocator() |
2988 | +{ |
2989 | +} |
2990 | + |
2991 | +class DefaultValueAllocator : public ValueAllocator |
2992 | +{ |
2993 | +public: |
2994 | + virtual ~DefaultValueAllocator() |
2995 | + { |
2996 | + } |
2997 | + |
2998 | + virtual char *makeMemberName( const char *memberName ) |
2999 | + { |
3000 | + return duplicateStringValue( memberName ); |
3001 | + } |
3002 | + |
3003 | + virtual void releaseMemberName( char *memberName ) |
3004 | + { |
3005 | + releaseStringValue( memberName ); |
3006 | + } |
3007 | + |
3008 | + virtual char *duplicateStringValue( const char *value, |
3009 | + unsigned int length = unknown ) |
3010 | + { |
3011 | + //@todo invesgate this old optimization |
3012 | + //if ( !value || value[0] == 0 ) |
3013 | + // return 0; |
3014 | + |
3015 | + if ( length == unknown ) |
3016 | + length = (unsigned int)strlen(value); |
3017 | + char *newString = static_cast<char *>( malloc( length + 1 ) ); |
3018 | + memcpy( newString, value, length ); |
3019 | + newString[length] = 0; |
3020 | + return newString; |
3021 | + } |
3022 | + |
3023 | + virtual void releaseStringValue( char *value ) |
3024 | + { |
3025 | + if ( value ) |
3026 | + free( value ); |
3027 | + } |
3028 | +}; |
3029 | + |
3030 | +static ValueAllocator *&valueAllocator() |
3031 | +{ |
3032 | + static DefaultValueAllocator defaultAllocator; |
3033 | + static ValueAllocator *valueAllocator = &defaultAllocator; |
3034 | + return valueAllocator; |
3035 | +} |
3036 | + |
3037 | +static struct DummyValueAllocatorInitializer { |
3038 | + DummyValueAllocatorInitializer() |
3039 | + { |
3040 | + valueAllocator(); // ensure valueAllocator() statics are initialized before main(). |
3041 | + } |
3042 | +} dummyValueAllocatorInitializer; |
3043 | + |
3044 | + |
3045 | + |
3046 | +// ////////////////////////////////////////////////////////////////// |
3047 | +// ////////////////////////////////////////////////////////////////// |
3048 | +// ////////////////////////////////////////////////////////////////// |
3049 | +// ValueInternals... |
3050 | +// ////////////////////////////////////////////////////////////////// |
3051 | +// ////////////////////////////////////////////////////////////////// |
3052 | +// ////////////////////////////////////////////////////////////////// |
3053 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
3054 | +# include "json_internalarray.inl" |
3055 | +# include "json_internalmap.inl" |
3056 | +#endif // JSON_VALUE_USE_INTERNAL_MAP |
3057 | + |
3058 | +# include "json_valueiterator.inl" |
3059 | + |
3060 | + |
3061 | +// ////////////////////////////////////////////////////////////////// |
3062 | +// ////////////////////////////////////////////////////////////////// |
3063 | +// ////////////////////////////////////////////////////////////////// |
3064 | +// class Value::CommentInfo |
3065 | +// ////////////////////////////////////////////////////////////////// |
3066 | +// ////////////////////////////////////////////////////////////////// |
3067 | +// ////////////////////////////////////////////////////////////////// |
3068 | + |
3069 | + |
3070 | +Value::CommentInfo::CommentInfo() |
3071 | + : comment_( 0 ) |
3072 | +{ |
3073 | +} |
3074 | + |
3075 | +Value::CommentInfo::~CommentInfo() |
3076 | +{ |
3077 | + if ( comment_ ) |
3078 | + valueAllocator()->releaseStringValue( comment_ ); |
3079 | +} |
3080 | + |
3081 | + |
3082 | +void |
3083 | +Value::CommentInfo::setComment( const char *text ) |
3084 | +{ |
3085 | + if ( comment_ ) |
3086 | + valueAllocator()->releaseStringValue( comment_ ); |
3087 | + JSON_ASSERT( text ); |
3088 | + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); |
3089 | + // It seems that /**/ style comments are acceptable as well. |
3090 | + comment_ = valueAllocator()->duplicateStringValue( text ); |
3091 | +} |
3092 | + |
3093 | + |
3094 | +// ////////////////////////////////////////////////////////////////// |
3095 | +// ////////////////////////////////////////////////////////////////// |
3096 | +// ////////////////////////////////////////////////////////////////// |
3097 | +// class Value::CZString |
3098 | +// ////////////////////////////////////////////////////////////////// |
3099 | +// ////////////////////////////////////////////////////////////////// |
3100 | +// ////////////////////////////////////////////////////////////////// |
3101 | +# ifndef JSON_VALUE_USE_INTERNAL_MAP |
3102 | + |
3103 | +// Notes: index_ indicates if the string was allocated when |
3104 | +// a string is stored. |
3105 | + |
3106 | +Value::CZString::CZString( int index_arg ) |
3107 | + : cstr_( 0 ) |
3108 | + , index_( index_arg ) |
3109 | +{ |
3110 | +} |
3111 | + |
3112 | +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) |
3113 | + : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) |
3114 | + : cstr ) |
3115 | + , index_( allocate ) |
3116 | +{ |
3117 | +} |
3118 | + |
3119 | +Value::CZString::CZString( const CZString &other ) |
3120 | +: cstr_( other.index_ != noDuplication && other.cstr_ != 0 |
3121 | + ? valueAllocator()->makeMemberName( other.cstr_ ) |
3122 | + : other.cstr_ ) |
3123 | + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) |
3124 | + : other.index_ ) |
3125 | +{ |
3126 | +} |
3127 | + |
3128 | +Value::CZString::~CZString() |
3129 | +{ |
3130 | + if ( cstr_ && index_ == duplicate ) |
3131 | + valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) ); |
3132 | +} |
3133 | + |
3134 | +void |
3135 | +Value::CZString::swap( CZString &other ) |
3136 | +{ |
3137 | + std::swap( cstr_, other.cstr_ ); |
3138 | + std::swap( index_, other.index_ ); |
3139 | +} |
3140 | + |
3141 | +Value::CZString & |
3142 | +Value::CZString::operator =( const CZString &other ) |
3143 | +{ |
3144 | + CZString temp( other ); |
3145 | + swap( temp ); |
3146 | + return *this; |
3147 | +} |
3148 | + |
3149 | +bool |
3150 | +Value::CZString::operator<( const CZString &other ) const |
3151 | +{ |
3152 | + if ( cstr_ ) |
3153 | + return strcmp( cstr_, other.cstr_ ) < 0; |
3154 | + return index_ < other.index_; |
3155 | +} |
3156 | + |
3157 | +bool |
3158 | +Value::CZString::operator==( const CZString &other ) const |
3159 | +{ |
3160 | + if ( cstr_ ) |
3161 | + return strcmp( cstr_, other.cstr_ ) == 0; |
3162 | + return index_ == other.index_; |
3163 | +} |
3164 | + |
3165 | + |
3166 | +int |
3167 | +Value::CZString::index() const |
3168 | +{ |
3169 | + return index_; |
3170 | +} |
3171 | + |
3172 | + |
3173 | +const char * |
3174 | +Value::CZString::c_str() const |
3175 | +{ |
3176 | + return cstr_; |
3177 | +} |
3178 | + |
3179 | +bool |
3180 | +Value::CZString::isStaticString() const |
3181 | +{ |
3182 | + return index_ == noDuplication; |
3183 | +} |
3184 | + |
3185 | +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP |
3186 | + |
3187 | + |
3188 | +// ////////////////////////////////////////////////////////////////// |
3189 | +// ////////////////////////////////////////////////////////////////// |
3190 | +// ////////////////////////////////////////////////////////////////// |
3191 | +// class Value::Value |
3192 | +// ////////////////////////////////////////////////////////////////// |
3193 | +// ////////////////////////////////////////////////////////////////// |
3194 | +// ////////////////////////////////////////////////////////////////// |
3195 | + |
3196 | +/*! \internal Default constructor initialization must be equivalent to: |
3197 | + * memset( this, 0, sizeof(Value) ) |
3198 | + * This optimization is used in ValueInternalMap fast allocator. |
3199 | + */ |
3200 | +Value::Value( ValueType type_arg ) |
3201 | + : type_( type_arg ) |
3202 | + , allocated_( 0 ) |
3203 | + , comments_( 0 ) |
3204 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3205 | + , itemIsUsed_( 0 ) |
3206 | +#endif |
3207 | +{ |
3208 | + switch ( type_arg ) |
3209 | + { |
3210 | + case nullValue: |
3211 | + break; |
3212 | + case intValue: |
3213 | + case uintValue: |
3214 | + value_.int_ = 0; |
3215 | + break; |
3216 | + case realValue: |
3217 | + value_.real_ = 0.0; |
3218 | + break; |
3219 | + case stringValue: |
3220 | + value_.string_ = 0; |
3221 | + break; |
3222 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3223 | + case arrayValue: |
3224 | + case objectValue: |
3225 | + value_.map_ = new ObjectValues(); |
3226 | + break; |
3227 | +#else |
3228 | + case arrayValue: |
3229 | + value_.array_ = arrayAllocator()->newArray(); |
3230 | + break; |
3231 | + case objectValue: |
3232 | + value_.map_ = mapAllocator()->newMap(); |
3233 | + break; |
3234 | +#endif |
3235 | + case booleanValue: |
3236 | + value_.bool_ = false; |
3237 | + break; |
3238 | + default: |
3239 | + JSON_ASSERT_UNREACHABLE; |
3240 | + } |
3241 | +} |
3242 | + |
3243 | + |
3244 | +Value::Value( Int value ) |
3245 | + : type_( intValue ) |
3246 | + , comments_( 0 ) |
3247 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3248 | + , itemIsUsed_( 0 ) |
3249 | +#endif |
3250 | +{ |
3251 | + value_.int_ = value; |
3252 | +} |
3253 | + |
3254 | + |
3255 | +Value::Value( UInt value ) |
3256 | + : type_( uintValue ) |
3257 | + , comments_( 0 ) |
3258 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3259 | + , itemIsUsed_( 0 ) |
3260 | +#endif |
3261 | +{ |
3262 | + value_.uint_ = value; |
3263 | +} |
3264 | + |
3265 | +Value::Value( double value ) |
3266 | + : type_( realValue ) |
3267 | + , comments_( 0 ) |
3268 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3269 | + , itemIsUsed_( 0 ) |
3270 | +#endif |
3271 | +{ |
3272 | + value_.real_ = value; |
3273 | +} |
3274 | + |
3275 | +Value::Value( const char *value ) |
3276 | + : type_( stringValue ) |
3277 | + , allocated_( true ) |
3278 | + , comments_( NULL ) |
3279 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3280 | + , itemIsUsed_( 0 ) |
3281 | +#endif |
3282 | +{ |
3283 | + value_.string_ = valueAllocator()->duplicateStringValue( value ); |
3284 | +} |
3285 | + |
3286 | + |
3287 | +Value::Value( const char *beginValue, |
3288 | + const char *endValue ) |
3289 | + : type_( stringValue ) |
3290 | + , allocated_( true ) |
3291 | + , comments_( NULL ) |
3292 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3293 | + , itemIsUsed_( 0 ) |
3294 | +#endif |
3295 | +{ |
3296 | + value_.string_ = valueAllocator()->duplicateStringValue( beginValue, |
3297 | + UInt(endValue - beginValue) ); |
3298 | +} |
3299 | + |
3300 | + |
3301 | +Value::Value( const std::string &value ) |
3302 | + : type_( stringValue ) |
3303 | + , allocated_( true ) |
3304 | + , comments_( 0 ) |
3305 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3306 | + , itemIsUsed_( 0 ) |
3307 | +#endif |
3308 | +{ |
3309 | + value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), |
3310 | + (unsigned int)value.length() ); |
3311 | + |
3312 | +} |
3313 | + |
3314 | +Value::Value( const StaticString &value ) |
3315 | + : type_( stringValue ) |
3316 | + , allocated_( false ) |
3317 | + , comments_( 0 ) |
3318 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3319 | + , itemIsUsed_( 0 ) |
3320 | +#endif |
3321 | +{ |
3322 | + value_.string_ = const_cast<char *>( value.c_str() ); |
3323 | +} |
3324 | + |
3325 | + |
3326 | +# ifdef JSON_USE_CPPTL |
3327 | +Value::Value( const CppTL::ConstString &value ) |
3328 | + : type_( stringValue ) |
3329 | + , allocated_( true ) |
3330 | + , comments_( 0 ) |
3331 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3332 | + , itemIsUsed_( 0 ) |
3333 | +#endif |
3334 | +{ |
3335 | + value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); |
3336 | +} |
3337 | +# endif |
3338 | + |
3339 | +Value::Value( bool value ) |
3340 | + : type_( booleanValue ) |
3341 | + , comments_( 0 ) |
3342 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3343 | + , itemIsUsed_( 0 ) |
3344 | +#endif |
3345 | +{ |
3346 | + value_.bool_ = value; |
3347 | +} |
3348 | + |
3349 | + |
3350 | +Value::Value( const Value &other ) |
3351 | + : type_( other.type_ ) |
3352 | + , comments_( 0 ) |
3353 | +# ifdef JSON_VALUE_USE_INTERNAL_MAP |
3354 | + , itemIsUsed_( 0 ) |
3355 | +#endif |
3356 | +{ |
3357 | + switch ( type_ ) |
3358 | + { |
3359 | + case nullValue: |
3360 | + case intValue: |
3361 | + case uintValue: |
3362 | + case realValue: |
3363 | + case booleanValue: |
3364 | + value_ = other.value_; |
3365 | + break; |
3366 | + case stringValue: |
3367 | + if ( other.value_.string_ ) |
3368 | + { |
3369 | + value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); |
3370 | + allocated_ = true; |
3371 | + } |
3372 | + else |
3373 | + value_.string_ = 0; |
3374 | + break; |
3375 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3376 | + case arrayValue: |
3377 | + case objectValue: |
3378 | + value_.map_ = new ObjectValues( *other.value_.map_ ); |
3379 | + break; |
3380 | +#else |
3381 | + case arrayValue: |
3382 | + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); |
3383 | + break; |
3384 | + case objectValue: |
3385 | + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); |
3386 | + break; |
3387 | +#endif |
3388 | + default: |
3389 | + JSON_ASSERT_UNREACHABLE; |
3390 | + } |
3391 | + if ( other.comments_ ) |
3392 | + { |
3393 | + comments_ = new CommentInfo[numberOfCommentPlacement]; |
3394 | + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) |
3395 | + { |
3396 | + const CommentInfo &otherComment = other.comments_[comment]; |
3397 | + if ( otherComment.comment_ ) |
3398 | + comments_[comment].setComment( otherComment.comment_ ); |
3399 | + } |
3400 | + } |
3401 | +} |
3402 | + |
3403 | + |
3404 | +Value::~Value() |
3405 | +{ |
3406 | + switch ( type_ ) |
3407 | + { |
3408 | + case nullValue: |
3409 | + case intValue: |
3410 | + case uintValue: |
3411 | + case realValue: |
3412 | + case booleanValue: |
3413 | + break; |
3414 | + case stringValue: |
3415 | + if ( allocated_ ) |
3416 | + valueAllocator()->releaseStringValue( value_.string_ ); |
3417 | + break; |
3418 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3419 | + case arrayValue: |
3420 | + case objectValue: |
3421 | + delete value_.map_; |
3422 | + break; |
3423 | +#else |
3424 | + case arrayValue: |
3425 | + arrayAllocator()->destructArray( value_.array_ ); |
3426 | + break; |
3427 | + case objectValue: |
3428 | + mapAllocator()->destructMap( value_.map_ ); |
3429 | + break; |
3430 | +#endif |
3431 | + default: |
3432 | + JSON_ASSERT_UNREACHABLE; |
3433 | + } |
3434 | + |
3435 | + if ( comments_ ) |
3436 | + delete[] comments_; |
3437 | +} |
3438 | + |
3439 | +Value & |
3440 | +Value::operator=( const Value &other ) |
3441 | +{ |
3442 | + Value temp( other ); |
3443 | + swap( temp ); |
3444 | + return *this; |
3445 | +} |
3446 | + |
3447 | +void |
3448 | +Value::swap( Value &other ) |
3449 | +{ |
3450 | + ValueType temp = type_; |
3451 | + type_ = other.type_; |
3452 | + other.type_ = temp; |
3453 | + std::swap( value_, other.value_ ); |
3454 | + int temp2 = allocated_; |
3455 | + allocated_ = other.allocated_; |
3456 | + other.allocated_ = temp2; |
3457 | +} |
3458 | + |
3459 | +ValueType |
3460 | +Value::type() const |
3461 | +{ |
3462 | + return type_; |
3463 | +} |
3464 | + |
3465 | + |
3466 | +int |
3467 | +Value::compare( const Value & ) |
3468 | +{ |
3469 | + /* |
3470 | + int typeDelta = other.type_ - type_; |
3471 | + switch ( type_ ) |
3472 | + { |
3473 | + case nullValue: |
3474 | + |
3475 | + return other.type_ == type_; |
3476 | + case intValue: |
3477 | + if ( other.type_.isNumeric() |
3478 | + case uintValue: |
3479 | + case realValue: |
3480 | + case booleanValue: |
3481 | + break; |
3482 | + case stringValue, |
3483 | + break; |
3484 | + case arrayValue: |
3485 | + delete value_.array_; |
3486 | + break; |
3487 | + case objectValue: |
3488 | + delete value_.map_; |
3489 | + default: |
3490 | + JSON_ASSERT_UNREACHABLE; |
3491 | + } |
3492 | + */ |
3493 | + return 0; // unreachable |
3494 | +} |
3495 | + |
3496 | +bool |
3497 | +Value::operator <( const Value &other ) const |
3498 | +{ |
3499 | + int typeDelta = type_ - other.type_; |
3500 | + if ( typeDelta ) |
3501 | + return typeDelta < 0 ? true : false; |
3502 | + switch ( type_ ) |
3503 | + { |
3504 | + case nullValue: |
3505 | + return false; |
3506 | + case intValue: |
3507 | + return value_.int_ < other.value_.int_; |
3508 | + case uintValue: |
3509 | + return value_.uint_ < other.value_.uint_; |
3510 | + case realValue: |
3511 | + return value_.real_ < other.value_.real_; |
3512 | + case booleanValue: |
3513 | + return value_.bool_ < other.value_.bool_; |
3514 | + case stringValue: |
3515 | + return ( value_.string_ == 0 && other.value_.string_ ) |
3516 | + || ( other.value_.string_ |
3517 | + && value_.string_ |
3518 | + && strcmp( value_.string_, other.value_.string_ ) < 0 ); |
3519 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3520 | + case arrayValue: |
3521 | + case objectValue: |
3522 | + { |
3523 | + int delta = int( value_.map_->size() - other.value_.map_->size() ); |
3524 | + if ( delta ) |
3525 | + return delta < 0; |
3526 | + return (*value_.map_) < (*other.value_.map_); |
3527 | + } |
3528 | +#else |
3529 | + case arrayValue: |
3530 | + return value_.array_->compare( *(other.value_.array_) ) < 0; |
3531 | + case objectValue: |
3532 | + return value_.map_->compare( *(other.value_.map_) ) < 0; |
3533 | +#endif |
3534 | + default: |
3535 | + JSON_ASSERT_UNREACHABLE; |
3536 | + } |
3537 | + return 0; // unreachable |
3538 | +} |
3539 | + |
3540 | +bool |
3541 | +Value::operator <=( const Value &other ) const |
3542 | +{ |
3543 | + return !(other > *this); |
3544 | +} |
3545 | + |
3546 | +bool |
3547 | +Value::operator >=( const Value &other ) const |
3548 | +{ |
3549 | + return !(*this < other); |
3550 | +} |
3551 | + |
3552 | +bool |
3553 | +Value::operator >( const Value &other ) const |
3554 | +{ |
3555 | + return other < *this; |
3556 | +} |
3557 | + |
3558 | +bool |
3559 | +Value::operator ==( const Value &other ) const |
3560 | +{ |
3561 | + //if ( type_ != other.type_ ) |
3562 | + // GCC 2.95.3 says: |
3563 | + // attempt to take address of bit-field structure member `Json::Value::type_' |
3564 | + // Beats me, but a temp solves the problem. |
3565 | + int temp = other.type_; |
3566 | + if ( type_ != temp ) |
3567 | + return false; |
3568 | + switch ( type_ ) |
3569 | + { |
3570 | + case nullValue: |
3571 | + return true; |
3572 | + case intValue: |
3573 | + return value_.int_ == other.value_.int_; |
3574 | + case uintValue: |
3575 | + return value_.uint_ == other.value_.uint_; |
3576 | + case realValue: |
3577 | + return value_.real_ == other.value_.real_; |
3578 | + case booleanValue: |
3579 | + return value_.bool_ == other.value_.bool_; |
3580 | + case stringValue: |
3581 | + return ( value_.string_ == other.value_.string_ ) |
3582 | + || ( other.value_.string_ |
3583 | + && value_.string_ |
3584 | + && strcmp( value_.string_, other.value_.string_ ) == 0 ); |
3585 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3586 | + case arrayValue: |
3587 | + case objectValue: |
3588 | + return value_.map_->size() == other.value_.map_->size() |
3589 | + && (*value_.map_) == (*other.value_.map_); |
3590 | +#else |
3591 | + case arrayValue: |
3592 | + return value_.array_->compare( *(other.value_.array_) ) == 0; |
3593 | + case objectValue: |
3594 | + return value_.map_->compare( *(other.value_.map_) ) == 0; |
3595 | +#endif |
3596 | + default: |
3597 | + JSON_ASSERT_UNREACHABLE; |
3598 | + } |
3599 | + return 0; // unreachable |
3600 | +} |
3601 | + |
3602 | +bool |
3603 | +Value::operator !=( const Value &other ) const |
3604 | +{ |
3605 | + return !( *this == other ); |
3606 | +} |
3607 | + |
3608 | +const char * |
3609 | +Value::asCString() const |
3610 | +{ |
3611 | + JSON_ASSERT( type_ == stringValue ); |
3612 | + return value_.string_; |
3613 | +} |
3614 | + |
3615 | + |
3616 | +std::string |
3617 | +Value::asString() const |
3618 | +{ |
3619 | + switch ( type_ ) |
3620 | + { |
3621 | + case nullValue: |
3622 | + return ""; |
3623 | + case stringValue: |
3624 | + return value_.string_ ? value_.string_ : ""; |
3625 | + case booleanValue: |
3626 | + return value_.bool_ ? "true" : "false"; |
3627 | + case intValue: |
3628 | + case uintValue: |
3629 | + case realValue: |
3630 | + case arrayValue: |
3631 | + case objectValue: |
3632 | + JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); |
3633 | + default: |
3634 | + JSON_ASSERT_UNREACHABLE; |
3635 | + } |
3636 | + return ""; // unreachable |
3637 | +} |
3638 | + |
3639 | +# ifdef JSON_USE_CPPTL |
3640 | +CppTL::ConstString |
3641 | +Value::asConstString() const |
3642 | +{ |
3643 | + return CppTL::ConstString( asString().c_str() ); |
3644 | +} |
3645 | +# endif |
3646 | + |
3647 | +Value::Int |
3648 | +Value::asInt() const |
3649 | +{ |
3650 | + switch ( type_ ) |
3651 | + { |
3652 | + case nullValue: |
3653 | + return 0; |
3654 | + case intValue: |
3655 | + return value_.int_; |
3656 | + case uintValue: |
3657 | + JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); |
3658 | + return value_.uint_; |
3659 | + case realValue: |
3660 | + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); |
3661 | + return Int( value_.real_ ); |
3662 | + case booleanValue: |
3663 | + return value_.bool_ ? 1 : 0; |
3664 | + case stringValue: |
3665 | + case arrayValue: |
3666 | + case objectValue: |
3667 | + JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); |
3668 | + default: |
3669 | + JSON_ASSERT_UNREACHABLE; |
3670 | + } |
3671 | + return 0; // unreachable; |
3672 | +} |
3673 | + |
3674 | +Value::UInt |
3675 | +Value::asUInt() const |
3676 | +{ |
3677 | + switch ( type_ ) |
3678 | + { |
3679 | + case nullValue: |
3680 | + return 0; |
3681 | + case intValue: |
3682 | + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); |
3683 | + return value_.int_; |
3684 | + case uintValue: |
3685 | + return value_.uint_; |
3686 | + case realValue: |
3687 | + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); |
3688 | + return UInt( value_.real_ ); |
3689 | + case booleanValue: |
3690 | + return value_.bool_ ? 1 : 0; |
3691 | + case stringValue: |
3692 | + case arrayValue: |
3693 | + case objectValue: |
3694 | + JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); |
3695 | + default: |
3696 | + JSON_ASSERT_UNREACHABLE; |
3697 | + } |
3698 | + return 0; // unreachable; |
3699 | +} |
3700 | + |
3701 | +double |
3702 | +Value::asDouble() const |
3703 | +{ |
3704 | + switch ( type_ ) |
3705 | + { |
3706 | + case nullValue: |
3707 | + return 0.0; |
3708 | + case intValue: |
3709 | + return value_.int_; |
3710 | + case uintValue: |
3711 | + return value_.uint_; |
3712 | + case realValue: |
3713 | + return value_.real_; |
3714 | + case booleanValue: |
3715 | + return value_.bool_ ? 1.0 : 0.0; |
3716 | + case stringValue: |
3717 | + case arrayValue: |
3718 | + case objectValue: |
3719 | + JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); |
3720 | + default: |
3721 | + JSON_ASSERT_UNREACHABLE; |
3722 | + } |
3723 | + return 0; // unreachable; |
3724 | +} |
3725 | + |
3726 | +bool |
3727 | +Value::asBool() const |
3728 | +{ |
3729 | + switch ( type_ ) |
3730 | + { |
3731 | + case nullValue: |
3732 | + return false; |
3733 | + case intValue: |
3734 | + case uintValue: |
3735 | + return value_.int_ != 0; |
3736 | + case realValue: |
3737 | + return value_.real_ != 0.0; |
3738 | + case booleanValue: |
3739 | + return value_.bool_; |
3740 | + case stringValue: |
3741 | + return value_.string_ && value_.string_[0] != 0; |
3742 | + case arrayValue: |
3743 | + case objectValue: |
3744 | + return value_.map_->size() != 0; |
3745 | + default: |
3746 | + JSON_ASSERT_UNREACHABLE; |
3747 | + } |
3748 | + return false; // unreachable; |
3749 | +} |
3750 | + |
3751 | + |
3752 | +bool |
3753 | +Value::isConvertibleTo( ValueType other ) const |
3754 | +{ |
3755 | + switch ( type_ ) |
3756 | + { |
3757 | + case nullValue: |
3758 | + return true; |
3759 | + case intValue: |
3760 | + return ( other == nullValue && value_.int_ == 0 ) |
3761 | + || other == intValue |
3762 | + || ( other == uintValue && value_.int_ >= 0 ) |
3763 | + || other == realValue |
3764 | + || other == stringValue |
3765 | + || other == booleanValue; |
3766 | + case uintValue: |
3767 | + return ( other == nullValue && value_.uint_ == 0 ) |
3768 | + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) |
3769 | + || other == uintValue |
3770 | + || other == realValue |
3771 | + || other == stringValue |
3772 | + || other == booleanValue; |
3773 | + case realValue: |
3774 | + return ( other == nullValue && value_.real_ == 0.0 ) |
3775 | + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) |
3776 | + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) |
3777 | + || other == realValue |
3778 | + || other == stringValue |
3779 | + || other == booleanValue; |
3780 | + case booleanValue: |
3781 | + return ( other == nullValue && value_.bool_ == false ) |
3782 | + || other == intValue |
3783 | + || other == uintValue |
3784 | + || other == realValue |
3785 | + || other == stringValue |
3786 | + || other == booleanValue; |
3787 | + case stringValue: |
3788 | + return other == stringValue |
3789 | + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); |
3790 | + case arrayValue: |
3791 | + return other == arrayValue |
3792 | + || ( other == nullValue && value_.map_->size() == 0 ); |
3793 | + case objectValue: |
3794 | + return other == objectValue |
3795 | + || ( other == nullValue && value_.map_->size() == 0 ); |
3796 | + default: |
3797 | + JSON_ASSERT_UNREACHABLE; |
3798 | + } |
3799 | + return false; // unreachable; |
3800 | +} |
3801 | + |
3802 | + |
3803 | +/// Number of values in array or object |
3804 | +Value::UInt |
3805 | +Value::size() const |
3806 | +{ |
3807 | + switch ( type_ ) |
3808 | + { |
3809 | + case nullValue: |
3810 | + case intValue: |
3811 | + case uintValue: |
3812 | + case realValue: |
3813 | + case booleanValue: |
3814 | + case stringValue: |
3815 | + return 0; |
3816 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3817 | + case arrayValue: // size of the array is highest index + 1 |
3818 | + if ( !value_.map_->empty() ) |
3819 | + { |
3820 | + ObjectValues::const_iterator itLast = value_.map_->end(); |
3821 | + --itLast; |
3822 | + return (*itLast).first.index()+1; |
3823 | + } |
3824 | + return 0; |
3825 | + case objectValue: |
3826 | + return Int( value_.map_->size() ); |
3827 | +#else |
3828 | + case arrayValue: |
3829 | + return Int( value_.array_->size() ); |
3830 | + case objectValue: |
3831 | + return Int( value_.map_->size() ); |
3832 | +#endif |
3833 | + default: |
3834 | + JSON_ASSERT_UNREACHABLE; |
3835 | + } |
3836 | + return 0; // unreachable; |
3837 | +} |
3838 | + |
3839 | + |
3840 | +bool |
3841 | +Value::empty() const |
3842 | +{ |
3843 | + if ( isNull() || isArray() || isObject() ) |
3844 | + return size() == 0u; |
3845 | + else |
3846 | + return false; |
3847 | +} |
3848 | + |
3849 | + |
3850 | +bool |
3851 | +Value::operator!() const |
3852 | +{ |
3853 | + return isNull(); |
3854 | +} |
3855 | + |
3856 | + |
3857 | +void |
3858 | +Value::clear() |
3859 | +{ |
3860 | + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); |
3861 | + |
3862 | + switch ( type_ ) |
3863 | + { |
3864 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3865 | + case arrayValue: |
3866 | + case objectValue: |
3867 | + value_.map_->clear(); |
3868 | + break; |
3869 | +#else |
3870 | + case arrayValue: |
3871 | + value_.array_->clear(); |
3872 | + break; |
3873 | + case objectValue: |
3874 | + value_.map_->clear(); |
3875 | + break; |
3876 | +#endif |
3877 | + default: |
3878 | + break; |
3879 | + } |
3880 | +} |
3881 | + |
3882 | +void |
3883 | +Value::resize( UInt newSize ) |
3884 | +{ |
3885 | + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); |
3886 | + if ( type_ == nullValue ) |
3887 | + *this = Value( arrayValue ); |
3888 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3889 | + UInt oldSize = size(); |
3890 | + if ( newSize == 0 ) |
3891 | + clear(); |
3892 | + else if ( newSize > oldSize ) |
3893 | + (*this)[ newSize - 1 ]; |
3894 | + else |
3895 | + { |
3896 | + for ( UInt index = newSize; index < oldSize; ++index ) |
3897 | + value_.map_->erase( index ); |
3898 | + assert( size() == newSize ); |
3899 | + } |
3900 | +#else |
3901 | + value_.array_->resize( newSize ); |
3902 | +#endif |
3903 | +} |
3904 | + |
3905 | + |
3906 | +Value & |
3907 | +Value::operator[]( UInt index ) |
3908 | +{ |
3909 | + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); |
3910 | + if ( type_ == nullValue ) |
3911 | + *this = Value( arrayValue ); |
3912 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3913 | + CZString key( index ); |
3914 | + ObjectValues::iterator it = value_.map_->lower_bound( key ); |
3915 | + if ( it != value_.map_->end() && (*it).first == key ) |
3916 | + return (*it).second; |
3917 | + |
3918 | + ObjectValues::value_type defaultValue( key, null ); |
3919 | + it = value_.map_->insert( it, defaultValue ); |
3920 | + return (*it).second; |
3921 | +#else |
3922 | + return value_.array_->resolveReference( index ); |
3923 | +#endif |
3924 | +} |
3925 | + |
3926 | + |
3927 | +const Value & |
3928 | +Value::operator[]( UInt index ) const |
3929 | +{ |
3930 | + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); |
3931 | + if ( type_ == nullValue ) |
3932 | + return null; |
3933 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3934 | + CZString key( index ); |
3935 | + ObjectValues::const_iterator it = value_.map_->find( key ); |
3936 | + if ( it == value_.map_->end() ) |
3937 | + return null; |
3938 | + return (*it).second; |
3939 | +#else |
3940 | + Value *value = value_.array_->find( index ); |
3941 | + return value ? *value : null; |
3942 | +#endif |
3943 | +} |
3944 | + |
3945 | + |
3946 | +Value & |
3947 | +Value::operator[]( const char *key ) |
3948 | +{ |
3949 | + return resolveReference( key, false ); |
3950 | +} |
3951 | + |
3952 | + |
3953 | +Value & |
3954 | +Value::resolveReference( const char *key, |
3955 | + bool isStatic ) |
3956 | +{ |
3957 | + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); |
3958 | + if ( type_ == nullValue ) |
3959 | + *this = Value( objectValue ); |
3960 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
3961 | + CZString actualKey( key, isStatic ? CZString::noDuplication |
3962 | + : CZString::duplicateOnCopy ); |
3963 | + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); |
3964 | + if ( it != value_.map_->end() && (*it).first == actualKey ) |
3965 | + return (*it).second; |
3966 | + |
3967 | + ObjectValues::value_type defaultValue( actualKey, null ); |
3968 | + it = value_.map_->insert( it, defaultValue ); |
3969 | + Value &value = (*it).second; |
3970 | + return value; |
3971 | +#else |
3972 | + return value_.map_->resolveReference( key, isStatic ); |
3973 | +#endif |
3974 | +} |
3975 | + |
3976 | + |
3977 | +Value |
3978 | +Value::get( UInt index, |
3979 | + const Value &defaultValue ) const |
3980 | +{ |
3981 | + const Value *value = &((*this)[index]); |
3982 | + return value == &null ? defaultValue : *value; |
3983 | +} |
3984 | + |
3985 | + |
3986 | +bool |
3987 | +Value::isValidIndex( UInt index ) const |
3988 | +{ |
3989 | + return index < size(); |
3990 | +} |
3991 | + |
3992 | + |
3993 | + |
3994 | +const Value & |
3995 | +Value::operator[]( const char *key ) const |
3996 | +{ |
3997 | + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); |
3998 | + if ( type_ == nullValue ) |
3999 | + return null; |
4000 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4001 | + CZString actualKey( key, CZString::noDuplication ); |
4002 | + ObjectValues::const_iterator it = value_.map_->find( actualKey ); |
4003 | + if ( it == value_.map_->end() ) |
4004 | + return null; |
4005 | + return (*it).second; |
4006 | +#else |
4007 | + const Value *value = value_.map_->find( key ); |
4008 | + return value ? *value : null; |
4009 | +#endif |
4010 | +} |
4011 | + |
4012 | + |
4013 | +Value & |
4014 | +Value::operator[]( const std::string &key ) |
4015 | +{ |
4016 | + return (*this)[ key.c_str() ]; |
4017 | +} |
4018 | + |
4019 | + |
4020 | +const Value & |
4021 | +Value::operator[]( const std::string &key ) const |
4022 | +{ |
4023 | + return (*this)[ key.c_str() ]; |
4024 | +} |
4025 | + |
4026 | +Value & |
4027 | +Value::operator[]( const StaticString &key ) |
4028 | +{ |
4029 | + return resolveReference( key, true ); |
4030 | +} |
4031 | + |
4032 | + |
4033 | +# ifdef JSON_USE_CPPTL |
4034 | +Value & |
4035 | +Value::operator[]( const CppTL::ConstString &key ) |
4036 | +{ |
4037 | + return (*this)[ key.c_str() ]; |
4038 | +} |
4039 | + |
4040 | + |
4041 | +const Value & |
4042 | +Value::operator[]( const CppTL::ConstString &key ) const |
4043 | +{ |
4044 | + return (*this)[ key.c_str() ]; |
4045 | +} |
4046 | +# endif |
4047 | + |
4048 | + |
4049 | +Value & |
4050 | +Value::append( const Value &value ) |
4051 | +{ |
4052 | + return (*this)[size()] = value; |
4053 | +} |
4054 | + |
4055 | + |
4056 | +Value |
4057 | +Value::get( const char *key, |
4058 | + const Value &defaultValue ) const |
4059 | +{ |
4060 | + const Value *value = &((*this)[key]); |
4061 | + return value == &null ? defaultValue : *value; |
4062 | +} |
4063 | + |
4064 | + |
4065 | +Value |
4066 | +Value::get( const std::string &key, |
4067 | + const Value &defaultValue ) const |
4068 | +{ |
4069 | + return get( key.c_str(), defaultValue ); |
4070 | +} |
4071 | + |
4072 | +Value |
4073 | +Value::removeMember( const char* key ) |
4074 | +{ |
4075 | + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); |
4076 | + if ( type_ == nullValue ) |
4077 | + return null; |
4078 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4079 | + CZString actualKey( key, CZString::noDuplication ); |
4080 | + ObjectValues::iterator it = value_.map_->find( actualKey ); |
4081 | + if ( it == value_.map_->end() ) |
4082 | + return null; |
4083 | + Value old(it->second); |
4084 | + value_.map_->erase(it); |
4085 | + return old; |
4086 | +#else |
4087 | + Value *value = value_.map_->find( key ); |
4088 | + if (value){ |
4089 | + Value old(*value); |
4090 | + value_.map_.remove( key ); |
4091 | + return old; |
4092 | + } else { |
4093 | + return null; |
4094 | + } |
4095 | +#endif |
4096 | +} |
4097 | + |
4098 | +Value |
4099 | +Value::removeMember( const std::string &key ) |
4100 | +{ |
4101 | + return removeMember( key.c_str() ); |
4102 | +} |
4103 | + |
4104 | +# ifdef JSON_USE_CPPTL |
4105 | +Value |
4106 | +Value::get( const CppTL::ConstString &key, |
4107 | + const Value &defaultValue ) const |
4108 | +{ |
4109 | + return get( key.c_str(), defaultValue ); |
4110 | +} |
4111 | +# endif |
4112 | + |
4113 | +bool |
4114 | +Value::isMember( const char *key ) const |
4115 | +{ |
4116 | + const Value *value = &((*this)[key]); |
4117 | + return value != &null; |
4118 | +} |
4119 | + |
4120 | + |
4121 | +bool |
4122 | +Value::isMember( const std::string &key ) const |
4123 | +{ |
4124 | + return isMember( key.c_str() ); |
4125 | +} |
4126 | + |
4127 | + |
4128 | +# ifdef JSON_USE_CPPTL |
4129 | +bool |
4130 | +Value::isMember( const CppTL::ConstString &key ) const |
4131 | +{ |
4132 | + return isMember( key.c_str() ); |
4133 | +} |
4134 | +#endif |
4135 | + |
4136 | +Value::Members |
4137 | +Value::getMemberNames() const |
4138 | +{ |
4139 | + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); |
4140 | + if ( type_ == nullValue ) |
4141 | + return Value::Members(); |
4142 | + Members members; |
4143 | + members.reserve( value_.map_->size() ); |
4144 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4145 | + ObjectValues::const_iterator it = value_.map_->begin(); |
4146 | + ObjectValues::const_iterator itEnd = value_.map_->end(); |
4147 | + for ( ; it != itEnd; ++it ) |
4148 | + members.push_back( std::string( (*it).first.c_str() ) ); |
4149 | +#else |
4150 | + ValueInternalMap::IteratorState it; |
4151 | + ValueInternalMap::IteratorState itEnd; |
4152 | + value_.map_->makeBeginIterator( it ); |
4153 | + value_.map_->makeEndIterator( itEnd ); |
4154 | + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) |
4155 | + members.push_back( std::string( ValueInternalMap::key( it ) ) ); |
4156 | +#endif |
4157 | + return members; |
4158 | +} |
4159 | +// |
4160 | +//# ifdef JSON_USE_CPPTL |
4161 | +//EnumMemberNames |
4162 | +//Value::enumMemberNames() const |
4163 | +//{ |
4164 | +// if ( type_ == objectValue ) |
4165 | +// { |
4166 | +// return CppTL::Enum::any( CppTL::Enum::transform( |
4167 | +// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), |
4168 | +// MemberNamesTransform() ) ); |
4169 | +// } |
4170 | +// return EnumMemberNames(); |
4171 | +//} |
4172 | +// |
4173 | +// |
4174 | +//EnumValues |
4175 | +//Value::enumValues() const |
4176 | +//{ |
4177 | +// if ( type_ == objectValue || type_ == arrayValue ) |
4178 | +// return CppTL::Enum::anyValues( *(value_.map_), |
4179 | +// CppTL::Type<const Value &>() ); |
4180 | +// return EnumValues(); |
4181 | +//} |
4182 | +// |
4183 | +//# endif |
4184 | + |
4185 | + |
4186 | +bool |
4187 | +Value::isNull() const |
4188 | +{ |
4189 | + return type_ == nullValue; |
4190 | +} |
4191 | + |
4192 | + |
4193 | +bool |
4194 | +Value::isBool() const |
4195 | +{ |
4196 | + return type_ == booleanValue; |
4197 | +} |
4198 | + |
4199 | + |
4200 | +bool |
4201 | +Value::isInt() const |
4202 | +{ |
4203 | + return type_ == intValue; |
4204 | +} |
4205 | + |
4206 | + |
4207 | +bool |
4208 | +Value::isUInt() const |
4209 | +{ |
4210 | + return type_ == uintValue; |
4211 | +} |
4212 | + |
4213 | + |
4214 | +bool |
4215 | +Value::isIntegral() const |
4216 | +{ |
4217 | + return type_ == intValue |
4218 | + || type_ == uintValue |
4219 | + || type_ == booleanValue; |
4220 | +} |
4221 | + |
4222 | + |
4223 | +bool |
4224 | +Value::isDouble() const |
4225 | +{ |
4226 | + return type_ == realValue; |
4227 | +} |
4228 | + |
4229 | + |
4230 | +bool |
4231 | +Value::isNumeric() const |
4232 | +{ |
4233 | + return isIntegral() || isDouble(); |
4234 | +} |
4235 | + |
4236 | + |
4237 | +bool |
4238 | +Value::isString() const |
4239 | +{ |
4240 | + return type_ == stringValue; |
4241 | +} |
4242 | + |
4243 | + |
4244 | +bool |
4245 | +Value::isArray() const |
4246 | +{ |
4247 | + return type_ == nullValue || type_ == arrayValue; |
4248 | +} |
4249 | + |
4250 | + |
4251 | +bool |
4252 | +Value::isObject() const |
4253 | +{ |
4254 | + return type_ == nullValue || type_ == objectValue; |
4255 | +} |
4256 | + |
4257 | + |
4258 | +void |
4259 | +Value::setComment( const char *comment, |
4260 | + CommentPlacement placement ) |
4261 | +{ |
4262 | + if ( !comments_ ) |
4263 | + comments_ = new CommentInfo[numberOfCommentPlacement]; |
4264 | + comments_[placement].setComment( comment ); |
4265 | +} |
4266 | + |
4267 | + |
4268 | +void |
4269 | +Value::setComment( const std::string &comment, |
4270 | + CommentPlacement placement ) |
4271 | +{ |
4272 | + setComment( comment.c_str(), placement ); |
4273 | +} |
4274 | + |
4275 | + |
4276 | +bool |
4277 | +Value::hasComment( CommentPlacement placement ) const |
4278 | +{ |
4279 | + return comments_ != 0 && comments_[placement].comment_ != 0; |
4280 | +} |
4281 | + |
4282 | +std::string |
4283 | +Value::getComment( CommentPlacement placement ) const |
4284 | +{ |
4285 | + if ( hasComment(placement) ) |
4286 | + return comments_[placement].comment_; |
4287 | + return ""; |
4288 | +} |
4289 | + |
4290 | + |
4291 | +std::string |
4292 | +Value::toStyledString() const |
4293 | +{ |
4294 | + StyledWriter writer; |
4295 | + return writer.write( *this ); |
4296 | +} |
4297 | + |
4298 | + |
4299 | +Value::const_iterator |
4300 | +Value::begin() const |
4301 | +{ |
4302 | + switch ( type_ ) |
4303 | + { |
4304 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
4305 | + case arrayValue: |
4306 | + if ( value_.array_ ) |
4307 | + { |
4308 | + ValueInternalArray::IteratorState it; |
4309 | + value_.array_->makeBeginIterator( it ); |
4310 | + return const_iterator( it ); |
4311 | + } |
4312 | + break; |
4313 | + case objectValue: |
4314 | + if ( value_.map_ ) |
4315 | + { |
4316 | + ValueInternalMap::IteratorState it; |
4317 | + value_.map_->makeBeginIterator( it ); |
4318 | + return const_iterator( it ); |
4319 | + } |
4320 | + break; |
4321 | +#else |
4322 | + case arrayValue: |
4323 | + case objectValue: |
4324 | + if ( value_.map_ ) |
4325 | + return const_iterator( value_.map_->begin() ); |
4326 | + break; |
4327 | +#endif |
4328 | + default: |
4329 | + break; |
4330 | + } |
4331 | + return const_iterator(); |
4332 | +} |
4333 | + |
4334 | +Value::const_iterator |
4335 | +Value::end() const |
4336 | +{ |
4337 | + switch ( type_ ) |
4338 | + { |
4339 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
4340 | + case arrayValue: |
4341 | + if ( value_.array_ ) |
4342 | + { |
4343 | + ValueInternalArray::IteratorState it; |
4344 | + value_.array_->makeEndIterator( it ); |
4345 | + return const_iterator( it ); |
4346 | + } |
4347 | + break; |
4348 | + case objectValue: |
4349 | + if ( value_.map_ ) |
4350 | + { |
4351 | + ValueInternalMap::IteratorState it; |
4352 | + value_.map_->makeEndIterator( it ); |
4353 | + return const_iterator( it ); |
4354 | + } |
4355 | + break; |
4356 | +#else |
4357 | + case arrayValue: |
4358 | + case objectValue: |
4359 | + if ( value_.map_ ) |
4360 | + return const_iterator( value_.map_->end() ); |
4361 | + break; |
4362 | +#endif |
4363 | + default: |
4364 | + break; |
4365 | + } |
4366 | + return const_iterator(); |
4367 | +} |
4368 | + |
4369 | + |
4370 | +Value::iterator |
4371 | +Value::begin() |
4372 | +{ |
4373 | + switch ( type_ ) |
4374 | + { |
4375 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
4376 | + case arrayValue: |
4377 | + if ( value_.array_ ) |
4378 | + { |
4379 | + ValueInternalArray::IteratorState it; |
4380 | + value_.array_->makeBeginIterator( it ); |
4381 | + return iterator( it ); |
4382 | + } |
4383 | + break; |
4384 | + case objectValue: |
4385 | + if ( value_.map_ ) |
4386 | + { |
4387 | + ValueInternalMap::IteratorState it; |
4388 | + value_.map_->makeBeginIterator( it ); |
4389 | + return iterator( it ); |
4390 | + } |
4391 | + break; |
4392 | +#else |
4393 | + case arrayValue: |
4394 | + case objectValue: |
4395 | + if ( value_.map_ ) |
4396 | + return iterator( value_.map_->begin() ); |
4397 | + break; |
4398 | +#endif |
4399 | + default: |
4400 | + break; |
4401 | + } |
4402 | + return iterator(); |
4403 | +} |
4404 | + |
4405 | +Value::iterator |
4406 | +Value::end() |
4407 | +{ |
4408 | + switch ( type_ ) |
4409 | + { |
4410 | +#ifdef JSON_VALUE_USE_INTERNAL_MAP |
4411 | + case arrayValue: |
4412 | + if ( value_.array_ ) |
4413 | + { |
4414 | + ValueInternalArray::IteratorState it; |
4415 | + value_.array_->makeEndIterator( it ); |
4416 | + return iterator( it ); |
4417 | + } |
4418 | + break; |
4419 | + case objectValue: |
4420 | + if ( value_.map_ ) |
4421 | + { |
4422 | + ValueInternalMap::IteratorState it; |
4423 | + value_.map_->makeEndIterator( it ); |
4424 | + return iterator( it ); |
4425 | + } |
4426 | + break; |
4427 | +#else |
4428 | + case arrayValue: |
4429 | + case objectValue: |
4430 | + if ( value_.map_ ) |
4431 | + return iterator( value_.map_->end() ); |
4432 | + break; |
4433 | +#endif |
4434 | + default: |
4435 | + break; |
4436 | + } |
4437 | + return iterator(); |
4438 | +} |
4439 | + |
4440 | + |
4441 | +// class PathArgument |
4442 | +// ////////////////////////////////////////////////////////////////// |
4443 | + |
4444 | +PathArgument::PathArgument() |
4445 | + : kind_( kindNone ) |
4446 | +{ |
4447 | +} |
4448 | + |
4449 | + |
4450 | +PathArgument::PathArgument( Value::UInt index ) |
4451 | + : index_( index ) |
4452 | + , kind_( kindIndex ) |
4453 | +{ |
4454 | +} |
4455 | + |
4456 | + |
4457 | +PathArgument::PathArgument( const char *key ) |
4458 | + : key_( key ) |
4459 | + , kind_( kindKey ) |
4460 | +{ |
4461 | +} |
4462 | + |
4463 | + |
4464 | +PathArgument::PathArgument( const std::string &key ) |
4465 | + : key_( key.c_str() ) |
4466 | + , kind_( kindKey ) |
4467 | +{ |
4468 | +} |
4469 | + |
4470 | +// class Path |
4471 | +// ////////////////////////////////////////////////////////////////// |
4472 | + |
4473 | +Path::Path( const std::string &path, |
4474 | + const PathArgument &a1, |
4475 | + const PathArgument &a2, |
4476 | + const PathArgument &a3, |
4477 | + const PathArgument &a4, |
4478 | + const PathArgument &a5 ) |
4479 | +{ |
4480 | + InArgs in; |
4481 | + in.push_back( &a1 ); |
4482 | + in.push_back( &a2 ); |
4483 | + in.push_back( &a3 ); |
4484 | + in.push_back( &a4 ); |
4485 | + in.push_back( &a5 ); |
4486 | + makePath( path, in ); |
4487 | +} |
4488 | + |
4489 | + |
4490 | +void |
4491 | +Path::makePath( const std::string &path, |
4492 | + const InArgs &in ) |
4493 | +{ |
4494 | + const char *current = path.c_str(); |
4495 | + const char *end = current + path.length(); |
4496 | + InArgs::const_iterator itInArg = in.begin(); |
4497 | + while ( current != end ) |
4498 | + { |
4499 | + if ( *current == '[' ) |
4500 | + { |
4501 | + ++current; |
4502 | + if ( *current == '%' ) |
4503 | + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); |
4504 | + else |
4505 | + { |
4506 | + Value::UInt index = 0; |
4507 | + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) |
4508 | + index = index * 10 + Value::UInt(*current - '0'); |
4509 | + args_.push_back( index ); |
4510 | + } |
4511 | + if ( current == end || *current++ != ']' ) |
4512 | + invalidPath( path, int(current - path.c_str()) ); |
4513 | + } |
4514 | + else if ( *current == '%' ) |
4515 | + { |
4516 | + addPathInArg( path, in, itInArg, PathArgument::kindKey ); |
4517 | + ++current; |
4518 | + } |
4519 | + else if ( *current == '.' ) |
4520 | + { |
4521 | + ++current; |
4522 | + } |
4523 | + else |
4524 | + { |
4525 | + const char *beginName = current; |
4526 | + while ( current != end && !strchr( "[.", *current ) ) |
4527 | + ++current; |
4528 | + args_.push_back( std::string( beginName, current ) ); |
4529 | + } |
4530 | + } |
4531 | +} |
4532 | + |
4533 | + |
4534 | +void |
4535 | +Path::addPathInArg( const std::string &, |
4536 | + const InArgs &in, |
4537 | + InArgs::const_iterator &itInArg, |
4538 | + PathArgument::Kind kind ) |
4539 | +{ |
4540 | + if ( itInArg == in.end() ) |
4541 | + { |
4542 | + // Error: missing argument %d |
4543 | + } |
4544 | + else if ( (*itInArg)->kind_ != kind ) |
4545 | + { |
4546 | + // Error: bad argument type |
4547 | + } |
4548 | + else |
4549 | + { |
4550 | + args_.push_back( **itInArg ); |
4551 | + } |
4552 | +} |
4553 | + |
4554 | + |
4555 | +void |
4556 | +Path::invalidPath( const std::string &, |
4557 | + int ) |
4558 | +{ |
4559 | + // Error: invalid path. |
4560 | +} |
4561 | + |
4562 | + |
4563 | +const Value & |
4564 | +Path::resolve( const Value &root ) const |
4565 | +{ |
4566 | + const Value *node = &root; |
4567 | + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) |
4568 | + { |
4569 | + const PathArgument &arg = *it; |
4570 | + if ( arg.kind_ == PathArgument::kindIndex ) |
4571 | + { |
4572 | + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) |
4573 | + { |
4574 | + // Error: unable to resolve path (array value expected at position... |
4575 | + } |
4576 | + node = &((*node)[arg.index_]); |
4577 | + } |
4578 | + else if ( arg.kind_ == PathArgument::kindKey ) |
4579 | + { |
4580 | + if ( !node->isObject() ) |
4581 | + { |
4582 | + // Error: unable to resolve path (object value expected at position...) |
4583 | + } |
4584 | + node = &((*node)[arg.key_]); |
4585 | + if ( node == &Value::null ) |
4586 | + { |
4587 | + // Error: unable to resolve path (object has no member named '' at position...) |
4588 | + } |
4589 | + } |
4590 | + } |
4591 | + return *node; |
4592 | +} |
4593 | + |
4594 | + |
4595 | +Value |
4596 | +Path::resolve( const Value &root, |
4597 | + const Value &defaultValue ) const |
4598 | +{ |
4599 | + const Value *node = &root; |
4600 | + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) |
4601 | + { |
4602 | + const PathArgument &arg = *it; |
4603 | + if ( arg.kind_ == PathArgument::kindIndex ) |
4604 | + { |
4605 | + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) |
4606 | + return defaultValue; |
4607 | + node = &((*node)[arg.index_]); |
4608 | + } |
4609 | + else if ( arg.kind_ == PathArgument::kindKey ) |
4610 | + { |
4611 | + if ( !node->isObject() ) |
4612 | + return defaultValue; |
4613 | + node = &((*node)[arg.key_]); |
4614 | + if ( node == &Value::null ) |
4615 | + return defaultValue; |
4616 | + } |
4617 | + } |
4618 | + return *node; |
4619 | +} |
4620 | + |
4621 | + |
4622 | +Value & |
4623 | +Path::make( Value &root ) const |
4624 | +{ |
4625 | + Value *node = &root; |
4626 | + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) |
4627 | + { |
4628 | + const PathArgument &arg = *it; |
4629 | + if ( arg.kind_ == PathArgument::kindIndex ) |
4630 | + { |
4631 | + if ( !node->isArray() ) |
4632 | + { |
4633 | + // Error: node is not an array at position ... |
4634 | + } |
4635 | + node = &((*node)[arg.index_]); |
4636 | + } |
4637 | + else if ( arg.kind_ == PathArgument::kindKey ) |
4638 | + { |
4639 | + if ( !node->isObject() ) |
4640 | + { |
4641 | + // Error: node is not an object at position... |
4642 | + } |
4643 | + node = &((*node)[arg.key_]); |
4644 | + } |
4645 | + } |
4646 | + return *node; |
4647 | +} |
4648 | + |
4649 | + |
4650 | +} // namespace Json |
4651 | |
4652 | === added file 'plugin/json_server/json/json_valueiterator.inl' |
4653 | --- plugin/json_server/json/json_valueiterator.inl 1970-01-01 00:00:00 +0000 |
4654 | +++ plugin/json_server/json/json_valueiterator.inl 2011-05-04 01:52:37 +0000 |
4655 | @@ -0,0 +1,330 @@ |
4656 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
4657 | + * |
4658 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
4659 | + * |
4660 | + * Copyright (C) 2011 Stewart Smith |
4661 | + * All rights reserved. |
4662 | + * |
4663 | + * Redistribution and use in source and binary forms, with or without |
4664 | + * modification, are permitted provided that the following conditions are |
4665 | + * met: |
4666 | + * |
4667 | + * * Redistributions of source code must retain the above copyright |
4668 | + * notice, this list of conditions and the following disclaimer. |
4669 | + * |
4670 | + * * Redistributions in binary form must reproduce the above |
4671 | + * copyright notice, this list of conditions and the following disclaimer |
4672 | + * in the documentation and/or other materials provided with the |
4673 | + * distribution. |
4674 | + * |
4675 | + * * The names of its contributors may not be used to endorse or |
4676 | + * promote products derived from this software without specific prior |
4677 | + * written permission. |
4678 | + * |
4679 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
4680 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
4681 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
4682 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
4683 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
4684 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
4685 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
4686 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
4687 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
4688 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
4689 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
4690 | + * |
4691 | + */ |
4692 | + |
4693 | +#pragma once |
4694 | +// included by json_value.cpp |
4695 | +// everything is within Json namespace |
4696 | + |
4697 | + |
4698 | +// ////////////////////////////////////////////////////////////////// |
4699 | +// ////////////////////////////////////////////////////////////////// |
4700 | +// ////////////////////////////////////////////////////////////////// |
4701 | +// class ValueIteratorBase |
4702 | +// ////////////////////////////////////////////////////////////////// |
4703 | +// ////////////////////////////////////////////////////////////////// |
4704 | +// ////////////////////////////////////////////////////////////////// |
4705 | + |
4706 | +ValueIteratorBase::ValueIteratorBase() |
4707 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4708 | + : current_() |
4709 | + , isNull_( true ) |
4710 | +{ |
4711 | +} |
4712 | +#else |
4713 | + : isArray_( true ) |
4714 | + , isNull_( true ) |
4715 | +{ |
4716 | + iterator_.array_ = ValueInternalArray::IteratorState(); |
4717 | +} |
4718 | +#endif |
4719 | + |
4720 | + |
4721 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4722 | +ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) |
4723 | + : current_( current ) |
4724 | + , isNull_( false ) |
4725 | +{ |
4726 | +} |
4727 | +#else |
4728 | +ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) |
4729 | + : isArray_( true ) |
4730 | +{ |
4731 | + iterator_.array_ = state; |
4732 | +} |
4733 | + |
4734 | + |
4735 | +ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) |
4736 | + : isArray_( false ) |
4737 | +{ |
4738 | + iterator_.map_ = state; |
4739 | +} |
4740 | +#endif |
4741 | + |
4742 | +Value & |
4743 | +ValueIteratorBase::deref() const |
4744 | +{ |
4745 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4746 | + return current_->second; |
4747 | +#else |
4748 | + if ( isArray_ ) |
4749 | + return ValueInternalArray::dereference( iterator_.array_ ); |
4750 | + return ValueInternalMap::value( iterator_.map_ ); |
4751 | +#endif |
4752 | +} |
4753 | + |
4754 | + |
4755 | +void |
4756 | +ValueIteratorBase::increment() |
4757 | +{ |
4758 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4759 | + ++current_; |
4760 | +#else |
4761 | + if ( isArray_ ) |
4762 | + ValueInternalArray::increment( iterator_.array_ ); |
4763 | + ValueInternalMap::increment( iterator_.map_ ); |
4764 | +#endif |
4765 | +} |
4766 | + |
4767 | + |
4768 | +void |
4769 | +ValueIteratorBase::decrement() |
4770 | +{ |
4771 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4772 | + --current_; |
4773 | +#else |
4774 | + if ( isArray_ ) |
4775 | + ValueInternalArray::decrement( iterator_.array_ ); |
4776 | + ValueInternalMap::decrement( iterator_.map_ ); |
4777 | +#endif |
4778 | +} |
4779 | + |
4780 | + |
4781 | +ValueIteratorBase::difference_type |
4782 | +ValueIteratorBase::computeDistance( const SelfType &other ) const |
4783 | +{ |
4784 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4785 | +# ifdef JSON_USE_CPPTL_SMALLMAP |
4786 | + return current_ - other.current_; |
4787 | +# else |
4788 | + // Iterator for null value are initialized using the default |
4789 | + // constructor, which initialize current_ to the default |
4790 | + // std::map::iterator. As begin() and end() are two instance |
4791 | + // of the default std::map::iterator, they can not be compared. |
4792 | + // To allow this, we handle this comparison specifically. |
4793 | + if ( isNull_ && other.isNull_ ) |
4794 | + { |
4795 | + return 0; |
4796 | + } |
4797 | + |
4798 | + |
4799 | + // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, |
4800 | + // which is the one used by default). |
4801 | + // Using a portable hand-made version for non random iterator instead: |
4802 | + // return difference_type( std::distance( current_, other.current_ ) ); |
4803 | + difference_type myDistance = 0; |
4804 | + for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) |
4805 | + { |
4806 | + ++myDistance; |
4807 | + } |
4808 | + return myDistance; |
4809 | +# endif |
4810 | +#else |
4811 | + if ( isArray_ ) |
4812 | + return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); |
4813 | + return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); |
4814 | +#endif |
4815 | +} |
4816 | + |
4817 | + |
4818 | +bool |
4819 | +ValueIteratorBase::isEqual( const SelfType &other ) const |
4820 | +{ |
4821 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4822 | + if ( isNull_ ) |
4823 | + { |
4824 | + return other.isNull_; |
4825 | + } |
4826 | + return current_ == other.current_; |
4827 | +#else |
4828 | + if ( isArray_ ) |
4829 | + return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); |
4830 | + return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); |
4831 | +#endif |
4832 | +} |
4833 | + |
4834 | + |
4835 | +void |
4836 | +ValueIteratorBase::copy( const SelfType &other ) |
4837 | +{ |
4838 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4839 | + current_ = other.current_; |
4840 | +#else |
4841 | + if ( isArray_ ) |
4842 | + iterator_.array_ = other.iterator_.array_; |
4843 | + iterator_.map_ = other.iterator_.map_; |
4844 | +#endif |
4845 | +} |
4846 | + |
4847 | + |
4848 | +Value |
4849 | +ValueIteratorBase::key() const |
4850 | +{ |
4851 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4852 | + const Value::CZString czstring = (*current_).first; |
4853 | + if ( czstring.c_str() ) |
4854 | + { |
4855 | + if ( czstring.isStaticString() ) |
4856 | + return Value( StaticString( czstring.c_str() ) ); |
4857 | + return Value( czstring.c_str() ); |
4858 | + } |
4859 | + return Value( czstring.index() ); |
4860 | +#else |
4861 | + if ( isArray_ ) |
4862 | + return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); |
4863 | + bool isStatic; |
4864 | + const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); |
4865 | + if ( isStatic ) |
4866 | + return Value( StaticString( memberName ) ); |
4867 | + return Value( memberName ); |
4868 | +#endif |
4869 | +} |
4870 | + |
4871 | + |
4872 | +UInt |
4873 | +ValueIteratorBase::index() const |
4874 | +{ |
4875 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4876 | + const Value::CZString czstring = (*current_).first; |
4877 | + if ( !czstring.c_str() ) |
4878 | + return czstring.index(); |
4879 | + return Value::UInt( -1 ); |
4880 | +#else |
4881 | + if ( isArray_ ) |
4882 | + return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); |
4883 | + return Value::UInt( -1 ); |
4884 | +#endif |
4885 | +} |
4886 | + |
4887 | + |
4888 | +const char * |
4889 | +ValueIteratorBase::memberName() const |
4890 | +{ |
4891 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4892 | + const char *name = (*current_).first.c_str(); |
4893 | + return name ? name : ""; |
4894 | +#else |
4895 | + if ( !isArray_ ) |
4896 | + return ValueInternalMap::key( iterator_.map_ ); |
4897 | + return ""; |
4898 | +#endif |
4899 | +} |
4900 | + |
4901 | + |
4902 | +// ////////////////////////////////////////////////////////////////// |
4903 | +// ////////////////////////////////////////////////////////////////// |
4904 | +// ////////////////////////////////////////////////////////////////// |
4905 | +// class ValueConstIterator |
4906 | +// ////////////////////////////////////////////////////////////////// |
4907 | +// ////////////////////////////////////////////////////////////////// |
4908 | +// ////////////////////////////////////////////////////////////////// |
4909 | + |
4910 | +ValueConstIterator::ValueConstIterator() |
4911 | +{ |
4912 | +} |
4913 | + |
4914 | + |
4915 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4916 | +ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) |
4917 | + : ValueIteratorBase( current ) |
4918 | +{ |
4919 | +} |
4920 | +#else |
4921 | +ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) |
4922 | + : ValueIteratorBase( state ) |
4923 | +{ |
4924 | +} |
4925 | + |
4926 | +ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) |
4927 | + : ValueIteratorBase( state ) |
4928 | +{ |
4929 | +} |
4930 | +#endif |
4931 | + |
4932 | +ValueConstIterator & |
4933 | +ValueConstIterator::operator =( const ValueIteratorBase &other ) |
4934 | +{ |
4935 | + copy( other ); |
4936 | + return *this; |
4937 | +} |
4938 | + |
4939 | + |
4940 | +// ////////////////////////////////////////////////////////////////// |
4941 | +// ////////////////////////////////////////////////////////////////// |
4942 | +// ////////////////////////////////////////////////////////////////// |
4943 | +// class ValueIterator |
4944 | +// ////////////////////////////////////////////////////////////////// |
4945 | +// ////////////////////////////////////////////////////////////////// |
4946 | +// ////////////////////////////////////////////////////////////////// |
4947 | + |
4948 | +ValueIterator::ValueIterator() |
4949 | +{ |
4950 | +} |
4951 | + |
4952 | + |
4953 | +#ifndef JSON_VALUE_USE_INTERNAL_MAP |
4954 | +ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) |
4955 | + : ValueIteratorBase( current ) |
4956 | +{ |
4957 | +} |
4958 | +#else |
4959 | +ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) |
4960 | + : ValueIteratorBase( state ) |
4961 | +{ |
4962 | +} |
4963 | + |
4964 | +ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) |
4965 | + : ValueIteratorBase( state ) |
4966 | +{ |
4967 | +} |
4968 | +#endif |
4969 | + |
4970 | +ValueIterator::ValueIterator( const ValueConstIterator &other ) |
4971 | + : ValueIteratorBase( other ) |
4972 | +{ |
4973 | +} |
4974 | + |
4975 | +ValueIterator::ValueIterator( const ValueIterator &other ) |
4976 | + : ValueIteratorBase( other ) |
4977 | +{ |
4978 | +} |
4979 | + |
4980 | +ValueIterator & |
4981 | +ValueIterator::operator =( const SelfType &other ) |
4982 | +{ |
4983 | + copy( other ); |
4984 | + return *this; |
4985 | +} |
4986 | |
4987 | === added file 'plugin/json_server/json/json_writer.cpp' |
4988 | --- plugin/json_server/json/json_writer.cpp 1970-01-01 00:00:00 +0000 |
4989 | +++ plugin/json_server/json/json_writer.cpp 2011-05-04 01:52:37 +0000 |
4990 | @@ -0,0 +1,862 @@ |
4991 | +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: |
4992 | + * |
4993 | + * JSON Library, originally from http://jsoncpp.sourceforge.net/ |
4994 | + * |
4995 | + * Copyright (C) 2011 Stewart Smith |
4996 | + * All rights reserved. |
4997 | + * |
4998 | + * Redistribution and use in source and binary forms, with or without |
4999 | + * modification, are permitted provided that the following conditions are |
5000 | + * met: |
note that this includes http:// jsoncpp. sourceforge. net/ code, which is in the public domain.