Compare commits

..

235 Commits

Author SHA1 Message Date
Christopher Dunn
7165f6ac4c 1.0.0 2014-11-20 08:45:58 -06:00
Christopher Dunn
37a9fa9f9d 1.0.0 2014-11-20 00:20:51 -06:00
xiaoyur347
83683da13f fix gcc warning when CXXFLAGS contains '-Wextra'
json_value.cpp:179:26: warning: enumeral and non-enumeral type in conditional expression [enabled by default]

https://github.com/open-source-parsers/jsoncpp/pull/84
2014-11-19 23:59:34 -06:00
Christopher Dunn
e5de78db82 Merge pull request #87 from cdunn2001/master
2to3 (but only the changes which should work with python2 also)
2014-11-19 23:54:56 -06:00
Christopher Dunn
ffd7295ab8 simple 2014-11-19 23:35:56 -06:00
Christopher Dunn
433876866d ws 2014-11-19 23:34:15 -06:00
Christopher Dunn
bd1e895287 simple py3 changes 2014-11-19 23:30:47 -06:00
Christopher Dunn
9aa6144b2a python except as 2014-11-19 23:10:02 -06:00
Christopher Dunn
5fda247dab Merge pull request #79 from ya1gaurav/patch-2
Remove gcc compilation warnings in json_reader.cpp
2014-11-18 00:14:06 -06:00
Gaurav
767713be2b Remove gcc compilation warning in json_reader.cpp
Submitting Patch for Issue : https://github.com/open-source-parsers/jsoncpp/issues/77
It will fix warnings in json_reader.cpp
2014-11-17 14:04:03 +05:30
Aaron Jacobs
3e3a8d5bd2 Merge pull request #74 from ya1gaurav/master
Prefer appending character constants over string literals.
2014-11-14 10:39:03 +11:00
Gaurav
abc1e07543 Prefer appending character constants over string literals - correct patch.
Submitting correct patch for https://github.com/open-source-parsers/jsoncpp/issues/61
2014-11-13 12:47:19 +05:30
Christopher Dunn
00b0a1b992 Merge pull request #70 from jmesmon/pkg-config-include-var
pkg-config: support INCLUDE_INSTALL_DIR
2014-11-12 00:03:52 -06:00
Cody P Schafer
1fe6c59827 pkg-config: support INCLUDE_INSTALL_DIR 2014-11-11 16:09:05 -05:00
Aaron Jacobs
20672ed02c Merge pull request #68 from BillyDonahue/refactor_ctor_boilerplate
Json::Value: Refactor common code in all constructors to an initBasic() function.
2014-11-10 20:23:52 +11:00
Billy Donahue
8eb5d89db6 Remove initInt and initUInt until they are needed. 2014-11-10 01:35:42 -05:00
Christopher Dunn
9c80798038 Merge pull request #63/#67 from dreifachstein/master
Allow customization of component install dirs
Passed Travis CI.
2014-11-08 15:56:36 -06:00
Yu Xiaolei
72e5223658 Fix default runtime install dir 2014-11-05 13:18:16 +08:00
Yu Xiaolei
dc84d96a49 Add CMake package file generation support 2014-11-05 12:31:44 +08:00
Yu Xiaolei
1c3a20de50 Allow customization of component install dirs 2014-11-05 11:25:53 +08:00
Christopher Dunn
533dbe0898 Update README.md
Note on C++11
2014-11-03 12:39:01 -06:00
Christopher Dunn
6cb2f7bd65 Merge pull request #58 from autochthe/master
Add public semantic error reporting
2014-10-29 22:41:50 -05:00
Mara Kim
b84a39cae5 Add public semantic error reporting
Closes open-source-parsers/jsoncpp#57
2014-10-23 02:18:14 -05:00
Christopher Dunn
7bd75b0fb4 Merge pull request #55 from glehmann/build-env
use the CXXFLAGS and LINKFLAGS environment variable in scons
2014-10-21 12:38:05 -05:00
Gaëtan Lehmann
f74a4ff17a use the CXXFLAGS and LINKFLAGS environment variable in scons
this allows homebrew to use its own flags during the build
2014-10-21 11:43:53 +02:00
Aaron Jacobs
b7eccbb110 Merge pull request #54 from I3ck/master
Updated documentation links to point to GitHub
2014-10-20 22:06:26 +11:00
Martin Buck
ebe2d6e6ee Updated documentation links to point to GitHub 2014-10-20 07:59:44 +02:00
Christopher Dunn
4cd31f01bb Merge pull request #53 from I3ck/master
Removed typo in README
2014-10-13 07:24:07 -05:00
I3ck
ab19fa1d6f Removed typo in README 2014-10-13 12:17:53 +02:00
Christopher Dunn
bc8b5d871f Merge pull request #52 from cquammen/master
Removed unneeded newlines from parsed comments
2014-10-11 16:40:51 -05:00
Cory Quammen
fd06bfca79 Removed unneeded newlines from parsed comments
Newlines from comments separated by lines are retained when comments
are appended, so adding a newline between separate comments for a
node is not needed.
2014-10-09 16:33:29 -04:00
Cory Quammen
4d23492d11 Added printing of comments to *.actual test files
This enables testing of comment-handling code. Updated *.expected test
result files to account for printing of comments.
2014-10-09 16:33:29 -04:00
Christopher Dunn
aa650c5b9d Merge pull request #50 from sergzub/master
CMake 2.8.5 or higher is required
2014-10-05 12:04:46 -05:00
sergzub
ae5a56f9ff CMake 2.8.5 or higher is required
make with error for the lower version:

Linking CXX executable ../../bin/jsoncpp_test
/bin/sh: $<TARGET_FILE:jsoncpp_test>: command not found
make[2]: *** [bin/jsoncpp_test] Error 127
make[1]: *** [src/test_lib_json/CMakeFiles/jsoncpp_test.dir/all] Error 2
make: *** [all] Error 2

due to 
http://stackoverflow.com/questions/5410164/how-do-i-use-a-targets-path-in-add-custom-command-in-cmake#comment6139682_5410794
2014-10-03 16:40:58 +04:00
Christopher Dunn
8aec8d88f2 Merge pull request #46 from chuckatkins/fix-for-old-msvc
Workaround for missing C99 functions in older versions of Visual Studio
2014-09-20 14:05:18 -07:00
Chuck Atkins
9dc9026e0b Workaround for missing C99 functions in older versions of Visual Studio 2014-09-19 13:16:09 -04:00
Christopher Dunn
4002f8a4be Revert "Revert "Removed vim mode lines.""
This reverts commit af77b5b594.

See discussion at
  32009b17e4 (commitcomment-7827708)
2014-09-18 16:46:40 -07:00
Christopher Dunn
0375af2eb5 drop version qualifier
This should help keep version.h stable.

    x.y.z-dev
    => major, minor, patch, qual
    == x, y, z, -dev

But we do not need -dev anymore.
2014-09-18 16:43:07 -07:00
Aaron Jacobs
ba330893d7 Ran clang-format again, this time hitting .inl files too.
clang-format -i $(find . -name '*.h' -or -name '*.cpp' -or -name '*.inl')
2014-09-18 16:33:49 -07:00
Christopher Dunn
57dde78308 Merge pull request #45 from jonessen96/master
Added Version definition to the pkg-config file
2014-09-18 16:33:29 -07:00
Jonas Platte
69c324ead5 Added Version definition to the pkg-config file 2014-09-17 20:37:59 +02:00
Christopher Dunn
263a4706fa Merge pull request #44 from cdunn2001/version
0.7.0
2014-09-16 19:11:59 -07:00
Christopher Dunn
4bceabf2f9 ws autogen 2014-09-16 19:11:20 -07:00
Christopher Dunn
877dd17206 bump version; proper SOVERSION 2014-09-16 12:42:33 -07:00
Christopher Dunn
16709c6ee8 JSONCPP_VERSION, not JSON_CPP_VERSION 2014-09-16 12:42:33 -07:00
Christopher Dunn
b2a1ca5b54 in dev.makefile, build shared too 2014-09-16 12:42:33 -07:00
Christopher Dunn
9aa4681052 Revert "Merge branch 'no-version'"
This reverts commit d9ced92d40, reversing
changes made to d2fa664a12.

Conflicts:
	include/json/version.h (keep)
2014-09-16 12:42:32 -07:00
Christopher Dunn
af77b5b594 Revert "Removed vim mode lines."
This reverts commit 32009b17e4.
2014-09-16 12:42:32 -07:00
Aaron Jacobs
11086dd6a7 Enabled PointerBindsToType in clang-format options. 2014-09-15 10:15:29 +10:00
Aaron Jacobs
30b07c0275 Ran clang-format over all .h and .cpp files.
clang-format -i $(find . -name '*.h' -or -name '*.cpp')
2014-09-15 10:14:48 +10:00
Aaron Jacobs
32009b17e4 Removed vim mode lines.
Users can set their own preferences in their personal vimrc.
2014-09-15 08:23:41 +10:00
Christopher Dunn
b4357fa224 Merge pull request #41 from bmcdorman/feature-arrow_operator
Added arrow operator to ValueIterator and ValueConstIterator
2014-09-14 08:17:03 -07:00
Braden McDorman
540db3b052 Added arrow operator to ValueIterator and ValueConstIterator 2014-09-14 08:15:47 -07:00
Christopher Dunn
f4b06cd607 rm trailing ws 2014-09-14 08:15:32 -07:00
Christopher Dunn
dd5b57a3d9 Merge pull request #42 from jonessen96/master
Add pkg-config support
2014-09-14 07:54:13 -07:00
Jonas Platte
6270858c43 Added pkg-config file 2014-09-14 15:45:07 +02:00
Christopher Dunn
d9ced92d40 Merge branch 'no-version'
We can modify version.h directly, as desired. It is retained for
backward-compatibility, in case anyone is using those macros.

Note: I have not modified SConstruct since that is deprecated, so
I have retained the `version` file, which should be ignored.

Addresses issue #38
2014-09-11 10:10:40 -07:00
Christopher Dunn
8f730b8a60 stop using version.h.in for cmake 2014-09-11 10:09:48 -07:00
Christopher Dunn
b061ff4a1e generated for the last time, maybe 2014-09-11 10:04:49 -07:00
Christopher Dunn
8ececfa538 stop ignoring version.h 2014-09-11 10:04:23 -07:00
Christopher Dunn
d2fa664a12 makefile for simple testing
This is hard to use within Travis-ci.com because that uses
build variants.
2014-09-10 18:03:34 -07:00
Christopher Dunn
b7894977e7 deprecate makerelease.py (someday drop version.h too?) 2014-09-10 18:01:10 -07:00
Christopher Dunn
53262c66d9 Merge branch 'SuperManitu:python3' from issue #36 2014-09-10 17:29:07 -07:00
Christopher Dunn
09228968ea fix for python2 2014-09-10 17:26:46 -07:00
SuperManitu
83b43caf8e allow python3 2014-09-10 11:09:35 -07:00
Aaron Jacobs
0dc03d0848 Merge pull request #37 from BillyDonahue/value-efficiency
Switch to copy-and-swap idiom for operator=.
2014-09-10 10:52:26 -07:00
Billy Donahue
45cd9490cd Switch to copy-and-swap idiom for operator=.
This allows the compiler to elide a copy when rhs is a temporary.
2014-09-10 10:37:34 -07:00
Christopher Dunn
236db83742 ws 2014-09-10 10:35:01 -07:00
findblar
a70b00750d pull request #35 from finblarr:patch-1
fix build directory, within repo tree
2014-09-10 10:32:51 -07:00
Christopher Dunn
033677cc1a Merge pull request #30 from mloy/redundant-strlen 2014-09-03 14:07:40 -07:00
Christopher Dunn
9d694516a0 clarify return value 2014-09-03 13:54:49 -07:00
Christopher Dunn
d94caac1ea ws 2014-09-03 13:46:37 -07:00
mloy
8eb6f88a87 snprintf does return a signed integer
assert if returned value is neagtive
2014-09-03 13:37:17 -07:00
Matthias Loy
64d591b720 snprintf already calculated the length 2014-09-03 13:37:17 -07:00
Matthias Loy
fe2cd01e80 free does nothing if parameter equals NULL 2014-09-03 13:37:17 -07:00
Christopher Dunn
b02ff20bd3 Merge pull request #33 from donmilham/master
added option to FastWriter which omits the trailing new line character
2014-09-03 13:32:53 -07:00
Don Milham
5bf16105b5 added option to FastWriter which omits the trailing new line character 2014-09-02 17:09:07 -06:00
Christopher Dunn
3515db184a Merge pull request #29 from mloy/type-punned-pointer
Type punned pointer

I'll revert this if anyone reports a problem. *strict-aliasing* is not my favorite compiler warning.
2014-08-13 23:41:05 -07:00
Matthias Loy
48d9a92a1b do intermediate step in order to omit "dereferencing type-punned pointer" error 2014-08-13 13:20:29 +02:00
Matthias Loy
f97723dbb7 provoke compile error:
"dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]"
2014-08-13 13:19:02 +02:00
Christopher Dunn
1a6426ac19 Merge pull request #21 from hiharin/master
Hmmm. Not ideal. A round-trip should reproduce the original, but null -> NaN -> ? But I guess it's no worse than it was.

The different behavior for Win CE is troubling, but it only affects people who are using these extreme values.

I've worked with Inf/NaN before, so I understand your pain.
2014-08-13 02:03:55 -07:00
David West
bc5dbc6d41 Patch for bug #53 on version 0.5.0
This is a patch that we have utilized at IDEXX Labs for the the bug described above.
We have tested and verified this on x86 32 and 64 bit linux and 32 bit arm.
2014-08-13 02:03:33 -07:00
Christopher Dunn
1ac2295c21 Merge pull request #27 from egor-tensin/master
Fixed deprecated target file path location

+1 for fixing indentation!
2014-08-13 02:03:18 -07:00
Egor Tensin
81d16dfda1 Fixed deprecated target file path location 2014-08-13 02:02:53 -07:00
Christopher Dunn
c138933784 Merge pull request #26 from alex-ac/master
Fix CMake subproject behaviour.

Sweet. But doesn't this assume that people call the subproject `jsoncpp`? It used to be `json-cpp`.
2014-08-13 02:02:33 -07:00
Aleksandr Derbenev
b3deb61f87 Fix CMake subproject behaviour. 2014-08-13 02:01:38 -07:00
Christopher Dunn
740e0207b1 Merge pull request #25 from cgilling/master
add tests to check that exceptions are thrown for wrong types

Nice!

For the record, I would have put the add-failure into the `try` block, for simplicity.
2014-08-13 02:01:11 -07:00
Chris Gilling
97c77b4a86 add tests to check that exceptions are thrown for wrong types
* Add JSONTEST_ASSERT_THROWS macro to test if an expression
  throws an exceptions.
* add JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions)
2014-08-13 02:00:41 -07:00
Christopher Dunn
7ebdabc059 Merge pull request #23 from mloy/msvc2010
Solution and project files for MSVC 2010

We'll just trust you on this. Thanks for the contribution.
2014-08-13 01:59:52 -07:00
mloy
c6d9424f71 project files for msvc2010 2014-08-13 01:57:45 -07:00
mloy
19d0ece5f9 add solution for msvc 2010 2014-08-13 01:57:45 -07:00
Christopher Dunn
35e4f2abd6 Merge pull request #22 from AlexeyKruchinin/patch-1
Update README.md
2014-08-13 01:01:37 -07:00
Alexey Kruchinin
b548cdf49c Update README.md 2014-08-06 23:24:34 -04:00
Christopher Dunn
3b9b7402fd Merge pull request #14 from eightnoteight/master
header.add_file (version.h) temporarily commented | header include path modified
2014-07-13 23:52:14 -07:00
eightnoteight
3585477f33 add file version.h temporarily commented | header include path modified 2014-07-14 11:11:14 +05:30
pffang
27e3263894 WinCE Compatibility Fix
Note: str.imbue and std::locale::classic() are not supported on WINCE
2014-07-10 20:27:52 -07:00
Christopher Dunn
8582876c5c vim modelines 2014-07-10 20:24:23 -07:00
Christopher Dunn
496c655523 fix numeric locale
In some locales (e.g. de_DE) floats have commas instead of
dots, but JSON requires dots.
See:
  https://github.com/open-source-parsers/jsoncpp/pull/9
  https://github.com/open-source-parsers/jsoncpp/pull/3
2014-07-10 20:24:23 -07:00
Christopher Dunn
49c732607b Revert "Merge pull request #7 from steffen-kiess/fix-locale"
This reverts commit 0db9d6ea01, reversing
changes made to 06dcb1fc89.

For discussion, see
  https://github.com/open-source-parsers/jsoncpp/pull/9
  https://github.com/open-source-parsers/jsoncpp/pull/3
2014-07-10 19:59:26 -07:00
Christopher Dunn
655a9db0cc Merge pull request #11 from cdunn2001/inc
improve some includes
2014-07-09 21:53:40 -07:00
Christopher Dunn
f3989977c0 rm generated version.h 2014-07-09 21:48:49 -07:00
Christopher Dunn
60f778b9fc relative include 2014-07-09 21:40:23 -07:00
Christopher Dunn
50f6779578 Merge pull request #10 from cdunn2001/doxy
Doxy
2014-07-09 21:29:18 -07:00
Christopher Dunn
5a65132e72 README/NEWS links 2014-07-09 11:48:27 -07:00
Christopher Dunn
bef834edca update docs for open-source-parsers org 2014-07-09 11:48:27 -07:00
Christopher Dunn
0973f2e6bc after doxygen -u 2014-07-09 11:48:27 -07:00
Christopher Dunn
5031a59518 doxygen changed 2014-07-09 11:48:27 -07:00
Christopher Dunn
5850b83a5b moved roadmap to wiki 2014-07-09 11:48:26 -07:00
Christopher Dunn
9dd7eea945 fix doxybuild.py paths 2014-07-09 11:48:26 -07:00
Christopher Dunn
35bea41bc9 update docs for github 2014-07-09 11:48:26 -07:00
Christopher Dunn
542cd1d3f5 remove some sourceforge links 2014-07-09 11:48:26 -07:00
Christopher Dunn
ba50403414 ignore doxygen stuff 2014-07-09 11:48:26 -07:00
Christopher Dunn
0db9d6ea01 Merge pull request #7 from cdunn2001/fix-locale
Use std::stringstream instead of snprintf() for double->string conversion
2014-07-09 11:47:48 -07:00
Steffen Kieß
b8aaa03367 Use std::stringstream instead of snprintf() for double->string conversion
`snprintf()` will use the current `LC_NUMERIC` locale
for converting a double to a string,
which will use a `,` instead of a `.` in some locales (e.g. de_DE).
`std::stringstream` allows setting the locale to `"C"` to always get a `.`.
This occurs only for that `stringstream` instance; no global is
altered.
2014-07-09 11:46:00 -07:00
Christopher Dunn
06dcb1fc89 cmake updates this 2014-07-08 21:57:12 -07:00
Christopher Dunn
973de3988b Merge pull request #1 from cdunn2001/patch-renu555
dead-code patch by renu555
2014-07-05 19:10:34 -07:00
renu555
41b79398a3 Always true condition.
for (int index = 0; index < size && !isMultiLine; ++index) 
In addition to dead code, in the above if condition checking to !isMultiLine is of no use as it will be always true and hence "for" depends only on condition [index < size.]
The mentioned test case works fine in this case also.
2014-07-05 19:05:41 -07:00
renu555
66b77384d8 Fix dead code scenario.
Changes explained
2014-07-05 19:05:41 -07:00
renu555
17c244e644 Fixing unreachable condition.
if (!isMultiLine) at line 563 suggests that isMultiline is 0 when if takes true branch. So the condition && at line 571 will always be false.
Also at line 568 !isMultiline in loop conditional check suggests that it depends only on one condition i.e. index <size because !isMultiline is always true. 
Hence , it seems logical mistake at line 571 of using && instead of ||
2014-07-05 19:05:41 -07:00
Christopher Dunn
8050d8b677 Merge pull request #6 from cdunn2001/fix-static-init
I will try to pull the other changes from Chromium as well.

This passed Travis.
2014-07-05 17:39:19 -07:00
Christopher Dunn
28836b8acc fix bug for static init
Ugh! Static initialization of instance variables is a very bad idea.

This fix is taken from the Chromium code-base. It includes their
double-fix for ARM.

* https://codereview.chromium.org/24984004
* https://src.chromium.org/viewvc/chrome?revision=226099&view=revision
* https://code.google.com/p/webrtc/issues/detail?id=1777
2014-07-05 17:36:20 -07:00
Aaron Jacobs
47f1577fd3 Gave the license section a makeover. 2014-07-01 13:13:46 +10:00
Aaron Jacobs
9cc184146f Gave the test output section a makeover. 2014-07-01 13:13:03 +10:00
Aaron Jacobs
c151549937 Gave the reader/writer test section a makeover. 2014-07-01 13:11:05 +10:00
Aaron Jacobs
d61fa29da8 Gave the amalgamated source section a makeover. 2014-07-01 13:09:15 +10:00
Aaron Jacobs
b2a086adeb Gave the documentation section a makeover. 2014-07-01 13:07:21 +10:00
Aaron Jacobs
8d0f8d0dcd Gave the testing section a makeover. 2014-07-01 13:06:40 +10:00
Aaron Jacobs
49ed6c9774 Gave the scons section a makeover. 2014-07-01 12:06:16 +10:00
Aaron Jacobs
38c9826423 Gave the cmake section a makeover. 2014-07-01 12:02:57 +10:00
Aaron Jacobs
969921748b Gave the using section a makeover. 2014-07-01 11:59:25 +10:00
Aaron Jacobs
ff22ca7973 Gave the introduction section a makeover. 2014-07-01 11:56:56 +10:00
Aaron Jacobs
4b687640cb Began converting the README to Markdown. 2014-07-01 11:54:14 +10:00
Aaron Jacobs
3a0c4fcc82 Ran clang-format again. 2014-07-01 09:20:48 +10:00
Aaron Jacobs
445328ace6 Fixed some clang-format weirdness. 2014-07-01 09:15:11 +10:00
Aaron Jacobs
9fa4e849a1 Ran clang-format over all .h and .cpp files.
clang-format -i $(find . -name '*.h' -or -name '*.cpp')
2014-07-01 08:48:54 +10:00
Aaron Jacobs
1b137a3802 Set BinPackParameters to false.
This option personally drives me crazy. I think it's much more readable
to be able to see one parameter per line when there are many.
2014-07-01 08:47:46 +10:00
Aaron Jacobs
fd6ada015e Added a clang-format config file, in preparation for formatting jsoncpp.
clang-format -style=llvm -dump-config > .clang-format
2014-07-01 08:45:32 +10:00
Aaron Jacobs
8540868347 Fixed some cruft in the Travis CI config file. 2014-06-30 19:57:59 +10:00
Aaron Jacobs
2de98d9bd1 Updated notification settings for Travis CI. 2014-06-30 19:51:29 +10:00
Christopher Dunn
6764059395 fix stdexcept
https://sourceforge.net/p/jsoncpp/bugs/68/
2014-05-13 09:49:25 +00:00
Aaron Jacobs
5d32295a6e Fixed a test that causes a crash when exceptions are disabled.
While I was at it, corrected whitespace too.
2014-04-23 23:57:59 +00:00
Aaron Jacobs
68db655347 Added structured error reporting to Reader.
This allows applications for interactively viewing or editing JSON to do
a better job of highlighting errors. Also added offset accessors to
Value, offering the same sort of functionality even for non-errors.

Thanks to Zach Clifford (zacharyc@google.com) for the patch.
2014-04-23 23:41:12 +00:00
Aaron Jacobs
642befc836 Added features that allow the reader to accept common non-standard JSON.
This is a version of patch #17, from Clay Wood:

    http://sourceforge.net/p/jsoncpp/patches/17/
2014-04-23 23:28:23 +00:00
Christopher Dunn
77cd83890d vim modeline
http://vim.wikia.com/wiki/Modeline_magic
2014-04-19 21:41:03 +00:00
Christopher Dunn
09439b7bc7 Comment reading/write improvements
This patch fixes some aspects of reading and writing comments:
- Multiple C++-style comments before a Json value had extra newlines appended to them. This patch removes the addition of those newlines.
- Comments written before Json values in the StyledWriter were not indented to match the indentation level of the value. This patch adds indentation to comments.
- Fixed inconsistency in newlines following C- and C++-style comments being saved as part of the comment. All newlines at the end of a comment are now removed.
- Added an additional test of comments.

https://sourceforge.net/p/jsoncpp/patches/25/
2014-04-19 21:19:24 +00:00
Christopher Dunn
ea0797351f JSON_ASSERT -> JSON_ASSERT_MESSAGE
This way, assertions can produce exceptions.
https://sourceforge.net/p/jsoncpp/bugs/67/
2014-04-19 06:37:23 +00:00
Aaron Jacobs
94d17e9fdf Added missing includes for std::istream.
Thanks to Quentin Fiard for the report.
2014-01-29 00:13:38 +00:00
Baptiste Lepilleur
a3f19c23a0 Fixed broken build on VS 2012 2013-09-23 14:10:39 +00:00
Aaron Jacobs
d2618806ba Fixed some snprintf-related build breakages in Visual Studio. 2013-08-08 23:08:28 +00:00
Aaron Jacobs
36400ac0c1 Updated two calls to sprintf that I missed in r269. 2013-08-08 00:39:32 +00:00
Aaron Jacobs
32ffb931e7 Replaced the complex implementation of valueToString(double).
The previous one was confusing and prone to buffer overflows, and didn't
work correctly with 16-decimal-digit numbers. The new one simply uses
snprintf with a standard format string.

The major change is that we don't always print a decimal point now.
Fortunately, JSON doesn't distinguish between integers and reals.
2013-08-08 00:39:12 +00:00
Aaron Jacobs
bb53cd0899 Added more floating point tests.
The first demonstrates a bug that I will soon fix.
2013-08-08 00:37:39 +00:00
Aaron Jacobs
4c531bb584 Added further floating point tests. 2013-08-08 00:13:10 +00:00
Aaron Jacobs
42d918b7aa Switched away from sprintf, which is prone to buffer overflows.
Most reasonable platforms have this function. If you're here because
this broke the build for you, consider adding an ifdef for your platform
and using sprintf there (but not on other platforms).
2013-08-06 23:12:56 +00:00
Baptiste Lepilleur
700b38020e - CMake: added option to turn fail compilation if warning occurs, and warning level 4 with MSVC.
- Fixed some warnings
2013-05-09 18:42:33 +00:00
Baptiste Lepilleur
7b62ceacee - disabled warning 4786 for VS6 caused by STL (identifier was truncated to '255' characters in the debug information)
- added batchbuild config for XP VM
2013-05-09 16:24:13 +00:00
Baptiste Lepilleur
cb5ae30f6e Added simple batch build script for CMake. 2013-05-09 15:22:14 +00:00
Baptiste Lepilleur
58b6541478 Added missing source file to CMakeLists.txt. 2013-05-09 15:21:06 +00:00
Baptiste Lepilleur
1ccfdfcb9b 2013-05-09 15:20:32 +00:00
Baptiste Lepilleur
71860de813 Fixed continuous integration matrix for debug/release build. Made static debug build verbose. 2013-05-08 22:23:07 +00:00
Baptiste Lepilleur
c515b8ec30 Added continuous integration matrix for debug/release build. Made static debug build verbose. 2013-05-08 22:15:15 +00:00
Baptiste Lepilleur
5fff185aa4 Added continuous integration matrix for shared/static library (specified through environment variables). 2013-05-08 22:04:57 +00:00
Baptiste Lepilleur
10712e85d6 Added continuous integration failure e-mail notification. 2013-05-08 21:23:52 +00:00
Baptiste Lepilleur
53c08ad916 Added clang compiler for continuous integration. 2013-05-08 21:04:42 +00:00
Baptiste Lepilleur
79e90fba0b Added basic Travis CI integration contributed by Igor Okulist. 2013-05-08 20:46:56 +00:00
Baptiste Lepilleur
ce277aa6e4 Fixed CMake / Unix build instructions. 2013-05-08 20:37:54 +00:00
Baptiste Lepilleur
eafd702a17 - New CMake based build system. Based in part on contribution from
Igor Okulist and Damien Buhl (Patch #14). Added support for running
tests and building with DLL on Windows.
- added missing JSON_API
- Visual Studio DLL: suppressed warning "C4251: <data member>: <type> 
needs to have dll-interface to be used by..." via pragma push/pop
in json-cpp headers.
- New header json/version.h now contains version number macros
(JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH
and JSONCPP_VERSION_HEXA). While this header is generated by CMake,
it is committed to ease build with alternate build system 
(CMake only update the file when it changes avoid issues with VCS).
2013-05-08 20:21:11 +00:00
Baptiste Lepilleur
a8afdd40af - Patch #3393345: BOOST_FOREACH compatibility. Made Json::iterator more standard compliant, added missing iterator_category and value_type typedefs (contribued by Robert A. Iannucci).
- Patch #3474563: added missing JSON_API on some classes causing link issues when building as a dynamic library on Windows (contributed by Francis Bolduc).
2013-04-12 14:10:13 +00:00
Baptiste Lepilleur
f92ace5e82 Patch #3600941: Missing field copy in Json::Value::iterator causing infinite loop when using experimental internal map (#define JSON_VALUE_USE_INTERNAL_MAP) (contributed by Ming-Lin Kao). 2013-04-12 13:26:23 +00:00
Baptiste Lepilleur
3f124172ce Patch #3539678: Copy constructor does not initialize allocated_ for stringValue (contributed by rmongia). 2013-04-12 13:11:14 +00:00
Baptiste Lepilleur
f8715856f3 Fix gcc -Wall warnings (patch from Matt McCormick) 2013-02-18 15:53:47 +00:00
Baptiste Lepilleur
42321f24a6 Fixed warning(error?) on #if testing value of _MSC_VER without checking that it was defined. 2012-12-20 10:08:50 +00:00
Baptiste Lepilleur
aff1171153 Added missing "include/json/assertions.h" header in amalgamate.py. 2012-07-27 09:06:40 +00:00
Aaron Jacobs
ae3c7a7aab Made it possible to drop null placeholders from array output.
This can be used when it's clear that the consumer is able to deal with
this, as web browsers are. Thanks to Yatin Chawathe for the patch.
2012-03-12 04:53:57 +00:00
Aaron Jacobs
f572e8e42e Added an exit() to JSON_FAIL_MESSAGE to fix "no return" errors. 2012-01-08 23:49:55 +00:00
Aaron Jacobs
2b853c4067 Got rid of several unnecessary includes of <iostream>.
Including <iostream> causes the file to be polluted with a static
initializer for the __ioinit symbol. This can harm binary startup time.
For more info, see here:

    http://neugierig.org/software/chromium/notes/2011/08/static-initializers.html
2011-12-22 03:18:24 +00:00
Aaron Jacobs
7c507d7eba Made JSON_USE_EXCEPTION's value in config.h a default that can be overridden.
This allows users to override it with their compiler invocation. For example:

    g++ -D JSON_USE_EXCEPTION=0 ...
2011-09-14 08:41:37 +00:00
Christopher Dunn
c3763f55da Updated bug-fix list. 2011-06-24 21:15:30 +00:00
Christopher Dunn
3b3540d9ef bug#2407932: strpbrk() could fail for NULL pointer. 2011-06-22 21:04:41 +00:00
Christopher Dunn
9d317c3794 bug#3306345: minor typo in Path::resolve() -- missing bang. 2011-06-22 08:30:21 +00:00
Christopher Dunn
03288e8eb6 (bug#3314841) Fixed JSON_IS_AMALGAMATION. Using os.path for OSX filename compatibility. 2011-06-22 00:43:31 +00:00
Christopher Dunn
c9f91dd929 More missing constructor initializers found by Coverity. 2011-06-21 23:02:06 +00:00
Christopher Dunn
2ba3bc3252 Another simple addition for constructor initialization, PathArgument. 2011-06-21 22:08:49 +00:00
Christopher Dunn
ac5df77bbc Simple changes to Reader initialization, from Chromium folks. (I do not think this was submitted as a bug.) 2011-06-21 21:56:54 +00:00
Christopher Dunn
468564b3fe More eol changes. 2011-06-21 21:53:02 +00:00
Christopher Dunn
dc0f736f59 Switched CRLF to LF in repo, and added svn:eol-style native. I might have missed a few files though. Just committing what I have so far. 2011-06-21 21:18:49 +00:00
Christopher Dunn
139da63aef Just testing whether I can still commit changes. I cannot tell my access-level from the sf project page. 2011-06-21 20:34:40 +00:00
Baptiste Lepilleur
d496e044b1 Fixed unit tests execution on MSVC 6 by removing usage of std::numeric_limits. It was returning 0 value in some max cases. Fixed Value::asFloat() to use integerToDouble(). 2011-05-27 08:12:41 +00:00
Baptiste Lepilleur
f587e6a420 Fixed compilation issues with MSVC 6: replace usage of ostringstream with valueToString to support 64 bits integer and high precision floating point conversion to string. Replace usage of ULL and LL literal with UInt64(expr) and Int64(expr). Introduced helper function uint64ToDouble() to work-around missing conversion. Unit tests do not pass yet. 2011-05-26 22:55:24 +00:00
Baptiste Lepilleur
f0b24e705f Fixed MSVS 2003, 2005 and 2008 tests execution by normalizing floating-point string representation using helper normalizeFloatingPointStr(). 2011-05-26 20:14:32 +00:00
Baptiste Lepilleur
e807a7640e Fixed unit test failure on IBM AIX xlC by hard-coding the maxUInt64AsDouble as double constant instead of relying on double(Value::maxUInt64) which produces an incorrect value. 2011-05-26 17:14:26 +00:00
Baptiste Lepilleur
d3cd9a7fc5 - Fixed unit test compilation on MSVS 2003, 2005 and 2008.
- Worked-around unit test failure with MSVS* by "forcing" all floating-point numbers to be loaded from memory instead of FPU registers.
2011-05-26 07:32:36 +00:00
Aaron Jacobs
a2fb7fb918 Fixed some test bugs that show up when 64-bit mode is disabled. 2011-05-26 06:58:52 +00:00
Aaron Jacobs
4b819c2309 Added a few test cases that Google is using internally for patches made
in the past.
2011-05-26 06:58:14 +00:00
Aaron Jacobs
c649badb95 Another round of attempting to fix VC++ errors... 2011-05-26 03:44:02 +00:00
Aaron Jacobs
a9eb1eccc0 Fixed more default cases. 2011-05-26 03:32:11 +00:00
Aaron Jacobs
6ffff91c54 Got rid of some unreachable code. 2011-05-26 03:27:44 +00:00
Aaron Jacobs
acdefb0869 Fixed a double -> float compilation warning/error. 2011-05-26 03:04:01 +00:00
Aaron Jacobs
c025697ea5 Reworked the type conversion system again, so that:A
*  isFoo methods determine exact representability.
 *  asFoo methods cause casting when safe.
 *  isConvertibleTo indicates whether casting is safe.

See NEWS.txt for details.
2011-05-26 02:46:28 +00:00
Aaron Jacobs
b0ec41c3e3 Made the unit test's output more readable, adding to jsontest's
capabilities (and simplifying its implementation) in the process.
2011-05-26 00:30:39 +00:00
Aaron Jacobs
2a2b5cf3ad Made jsontest work with 64-bit integers, and fixed an error. 2011-05-26 00:12:48 +00:00
Aaron Jacobs
b6620e2801 Removed some out of date TODOs. 2011-05-25 23:26:58 +00:00
Aaron Jacobs
ccde848fd1 Fixed test failures with 64-bit support disabled. 2011-05-25 05:53:59 +00:00
Aaron Jacobs
e082248001 Fixed a 'comparison between signed and unsigned' error. 2011-05-25 05:50:13 +00:00
Aaron Jacobs
7b5edd9859 Added line breaks to make error messages easier to read. 2011-05-25 04:59:57 +00:00
Aaron Jacobs
e91a68cb9e Fixed a compilation warning/error. 2011-05-25 04:34:57 +00:00
Aaron Jacobs
1b138e8544 Gave a more consistent behavior to the Value::isFoo methods. See
NEWS.txt for more details.
2011-05-25 04:19:17 +00:00
Aaron Jacobs
4f081b50e6 Fixed bugs in asInt64 and asUInt64. 2011-05-25 03:16:49 +00:00
Aaron Jacobs
3c9fdeb859 Added tests for default numeric values. 2011-05-25 02:54:11 +00:00
Aaron Jacobs
4b79fd1a00 Fixed a test bug. 2011-05-25 01:51:30 +00:00
Aaron Jacobs
e12d84ebaa Made tests more comprehensive. 2011-05-25 01:46:50 +00:00
Aaron Jacobs
078e0d7c37 Gave tests more general names in preparation for making them much more
comprehensive.
2011-05-25 01:24:23 +00:00
Aaron Jacobs
fee49b1a37 Fixed some whitespace. 2011-05-25 01:23:47 +00:00
Aaron Jacobs
22eede44c1 Added tests for 64-bit integers. 2011-05-25 01:23:08 +00:00
Aaron Jacobs
d9ec234fc2 Greatly fleshed out numeric type tests. 2011-05-25 01:04:07 +00:00
Aaron Jacobs
3e5b347f75 Added some missing checks. 2011-05-25 01:03:29 +00:00
Aaron Jacobs
96408a30e1 Renamed test cases to make more sense with the upcoming new behavior of
isFoo methods.
2011-05-25 00:39:55 +00:00
Aaron Jacobs
1d648f089a Fixed a whitespace problem. 2011-05-25 00:39:17 +00:00
Aaron Jacobs
f40c880585 Fixed a "comparison between signed and unsigned" warning/error. 2011-05-24 23:08:59 +00:00
Aaron Jacobs
39ba2dbea9 Added a .gitignore file, for ease of use with git-svn. 2011-05-24 23:05:56 +00:00
Aaron Jacobs
a761530f14 Fixed a missing include error. 2011-05-24 06:27:36 +00:00
Aaron Jacobs
ae9ffb5443 Fixed a parsing bug in decodeNumber, updating the failing test cases to be
correct in the process. (The test cases incorrectly used exact integers instead
of scientific notation.)
2011-05-24 03:59:24 +00:00
Aaron Jacobs
e656c5fa2d Added some test cases that catch a parsing bug. 2011-05-24 03:19:50 +00:00
Aaron Jacobs
f1053e7acb Fixed a bunch of compilation errors when JSON_HAS_INT64 is set. 2011-05-24 03:18:02 +00:00
Aaron Jacobs
e3d0eca9f4 Centralized assertion macros and made them obey JSON_USE_EXCEPTION. 2011-05-24 01:03:22 +00:00
Aaron Jacobs
a77a803c85 Made two security fixes. 2011-05-24 00:43:59 +00:00
Aaron Jacobs
785ba2675d Updated a cast to use a more appropriate type. 2011-05-24 00:43:30 +00:00
Aaron Jacobs
3b556ec633 Fixed constructor initializer list order warnings/errors. 2011-05-24 00:42:58 +00:00
Aaron Jacobs
5fb0f09cbb Removed an unused typedef. 2011-05-24 00:42:15 +00:00
Aaron Jacobs
73911f2e33 Fixed a hard to debug crash on OS X related to sscanf format strings.
See here for more info:
    http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
2011-05-24 00:41:12 +00:00
Baptiste Lepilleur
d21c256fae Released 0.6.0-rc2 2011-05-02 22:07:18 +00:00
Baptiste Lepilleur
72c406b550 Release 0.6.0-rc2 2011-05-02 21:30:42 +00:00
Baptiste Lepilleur
eadc478e50 Fixed typo: amalga*ma*te. Replaced macro JSON_IS_AMALGATED with JSON_IS_AMALGAMATION 2011-05-02 21:09:30 +00:00
Baptiste Lepilleur
1837a1c508 Value::compare() is now const and has an actual implementation with unit tests. 2011-05-02 20:11:48 +00:00
Baptiste Lepilleur
e3cc0f004b Untabified some sources 2011-05-02 18:41:01 +00:00
117 changed files with 13365 additions and 8735 deletions

47
.clang-format Normal file
View File

@@ -0,0 +1,47 @@
---
# BasedOnStyle: LLVM
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: false
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
DerivePointerBinding: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 60
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerBindsToType: true
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: false
Standard: Cpp03
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
IndentFunctionDeclarationAfterType: false
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterControlStatementKeyword: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
...

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
/build/
*.pyc
*.swp
*.actual
*.actual-rewrite
*.process-output
*.rewrite
/bin/
/buildscons/
/libs/
/doc/doxyfile
/dist/
/include/json/version.h

18
.travis.yml Normal file
View File

@@ -0,0 +1,18 @@
# Build matrix / environment variable are explained on:
# http://about.travis-ci.org/docs/user/build-configuration/
# This file can be validated on:
# http://lint.travis-ci.org/
before_install: sudo apt-get install cmake
language: cpp
compiler:
- gcc
- clang
script: cmake -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIBRARY -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
env:
matrix:
- SHARED_LIBRARY=ON BUILD_TYPE=release VERBOSE_MAKE=false
- SHARED_LIBRARY=OFF BUILD_TYPE=release VERBOSE_MAKE=false
- SHARED_LIBRARY=OFF BUILD_TYPE=debug VERBOSE VERBOSE_MAKE=true
notifications:
email:
- aaronjjacobs@gmail.com

117
CMakeLists.txt Normal file
View File

@@ -0,0 +1,117 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5)
PROJECT(jsoncpp)
ENABLE_TESTING()
OPTION(JSONCPP_WITH_TESTS "Compile and run JsonCpp test executables" ON)
OPTION(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
OPTION(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occurs" OFF)
OPTION(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
OPTION(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" OFF)
# Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix
IF(NOT WIN32)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)
ENDIF(NOT WIN32)
SET(RUNTIME_INSTALL_DIR bin
CACHE PATH "Install dir for executables and dlls")
SET(ARCHIVE_INSTALL_DIR lib
CACHE PATH "Install dir for static libraries")
SET(LIBRARY_INSTALL_DIR lib
CACHE PATH "Install dir for shared libraries")
SET(INCLUDE_INSTALL_DIR include
CACHE PATH "Install dir for headers")
SET(PACKAGE_INSTALL_DIR lib/cmake
CACHE PATH "Install dir for cmake package config files")
MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PACKAGE_INSTALL_DIR )
# This ensures shared DLL are in the same dir as executable on Windows.
# Put all executables / libraries are in a project global directory.
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
CACHE PATH "Single directory for all static libraries.")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
CACHE PATH "Single directory for all dynamic libraries on Unix.")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
CACHE PATH "Single directory for all executable and dynamic libraries on Windows.")
MARK_AS_ADVANCED( CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY )
# Set variable named ${VAR_NAME} to value ${VALUE}
FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
ENDFUNCTION(set_using_dynamic_name)
# Extract major, minor, patch from version text
# Parse a version string "X.Y.Z" and outputs
# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH.
# If parse succeeds then ${OUPUT_PREFIX}_FOUND is TRUE.
MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX)
SET(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?")
IF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
STRING(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT})
LIST(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR)
LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR)
LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH)
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
ENDMACRO(jsoncpp_parse_version)
# Read out version from "version" file
FILE(STRINGS "version" JSONCPP_VERSION)
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
IF(NOT JSONCPP_VERSION_FOUND)
MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
ENDIF(NOT JSONCPP_VERSION_FOUND)
MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
# File version.h is only regenerated on CMake configure step
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in"
"${PROJECT_SOURCE_DIR}/include/json/version.h" )
macro(UseCompilationWarningAsError)
if ( MSVC )
# Only enabled in debug because some old versions of VS STL generate
# warnings when compiled in release configuration.
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
endif( MSVC )
endmacro()
# Include our configuration header
INCLUDE_DIRECTORIES( ${jsoncpp_SOURCE_DIR}/include )
if ( MSVC )
# Only enabled in debug because some old versions of VS STL generate
# unreachable code warning when compiled in release configuration.
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
endif( MSVC )
IF(JSONCPP_WITH_WARNING_AS_ERROR)
UseCompilationWarningAsError()
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR)
IF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
CONFIGURE_FILE(
"pkg-config/jsoncpp.pc.in"
"pkg-config/jsoncpp.pc"
@ONLY)
INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc"
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
IF(JSONCPP_WITH_CMAKE_PACKAGE)
INSTALL(EXPORT jsoncpp
DESTINATION ${PACKAGE_INSTALL_DIR}/jsoncpp
FILE jsoncppConfig.cmake)
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
# Build the different applications
ADD_SUBDIRECTORY( src )
#install the includes
ADD_SUBDIRECTORY( include )

View File

@@ -1,3 +1,69 @@
New in SVN
----------
* Updated the type system's behavior, in order to better support backwards
compatibility with code that was written before 64-bit integer support was
introduced. Here's how it works now:
* isInt, isInt64, isUInt, and isUInt64 return true if and only if the
value can be exactly represented as that type. In particular, a value
constructed with a double like 17.0 will now return true for all of
these methods.
* isDouble and isFloat now return true for all numeric values, since all
numeric values can be converted to a double or float without
truncation. Note however that the conversion may not be exact -- for
example, doubles cannot exactly represent all integers above 2^53 + 1.
* isBool, isNull, isString, isArray, and isObject now return true if and
only if the value is of that type.
* isConvertibleTo(fooValue) indicates that it is safe to call asFoo.
(For each type foo, isFoo always implies isConvertibleTo(fooValue).)
asFoo returns an approximate or exact representation as appropriate.
For example, a double value may be truncated when asInt is called.
* For backwards compatibility with old code, isConvertibleTo(intValue)
may return false even if type() == intValue. This is because the value
may have been constructed with a 64-bit integer larger than maxInt,
and calling asInt() would cause an exception. If you're writing new
code, use isInt64 to find out whether the value is exactly
representable using an Int64, or asDouble() combined with minInt64 and
maxInt64 to figure out whether it is approximately representable.
* Value
- Patch #10: BOOST_FOREACH compatibility. Made Json::iterator more
standard compliant, added missing iterator_category and value_type
typedefs (contribued by Robert A. Iannucci).
* Compilation
- New CMake based build system. Based in part on contribution from
Igor Okulist and Damien Buhl (Patch #14).
- New header json/version.h now contains version number macros
(JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH
and JSONCPP_VERSION_HEXA).
- Patch #11: added missing JSON_API on some classes causing link issues
when building as a dynamic library on Windows
(contributed by Francis Bolduc).
- Visual Studio DLL: suppressed warning "C4251: <data member>: <type>
needs to have dll-interface to be used by..." via pragma push/pop
in json-cpp headers.
- Added Travis CI intregration: https://travis-ci.org/blep/jsoncpp-mirror
* Bug fixes
- Patch #15: Copy constructor does not initialize allocated_ for stringValue
(contributed by rmongia).
- Patch #16: Missing field copy in Json::Value::iterator causing infinite
loop when using experimental internal map (#define JSON_VALUE_USE_INTERNAL_MAP)
(contributed by Ming-Lin Kao).
New in JsonCpp 0.6.0: New in JsonCpp 0.6.0:
--------------------- ---------------------
@@ -88,11 +154,19 @@
length of 32 characters. length of 32 characters.
- Fixed Value::operator <= implementation (had the semantic of operator >=). - Fixed Value::operator <= implementation (had the semantic of operator >=).
Found when addigin unit tests for comparison operators. Found when adding unit tests for comparison operators.
- Value::compare() is now const and has an actual implementation with - Value::compare() is now const and has an actual implementation with
unit tests. unit tests.
- Bug #2407932: strpbrk() can fail for NULL pointer.
- Bug #3306345: Fixed minor typo in Path::resolve().
- Bug #3314841/#3306896: errors in amalgamate.py
- Fixed some Coverity warnings and line-endings.
* License * License
- See file LICENSE for details. Basically JsonCpp is now licensed under - See file LICENSE for details. Basically JsonCpp is now licensed under

224
README.md Normal file
View File

@@ -0,0 +1,224 @@
Introduction
------------
[JSON][json-org] is a lightweight data-interchange format. It can represent
numbers, strings, ordered sequences of values, and collections of name/value
pairs.
[json-org]: http://json.org/
JsonCpp is a C++ library that allows manipulating JSON values, including
serialization and deserialization to and from strings. It can also preserve
existing comment in unserialization/serialization steps, making it a convenient
format to store user input files.
## A note on backward-compatibility
Very soon, we are switching to C++11 only. For older compilers, try the `pre-C++11` branch.
Using JsonCpp in your project
-----------------------------
The recommended approach to integrating JsonCpp in your project is to build
the amalgamated source (a single `.cpp` file) with your own build system. This
ensures consistency of compilation flags and ABI compatibility. See the section
"Generating amalgamated source and header" for instructions.
The `include/` should be added to your compiler include path. Jsoncpp headers
should be included as follow:
#include <json/json.h>
If JsonCpp was build as a dynamic library on Windows, then your project needs to
define the macro `JSON_DLL`.
Building and testing with new CMake
-----------------------------------
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
Linux system as package. On Ubuntu:
sudo apt-get install cmake
[CMake]: http://www.cmake.org
Note that Python is also required to run the JSON reader/writer tests. If
missing, the build will skip running those tests.
When running CMake, a few parameters are required:
* a build directory where the makefiles/solution are generated. It is also used
to store objects, libraries and executables files.
* the generator to use: makefiles or Visual Studio solution? What version or
Visual Studio, 32 or 64 bits solution?
Steps for generating solution/makefiles using `cmake-gui`:
* Make "source code" point to the source directory.
* Make "where to build the binary" point to the directory to use for the build.
* Click on the "Grouped" check box.
* Review JsonCpp build options (tick `JSONCPP_LIB_BUILD_SHARED` to build as a
dynamic library).
* Click the configure button at the bottom, then the generate button.
* The generated solution/makefiles can be found in the binary directory.
Alternatively, from the command-line on Unix in the source directory:
mkdir -p build/debug
cd build/debug
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
make
Running `cmake -`" will display the list of available generators (passed using
the `-G` option).
By default CMake hides compilation commands. This can be modified by specifying
`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles.
Building and testing with SCons
-------------------------------
**Note:** The SCons-based build system is deprecated. Please use CMake; see the
section above.
JsonCpp can use [Scons][] as a build system. Note that SCons requires Python to
be installed.
[SCons]: http://www.scons.org/
Invoke SCons as follows:
scons platform=$PLATFORM [TARGET]
where `$PLATFORM` may be one of:
* `suncc`: Sun C++ (Solaris)
* `vacpp`: Visual Age C++ (AIX)
* `mingw`
* `msvc6`: Microsoft Visual Studio 6 service pack 5-6
* `msvc70`: Microsoft Visual Studio 2002
* `msvc71`: Microsoft Visual Studio 2003
* `msvc80`: Microsoft Visual Studio 2005
* `msvc90`: Microsoft Visual Studio 2008
* `linux-gcc`: Gnu C++ (linux, also reported to work for Mac OS X)
If you are building with Microsoft Visual Studio 2008, you need to set up the
environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before
running SCons.
Running the tests manually
--------------------------
Note that test can be run using SCons using the `check` target:
scons platform=$PLATFORM check
You need to run tests manually only if you are troubleshooting an issue.
In the instructions below, replace `path/to/jsontest` with the path of the
`jsontest` executable that was compiled on your platform.
cd test
# This will run the Reader/Writer tests
python runjsontests.py path/to/jsontest
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker path/to/jsontest
# This will run the unit tests (mostly Value)
python rununittests.py path/to/test_lib_json
# You can run the tests using valgrind:
python rununittests.py --valgrind path/to/test_lib_json
Building the documentation
--------------------------
Run the Python script `doxybuild.py` from the top directory:
python doxybuild.py --doxygen=$(which doxygen) --open --with-dot
See `doxybuild.py --help` for options.
Generating amalgamated source and header
----------------------------------------
JsonCpp is provided with a script to generate a single header and a single
source file to ease inclusion into an existing project. The amalgamated source
can be generated at any time by running the following command from the
top-directory (this requires Python 2.6):
python amalgamate.py
It is possible to specify header name. See the `-h` option for detail.
By default, the following files are generated:
* `dist/jsoncpp.cpp`: source file that needs to be added to your project.
* `dist/json/json.h`: corresponding header file for use in your project. It is
equivalent to including `json/json.h` in non-amalgamated source. This header
only depends on standard headers.
* `dist/json/json-forwards.h`: header that provides forward declaration of all
JsonCpp types.
The amalgamated sources are generated by concatenating JsonCpp source in the
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
of other headers.
Adding a reader/writer test
---------------------------
To add a test, you need to create two files in test/data:
* a `TESTNAME.json` file, that contains the input document in JSON format.
* a `TESTNAME.expected` file, that contains a flatened representation of the
input document.
The `TESTNAME.expected` file format is as follows:
* each line represents a JSON element of the element tree represented by the
input document.
* each line has two parts: the path to access the element separated from the
element value by `=`. Array and object values are always empty (i.e.
represented by either `[]` or `{}`).
* element path: `.` represents the root element, and is used to separate object
members. `[N]` is used to specify the value of an array element at index `N`.
See the examples `test_complex_01.json` and `test_complex_01.expected` to better
understand element paths.
Understanding reader/writer test output
---------------------------------------
When a test is run, output files are generated beside the input test files.
Below is a short description of the content of each file:
* `test_complex_01.json`: input JSON document.
* `test_complex_01.expected`: flattened JSON element tree used to check if
parsing was corrected.
* `test_complex_01.actual`: flattened JSON element tree produced by `jsontest`
from reading `test_complex_01.json`.
* `test_complex_01.rewrite`: JSON document written by `jsontest` using the
`Json::Value` parsed from `test_complex_01.json` and serialized using
`Json::StyledWritter`.
* `test_complex_01.actual-rewrite`: flattened JSON element tree produced by
`jsontest` from reading `test_complex_01.rewrite`.
* `test_complex_01.process-output`: `jsontest` output, typically useful for
understanding parsing errors.
License
-------
See the `LICENSE` file for details. In summary, JsonCpp is licensed under the
MIT license, or public domain if desired and recognized in your jurisdiction.

View File

@@ -1,172 +0,0 @@
* Introduction:
=============
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of
value, and a collection of name/value pairs.
JsonCpp (http://jsoncpp.sourceforge.net/) is a simple API to manipulate
JSON value, handle serialization and unserialization to string.
It can also preserve existing comment in unserialization/serialization steps,
making it a convenient format to store user input files.
Unserialization parsing is user friendly and provides precise error reports.
* Building/Testing:
=================
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
python to be installed (http://www.python.org).
You download scons-local distribution from the following url:
http://sourceforge.net/projects/scons/files/scons-local/1.2.0/
Unzip it in the directory where you found this README file. scons.py Should be
at the same level as README.
python scons.py platform=PLTFRM [TARGET]
where PLTFRM may be one of:
suncc Sun C++ (Solaris)
vacpp Visual Age C++ (AIX)
mingw
msvc6 Microsoft Visual Studio 6 service pack 5-6
msvc70 Microsoft Visual Studio 2002
msvc71 Microsoft Visual Studio 2003
msvc80 Microsoft Visual Studio 2005
msvc90 Microsoft Visual Studio 2008
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
Notes: if you are building with Microsoft Visual Studio 2008, you need to
setup the environment by running vcvars32.bat (e.g. MSVC 2008 command prompt)
before running scons.
Adding platform is fairly simple. You need to change the Sconstruct file
to do so.
and TARGET may be:
check: build library and run unit tests.
* Running the test manually:
==========================
Notes that test can be run by scons using the 'check' target (see above).
You need to run test manually only if you are troubleshooting an issue.
In the instruction below, replace "path to jsontest.exe" with the path
of the 'jsontest' executable that was compiled on your platform.
cd test
# This will run the Reader/Writer tests
python runjsontests.py "path to jsontest.exe"
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker "path to jsontest.exe"
# This will run the unit tests (mostly Value)
python rununittests.py "path to test_lib_json.exe"
You can run the tests using valgrind:
python rununittests.py --valgrind "path to test_lib_json.exe"
* Building the documentation:
===========================
Run the python script doxybuild.py from the top directory:
python doxybuild.py --open --with-dot
See doxybuild.py --help for options.
Notes that the documentation is also available for download as a tarball.
The documentation of the latest release is available online at:
http://jsoncpp.sourceforge.net/
* Generating amalgamated source and header
========================================
JsonCpp is provided with a script to generate a single header and a single
source file to ease inclusion in an existing project.
The amalgamated source can be generated at any time by running the following
command from the top-directory (requires python 2.6):
python amalgamate.py
It is possible to specify header name. See -h options for detail. By default,
the following files are generated:
- dist/jsoncpp.cpp: source file that need to be added to your project
- dist/json/json.h: header file corresponding to use in your project. It is
equivalent to including json/json.h in non-amalgamated source. This header
only depends on standard headers.
- dist/json/json-forwards.h: header the provides forward declaration
of all JsonCpp types. This typically what should be included in headers to
speed-up compilation.
The amalgamated sources are generated by concatenating JsonCpp source in the
correct order and defining macro JSON_IS_AMALGAMATION to prevent inclusion
of other headers.
* Using json-cpp in your project:
===============================
include/ should be added to your compiler include path. jsoncpp headers
should be included as follow:
#include <json/json.h>
* Adding a reader/writer test:
============================
To add a test, you need to create two files in test/data:
- a TESTNAME.json file, that contains the input document in JSON format.
- a TESTNAME.expected file, that contains a flatened representation of
the input document.
TESTNAME.expected file format:
- each line represents a JSON element of the element tree represented
by the input document.
- each line has two parts: the path to access the element separated from
the element value by '='. Array and object values are always empty
(e.g. represented by either [] or {}).
- element path: '.' represented the root element, and is used to separate
object members. [N] is used to specify the value of an array element
at index N.
See test_complex_01.json and test_complex_01.expected to better understand
element path.
* Understanding reader/writer test output:
========================================
When a test is run, output files are generated aside the input test files.
Below is a short description of the content of each file:
- test_complex_01.json: input JSON document
- test_complex_01.expected: flattened JSON element tree used to check if
parsing was corrected.
- test_complex_01.actual: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.json
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
Json::Value parsed from test_complex_01.json and serialized using
Json::StyledWritter.
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.rewrite.
test_complex_01.process-output: jsontest.exe output, typically useful to
understand parsing error.
* License
=======
See file LICENSE for details. Basically JsonCpp is licensed under
MIT license, or public domain if desired and recognized in your jurisdiction.

View File

@@ -119,7 +119,7 @@ elif platform == 'mingw':
env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] ) env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] )
elif platform.startswith('linux-gcc'): elif platform.startswith('linux-gcc'):
env.Tool( 'default' ) env.Tool( 'default' )
env.Append( LIBS = ['pthread'], CCFLAGS = "-Wall" ) env.Append( LIBS = ['pthread'], CCFLAGS = os.environ.get("CXXFLAGS", "-Wall"), LINKFLAGS=os.environ.get("LDFLAGS", "") )
env['SHARED_LIB_ENABLED'] = True env['SHARED_LIB_ENABLED'] = True
else: else:
print "UNSUPPORTED PLATFORM." print "UNSUPPORTED PLATFORM."

View File

@@ -15,36 +15,36 @@ class AmalgamationFile:
self.blocks = [] self.blocks = []
def add_text( self, text ): def add_text( self, text ):
if not text.endswith( '\n' ): if not text.endswith( "\n" ):
text += '\n' text += "\n"
self.blocks.append( text ) self.blocks.append( text )
def add_file( self, relative_input_path, wrap_in_comment=False ): def add_file( self, relative_input_path, wrap_in_comment=False ):
def add_marker( prefix ): def add_marker( prefix ):
self.add_text( '' ) self.add_text( "" )
self.add_text( '// ' + '/'*70 ) self.add_text( "// " + "/"*70 )
self.add_text( '// %s of content of file: %s' % (prefix, relative_input_path.replace('\\','/')) ) self.add_text( "// %s of content of file: %s" % (prefix, relative_input_path.replace("\\","/")) )
self.add_text( '// ' + '/'*70 ) self.add_text( "// " + "/"*70 )
self.add_text( '' ) self.add_text( "" )
add_marker( 'Beginning' ) add_marker( "Beginning" )
f = open( os.path.join( self.top_dir, relative_input_path ), 'rt' ) f = open( os.path.join( self.top_dir, relative_input_path ), "rt" )
content = f.read() content = f.read()
if wrap_in_comment: if wrap_in_comment:
content = '/*\n' + content + '\n*/' content = "/*\n" + content + "\n*/"
self.add_text( content ) self.add_text( content )
f.close() f.close()
add_marker( 'End' ) add_marker( "End" )
self.add_text( '\n\n\n\n' ) self.add_text( "\n\n\n\n" )
def get_value( self ): def get_value( self ):
return ''.join( self.blocks ).replace('\r\n','\n') return "".join( self.blocks ).replace("\r\n","\n")
def write_to( self, output_path ): def write_to( self, output_path ):
output_dir = os.path.dirname( output_path ) output_dir = os.path.dirname( output_path )
if output_dir and not os.path.isdir( output_dir ): if output_dir and not os.path.isdir( output_dir ):
os.makedirs( output_dir ) os.makedirs( output_dir )
f = open( output_path, 'wb' ) f = open( output_path, "wb" )
f.write( self.get_value() ) f.write( str.encode(self.get_value(), 'UTF-8') )
f.close() f.close()
def amalgamate_source( source_top_dir=None, def amalgamate_source( source_top_dir=None,
@@ -56,66 +56,69 @@ def amalgamate_source( source_top_dir=None,
target_source_path: output .cpp path target_source_path: output .cpp path
header_include_path: generated header path relative to target_source_path. header_include_path: generated header path relative to target_source_path.
""" """
print 'Amalgating header...' print("Amalgating header...")
header = AmalgamationFile( source_top_dir ) header = AmalgamationFile( source_top_dir )
header.add_text( '/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).' ) header.add_text( "/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/)." )
header.add_text( '/// It is intented to be used with #include <%s>' % header_include_path ) header.add_text( "/// It is intented to be used with #include <%s>" % header_include_path )
header.add_file( 'LICENSE', wrap_in_comment=True ) header.add_file( "LICENSE", wrap_in_comment=True )
header.add_text( '#ifndef JSON_AMALGATED_H_INCLUDED' ) header.add_text( "#ifndef JSON_AMALGATED_H_INCLUDED" )
header.add_text( '# define JSON_AMALGATED_H_INCLUDED' ) header.add_text( "# define JSON_AMALGATED_H_INCLUDED" )
header.add_text( '/// If defined, indicates that the source file is amalgated' ) header.add_text( "/// If defined, indicates that the source file is amalgated" )
header.add_text( '/// to prevent private header inclusion.' ) header.add_text( "/// to prevent private header inclusion." )
header.add_text( '#define JSON_IS_AMALGATED' ) header.add_text( "#define JSON_IS_AMALGAMATION" )
header.add_file( 'include/json/config.h' ) header.add_file( "include/json/version.h" )
header.add_file( 'include/json/forwards.h' ) header.add_file( "include/json/config.h" )
header.add_file( 'include/json/features.h' ) header.add_file( "include/json/forwards.h" )
header.add_file( 'include/json/value.h' ) header.add_file( "include/json/features.h" )
header.add_file( 'include/json/reader.h' ) header.add_file( "include/json/value.h" )
header.add_file( 'include/json/writer.h' ) header.add_file( "include/json/reader.h" )
header.add_text( '#endif //ifndef JSON_AMALGATED_H_INCLUDED' ) header.add_file( "include/json/writer.h" )
header.add_file( "include/json/assertions.h" )
header.add_text( "#endif //ifndef JSON_AMALGATED_H_INCLUDED" )
target_header_path = os.path.join( os.path.dirname(target_source_path), header_include_path ) target_header_path = os.path.join( os.path.dirname(target_source_path), header_include_path )
print 'Writing amalgated header to %r' % target_header_path print("Writing amalgated header to %r" % target_header_path)
header.write_to( target_header_path ) header.write_to( target_header_path )
base, ext = os.path.splitext( header_include_path ) base, ext = os.path.splitext( header_include_path )
forward_header_include_path = base + '-forwards' + ext forward_header_include_path = base + "-forwards" + ext
print 'Amalgating forward header...' print("Amalgating forward header...")
header = AmalgamationFile( source_top_dir ) header = AmalgamationFile( source_top_dir )
header.add_text( '/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).' ) header.add_text( "/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/)." )
header.add_text( '/// It is intented to be used with #include <%s>' % forward_header_include_path ) header.add_text( "/// It is intented to be used with #include <%s>" % forward_header_include_path )
header.add_text( '/// This header provides forward declaration for all JsonCpp types.' ) header.add_text( "/// This header provides forward declaration for all JsonCpp types." )
header.add_file( 'LICENSE', wrap_in_comment=True ) header.add_file( "LICENSE", wrap_in_comment=True )
header.add_text( '#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED' ) header.add_text( "#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" )
header.add_text( '# define JSON_FORWARD_AMALGATED_H_INCLUDED' ) header.add_text( "# define JSON_FORWARD_AMALGATED_H_INCLUDED" )
header.add_text( '/// If defined, indicates that the source file is amalgated' ) header.add_text( "/// If defined, indicates that the source file is amalgated" )
header.add_text( '/// to prevent private header inclusion.' ) header.add_text( "/// to prevent private header inclusion." )
header.add_text( '#define JSON_IS_AMALGATED' ) header.add_text( "#define JSON_IS_AMALGAMATION" )
header.add_file( 'include/json/config.h' ) header.add_file( "include/json/config.h" )
header.add_file( 'include/json/forwards.h' ) header.add_file( "include/json/forwards.h" )
header.add_text( '#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED' ) header.add_text( "#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" )
target_forward_header_path = os.path.join( os.path.dirname(target_source_path), target_forward_header_path = os.path.join( os.path.dirname(target_source_path),
forward_header_include_path ) forward_header_include_path )
print 'Writing amalgated forward header to %r' % target_forward_header_path print("Writing amalgated forward header to %r" % target_forward_header_path)
header.write_to( target_forward_header_path ) header.write_to( target_forward_header_path )
print 'Amalgating source...' print("Amalgating source...")
source = AmalgamationFile( source_top_dir ) source = AmalgamationFile( source_top_dir )
source.add_text( '/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).' ) source.add_text( "/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/)." )
source.add_text( '/// It is intented to be used with #include <%s>' % header_include_path ) source.add_text( "/// It is intented to be used with #include <%s>" % header_include_path )
source.add_file( 'LICENSE', wrap_in_comment=True ) source.add_file( "LICENSE", wrap_in_comment=True )
source.add_text( '' ) source.add_text( "" )
source.add_text( '#include <%s>' % header_include_path ) source.add_text( "#include <%s>" % header_include_path )
source.add_text( '' ) source.add_text( "" )
source.add_file( 'src/lib_json\json_tool.h' ) lib_json = "src/lib_json"
source.add_file( 'src/lib_json\json_reader.cpp' ) source.add_file( os.path.join(lib_json, "json_tool.h") )
source.add_file( 'src/lib_json\json_batchallocator.h' ) source.add_file( os.path.join(lib_json, "json_reader.cpp") )
source.add_file( 'src/lib_json\json_valueiterator.inl' ) source.add_file( os.path.join(lib_json, "json_batchallocator.h") )
source.add_file( 'src/lib_json\json_value.cpp' ) source.add_file( os.path.join(lib_json, "json_valueiterator.inl") )
source.add_file( 'src/lib_json\json_writer.cpp' ) source.add_file( os.path.join(lib_json, "json_value.cpp") )
source.add_file( os.path.join(lib_json, "json_writer.cpp") )
print 'Writing amalgated source to %r' % target_source_path print("Writing amalgated source to %r" % target_source_path)
source.write_to( target_source_path ) source.write_to( target_source_path )
def main(): def main():
@@ -125,11 +128,11 @@ Generate a single amalgated source and header file from the sources.
from optparse import OptionParser from optparse import OptionParser
parser = OptionParser(usage=usage) parser = OptionParser(usage=usage)
parser.allow_interspersed_args = False parser.allow_interspersed_args = False
parser.add_option('-s', '--source', dest="target_source_path", action='store', default='dist/jsoncpp.cpp', parser.add_option("-s", "--source", dest="target_source_path", action="store", default="dist/jsoncpp.cpp",
help="""Output .cpp source path. [Default: %default]""") help="""Output .cpp source path. [Default: %default]""")
parser.add_option('-i', '--include', dest="header_include_path", action='store', default='json/json.h', parser.add_option("-i", "--include", dest="header_include_path", action="store", default="json/json.h",
help="""Header include path. Used to include the header from the amalgated source file. [Default: %default]""") help="""Header include path. Used to include the header from the amalgated source file. [Default: %default]""")
parser.add_option('-t', '--top-dir', dest="top_dir", action='store', default=os.getcwd(), parser.add_option("-t", "--top-dir", dest="top_dir", action="store", default=os.getcwd(),
help="""Source top-directory. [Default: %default]""") help="""Source top-directory. [Default: %default]""")
parser.enable_interspersed_args() parser.enable_interspersed_args()
options, args = parser.parse_args() options, args = parser.parse_args()
@@ -138,10 +141,10 @@ Generate a single amalgated source and header file from the sources.
target_source_path=options.target_source_path, target_source_path=options.target_source_path,
header_include_path=options.header_include_path ) header_include_path=options.header_include_path )
if msg: if msg:
sys.stderr.write( msg + '\n' ) sys.stderr.write( msg + "\n" )
sys.exit( 1 ) sys.exit( 1 )
else: else:
print 'Source succesfully amalagated' print("Source succesfully amalagated")
if __name__ == '__main__': if __name__ == "__main__":
main() main()

14
dev.makefile Normal file
View File

@@ -0,0 +1,14 @@
all: build test-amalgamate
build:
mkdir -p build/debug
cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../..
make -C build/debug
# Currently, this depends on include/json/version.h generated
# by cmake.
test-amalgamate: build
python2.7 amalgamate.py
python3.4 amalgamate.py
.PHONY: build

33
devtools/agent_vmw7.json Normal file
View File

@@ -0,0 +1,33 @@
{
"cmake_variants" : [
{"name": "generator",
"generators": [
{"generator": [
"Visual Studio 7 .NET 2003",
"Visual Studio 9 2008",
"Visual Studio 9 2008 Win64",
"Visual Studio 10",
"Visual Studio 10 Win64",
"Visual Studio 11",
"Visual Studio 11 Win64"
]
},
{"generator": ["MinGW Makefiles"],
"env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}]
}
]
},
{"name": "shared_dll",
"variables": [
["JSONCPP_LIB_BUILD_SHARED=true"],
["JSONCPP_LIB_BUILD_SHARED=false"]
]
},
{"name": "build_type",
"build_types": [
"debug",
"release"
]
}
]
}

26
devtools/agent_vmxp.json Normal file
View File

@@ -0,0 +1,26 @@
{
"cmake_variants" : [
{"name": "generator",
"generators": [
{"generator": [
"Visual Studio 6",
"Visual Studio 7",
"Visual Studio 8 2005"
]
}
]
},
{"name": "shared_dll",
"variables": [
["JSONCPP_LIB_BUILD_SHARED=true"],
["JSONCPP_LIB_BUILD_SHARED=false"]
]
},
{"name": "build_type",
"build_types": [
"debug",
"release"
]
}
]
}

View File

@@ -2,6 +2,7 @@
# encoding: utf-8 # encoding: utf-8
# Baptiste Lepilleur, 2009 # Baptiste Lepilleur, 2009
from __future__ import print_function
from dircache import listdir from dircache import listdir
import re import re
import fnmatch import fnmatch
@@ -190,12 +191,12 @@ if __name__ == "__main__":
test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) ) test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) )
for ant_pattern, accepted_matches, rejected_matches in test_cases: for ant_pattern, accepted_matches, rejected_matches in test_cases:
rex = ant_pattern_to_re( ant_pattern ) rex = ant_pattern_to_re( ant_pattern )
print 'ant_pattern:', ant_pattern, ' => ', rex.pattern print('ant_pattern:', ant_pattern, ' => ', rex.pattern)
for accepted_match in accepted_matches: for accepted_match in accepted_matches:
print 'Accepted?:', accepted_match print('Accepted?:', accepted_match)
self.assert_( rex.match( accepted_match ) is not None ) self.assertTrue( rex.match( accepted_match ) is not None )
for rejected_match in rejected_matches: for rejected_match in rejected_matches:
print 'Rejected?:', rejected_match print('Rejected?:', rejected_match)
self.assert_( rex.match( rejected_match ) is None ) self.assertTrue( rex.match( rejected_match ) is None )
unittest.main() unittest.main()

281
devtools/batchbuild.py Normal file
View File

@@ -0,0 +1,281 @@
from __future__ import print_function
import collections
import itertools
import json
import os
import os.path
import re
import shutil
import string
import subprocess
import sys
import cgi
class BuildDesc:
def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None):
self.prepend_envs = prepend_envs or [] # [ { "var": "value" } ]
self.variables = variables or []
self.build_type = build_type
self.generator = generator
def merged_with( self, build_desc ):
"""Returns a new BuildDesc by merging field content.
Prefer build_desc fields to self fields for single valued field.
"""
return BuildDesc( self.prepend_envs + build_desc.prepend_envs,
self.variables + build_desc.variables,
build_desc.build_type or self.build_type,
build_desc.generator or self.generator )
def env( self ):
environ = os.environ.copy()
for values_by_name in self.prepend_envs:
for var, value in list(values_by_name.items()):
var = var.upper()
if type(value) is unicode:
value = value.encode( sys.getdefaultencoding() )
if var in environ:
environ[var] = value + os.pathsep + environ[var]
else:
environ[var] = value
return environ
def cmake_args( self ):
args = ["-D%s" % var for var in self.variables]
# skip build type for Visual Studio solution as it cause warning
if self.build_type and 'Visual' not in self.generator:
args.append( "-DCMAKE_BUILD_TYPE=%s" % self.build_type )
if self.generator:
args.extend( ['-G', self.generator] )
return args
def __repr__( self ):
return "BuildDesc( %s, build_type=%s )" % (" ".join( self.cmake_args()), self.build_type)
class BuildData:
def __init__( self, desc, work_dir, source_dir ):
self.desc = desc
self.work_dir = work_dir
self.source_dir = source_dir
self.cmake_log_path = os.path.join( work_dir, 'batchbuild_cmake.log' )
self.build_log_path = os.path.join( work_dir, 'batchbuild_build.log' )
self.cmake_succeeded = False
self.build_succeeded = False
def execute_build(self):
print('Build %s' % self.desc)
self._make_new_work_dir( )
self.cmake_succeeded = self._generate_makefiles( )
if self.cmake_succeeded:
self.build_succeeded = self._build_using_makefiles( )
return self.build_succeeded
def _generate_makefiles(self):
print(' Generating makefiles: ', end=' ')
cmd = ['cmake'] + self.desc.cmake_args( ) + [os.path.abspath( self.source_dir )]
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.cmake_log_path )
print('done' if succeeded else 'FAILED')
return succeeded
def _build_using_makefiles(self):
print(' Building:', end=' ')
cmd = ['cmake', '--build', self.work_dir]
if self.desc.build_type:
cmd += ['--config', self.desc.build_type]
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.build_log_path )
print('done' if succeeded else 'FAILED')
return succeeded
def _execute_build_subprocess(self, cmd, env, log_path):
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.work_dir,
env=env )
stdout, _ = process.communicate( )
succeeded = (process.returncode == 0)
with open( log_path, 'wb' ) as flog:
log = ' '.join( cmd ) + '\n' + stdout + '\nExit code: %r\n' % process.returncode
flog.write( fix_eol( log ) )
return succeeded
def _make_new_work_dir(self):
if os.path.isdir( self.work_dir ):
print(' Removing work directory', self.work_dir)
shutil.rmtree( self.work_dir, ignore_errors=True )
if not os.path.isdir( self.work_dir ):
os.makedirs( self.work_dir )
def fix_eol( stdout ):
"""Fixes wrong EOL produced by cmake --build on Windows (\r\r\n instead of \r\n).
"""
return re.sub( '\r*\n', os.linesep, stdout )
def load_build_variants_from_config( config_path ):
with open( config_path, 'rb' ) as fconfig:
data = json.load( fconfig )
variants = data[ 'cmake_variants' ]
build_descs_by_axis = collections.defaultdict( list )
for axis in variants:
axis_name = axis["name"]
build_descs = []
if "generators" in axis:
for generator_data in axis["generators"]:
for generator in generator_data["generator"]:
build_desc = BuildDesc( generator=generator,
prepend_envs=generator_data.get("env_prepend") )
build_descs.append( build_desc )
elif "variables" in axis:
for variables in axis["variables"]:
build_desc = BuildDesc( variables=variables )
build_descs.append( build_desc )
elif "build_types" in axis:
for build_type in axis["build_types"]:
build_desc = BuildDesc( build_type=build_type )
build_descs.append( build_desc )
build_descs_by_axis[axis_name].extend( build_descs )
return build_descs_by_axis
def generate_build_variants( build_descs_by_axis ):
"""Returns a list of BuildDesc generated for the partial BuildDesc for each axis."""
axis_names = list(build_descs_by_axis.keys())
build_descs = []
for axis_name, axis_build_descs in list(build_descs_by_axis.items()):
if len(build_descs):
# for each existing build_desc and each axis build desc, create a new build_desc
new_build_descs = []
for prototype_build_desc, axis_build_desc in itertools.product( build_descs, axis_build_descs):
new_build_descs.append( prototype_build_desc.merged_with( axis_build_desc ) )
build_descs = new_build_descs
else:
build_descs = axis_build_descs
return build_descs
HTML_TEMPLATE = string.Template('''<html>
<head>
<title>$title</title>
<style type="text/css">
td.failed {background-color:#f08080;}
td.ok {background-color:#c0eec0;}
</style>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>Variables</th>
$th_vars
</tr>
<tr>
<th>Build type</th>
$th_build_types
</tr>
</thead>
<tbody>
$tr_builds
</tbody>
</table>
</body></html>''')
def generate_html_report( html_report_path, builds ):
report_dir = os.path.dirname( html_report_path )
# Vertical axis: generator
# Horizontal: variables, then build_type
builds_by_generator = collections.defaultdict( list )
variables = set()
build_types_by_variable = collections.defaultdict( set )
build_by_pos_key = {} # { (generator, var_key, build_type): build }
for build in builds:
builds_by_generator[build.desc.generator].append( build )
var_key = tuple(sorted(build.desc.variables))
variables.add( var_key )
build_types_by_variable[var_key].add( build.desc.build_type )
pos_key = (build.desc.generator, var_key, build.desc.build_type)
build_by_pos_key[pos_key] = build
variables = sorted( variables )
th_vars = []
th_build_types = []
for variable in variables:
build_types = sorted( build_types_by_variable[variable] )
nb_build_type = len(build_types_by_variable[variable])
th_vars.append( '<th colspan="%d">%s</th>' % (nb_build_type, cgi.escape( ' '.join( variable ) ) ) )
for build_type in build_types:
th_build_types.append( '<th>%s</th>' % cgi.escape(build_type) )
tr_builds = []
for generator in sorted( builds_by_generator ):
tds = [ '<td>%s</td>\n' % cgi.escape( generator ) ]
for variable in variables:
build_types = sorted( build_types_by_variable[variable] )
for build_type in build_types:
pos_key = (generator, variable, build_type)
build = build_by_pos_key.get(pos_key)
if build:
cmake_status = 'ok' if build.cmake_succeeded else 'FAILED'
build_status = 'ok' if build.build_succeeded else 'FAILED'
cmake_log_url = os.path.relpath( build.cmake_log_path, report_dir )
build_log_url = os.path.relpath( build.build_log_path, report_dir )
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % (
build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
if build.cmake_succeeded:
td += '<br><a href="%s" class="%s">Build: %s</a>' % (
build_log_url, build_status.lower(), build_status)
td += '</td>'
else:
td = '<td></td>'
tds.append( td )
tr_builds.append( '<tr>%s</tr>' % '\n'.join( tds ) )
html = HTML_TEMPLATE.substitute(
title='Batch build report',
th_vars=' '.join(th_vars),
th_build_types=' '.join( th_build_types),
tr_builds='\n'.join( tr_builds ) )
with open( html_report_path, 'wt' ) as fhtml:
fhtml.write( html )
print('HTML report generated in:', html_report_path)
def main():
usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...]
Build a given CMake based project located in SOURCE_DIR with multiple generators/options.dry_run
as described in CONFIG_JSON_PATH building in WORK_DIR.
Example of call:
python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.json
"""
from optparse import OptionParser
parser = OptionParser(usage=usage)
parser.allow_interspersed_args = True
# parser.add_option('-v', '--verbose', dest="verbose", action='store_true',
# help="""Be verbose.""")
parser.enable_interspersed_args()
options, args = parser.parse_args()
if len(args) < 3:
parser.error( "Missing one of WORK_DIR SOURCE_DIR CONFIG_JSON_PATH." )
work_dir = args[0]
source_dir = args[1].rstrip('/\\')
config_paths = args[2:]
for config_path in config_paths:
if not os.path.isfile( config_path ):
parser.error( "Can not read: %r" % config_path )
# generate build variants
build_descs = []
for config_path in config_paths:
build_descs_by_axis = load_build_variants_from_config( config_path )
build_descs.extend( generate_build_variants( build_descs_by_axis ) )
print('Build variants (%d):' % len(build_descs))
# assign build directory for each variant
if not os.path.isdir( work_dir ):
os.makedirs( work_dir )
builds = []
with open( os.path.join( work_dir, 'matrix-dir-map.txt' ), 'wt' ) as fmatrixmap:
for index, build_desc in enumerate( build_descs ):
build_desc_work_dir = os.path.join( work_dir, '%03d' % (index+1) )
builds.append( BuildData( build_desc, build_desc_work_dir, source_dir ) )
fmatrixmap.write( '%s: %s\n' % (build_desc_work_dir, build_desc) )
for build in builds:
build.execute_build()
html_report_path = os.path.join( work_dir, 'batchbuild-report.html' )
generate_html_report( html_report_path, builds )
print('Done')
if __name__ == '__main__':
main()

View File

@@ -1,3 +1,4 @@
from __future__ import print_function
import os.path import os.path
def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ): def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
@@ -6,8 +7,8 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
raise ValueError( 'Path "%s" is not a file' % path ) raise ValueError( 'Path "%s" is not a file' % path )
try: try:
f = open(path, 'rb') f = open(path, 'rb')
except IOError, msg: except IOError as msg:
print >> sys.stderr, "%s: I/O Error: %s" % (file, str(msg)) print("%s: I/O Error: %s" % (file, str(msg)), file=sys.stderr)
return False return False
try: try:
raw_lines = f.readlines() raw_lines = f.readlines()
@@ -15,7 +16,7 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
f.close() f.close()
fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines] fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines]
if raw_lines != fixed_lines: if raw_lines != fixed_lines:
print '%s =>' % path, print('%s =>' % path, end=' ')
if not is_dry_run: if not is_dry_run:
f = open(path, "wb") f = open(path, "wb")
try: try:
@@ -23,7 +24,7 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
finally: finally:
f.close() f.close()
if verbose: if verbose:
print is_dry_run and ' NEED FIX' or ' FIXED' print(is_dry_run and ' NEED FIX' or ' FIXED')
return True return True
## ##
## ##

View File

@@ -1,5 +1,6 @@
"""Updates the license text in source file. """Updates the license text in source file.
""" """
from __future__ import print_function
# An existing license is found if the file starts with the string below, # An existing license is found if the file starts with the string below,
# and ends with the first blank line. # and ends with the first blank line.
@@ -34,11 +35,11 @@ def update_license( path, dry_run, show_diff ):
if not dry_run: if not dry_run:
with open( path, 'wb' ) as fout: with open( path, 'wb' ) as fout:
fout.write( new_text.replace('\n', newline ) ) fout.write( new_text.replace('\n', newline ) )
print 'Updated', path print('Updated', path)
if show_diff: if show_diff:
import difflib import difflib
print '\n'.join( difflib.unified_diff( original_text.split('\n'), print('\n'.join( difflib.unified_diff( original_text.split('\n'),
new_text.split('\n') ) ) new_text.split('\n') ) ))
return True return True
return False return False
@@ -83,7 +84,7 @@ python devtools\licenseupdater.py include src
parser.enable_interspersed_args() parser.enable_interspersed_args()
options, args = parser.parse_args() options, args = parser.parse_args()
update_license_in_source_directories( args, options.dry_run, options.show_diff ) update_license_in_source_directories( args, options.dry_run, options.show_diff )
print 'Done' print('Done')
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,3 @@
<hr> <hr>
<table width="100%">
<tr>
<td width="10%" align="left" valign="center">
<a href="http://sourceforge.net">
<img
src="http://sourceforge.net/sflogo.php?group_id=144446"
width="88" height="31" border="0" alt="SourceForge Logo"></a>
</td>
<td width="20%" align="left" valign="center">
hosts this site.
</td>
<td>
</td>
<td align="right" valign="center">
Send comments to:<br>
<a href="mailto:jsoncpp-devel@lists.sourceforge.net">Json-cpp Developers</a>
</td>
</tr>
</table>
</body> </body>
</html> </html>

View File

@@ -11,12 +11,12 @@ JsonCpp - JSON data format manipulation library
<table width="100%"> <table width="100%">
<tr> <tr>
<td width="40%" align="left" valign="center"> <td width="40%" align="left" valign="center">
<a href="http://sourceforge.net/projects/jsoncpp/"> <a href="https://github.com/open-source-parsers/jsoncpp">
JsonCpp project page JsonCpp project page
</a> </a>
</td> </td>
<td width="40%" align="right" valign="center"> <td width="40%" align="right" valign="center">
<a href="http://jsoncpp.sourceforge.net">JsonCpp home page</a> <a href="https://github.com/open-source-parsers/jsoncpp">JsonCpp home page</a>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -25,10 +25,11 @@ Here is an example of JSON data:
"indent" : { "length" : 3, "use_space": true } "indent" : { "length" : 3, "use_space": true }
} }
\endverbatim \endverbatim
<code>jsoncpp</code> supports comments as <i>meta-data</i>.
\section _features Features \section _features Features
- read and write JSON document - read and write JSON document
- attach C and C++ style comments to element during parsing - attach C++ style comments to element during parsing
- rewrite JSON document preserving original comments - rewrite JSON document preserving original comments
Notes: Comments used to be supported in JSON but where removed for Notes: Comments used to be supported in JSON but where removed for
@@ -84,43 +85,35 @@ std::cout << root;
\section _pbuild Build instructions \section _pbuild Build instructions
The build instructions are located in the file The build instructions are located in the file
<a HREF="README.txt">README.txt</a> in the top-directory of the project. <a HREF="https://github.com/open-source-parsers/jsoncpp/blob/master/README.md">README.md</a> in the top-directory of the project.
Permanent link to the latest revision of the file in subversion: The latest version of the source is available in the project's GitHub repository:
<a HREF="http://jsoncpp.svn.sourceforge.net/viewvc/jsoncpp/trunk/jsoncpp/README.txt?view=markup">latest README.txt</a> <a HREF="https://github.com/open-source-parsers/jsoncpp/">
jsoncpp</a>
\section _pdownload Download
The sources can be downloaded from
<a HREF="http://sourceforge.net/projects/jsoncpp/files/">SourceForge download page</a>.
The latest version of the source is available in the project's subversion repository:
<a HREF="http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/">
http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/</a>
To checkout the source, see the following
<a HREF="http://sourceforge.net/scm/?type=svn&group_id=144446">instructions</a>.
\section _news What's New? \section _news What's New?
The description of latest changes can be found in The description of latest changes can be found in
<a HREF="NEWS.txt">NEWS.txt</a> in the top-directory of the project. <a HREF="https://github.com/open-source-parsers/jsoncpp/wiki/NEWS">
the NEWS wiki
Permanent link to the latest revision of the file in subversion: </a>.
<a HREF="http://svn.sourceforge.net/viewcvs.cgi/jsoncpp/README.txt?view=markup">latest NEWS.txt</a>
\section _plinks Project links
- <a HREF="http://jsoncpp.sourceforge.net">json-cpp home</a>
- <a HREF="http://www.sourceforge.net/projects/jsoncpp/">json-cpp sourceforge project</a>
\section _rlinks Related links \section _rlinks Related links
- <a HREF="http://www.json.org/">JSON</a> Specification and alternate language implementations. - <a HREF="http://www.json.org/">JSON</a> Specification and alternate language implementations.
- <a HREF="http://www.yaml.org/">YAML</a> A data format designed for human readability. - <a HREF="http://www.yaml.org/">YAML</a> A data format designed for human readability.
- <a HREF="http://www.cl.cam.ac.uk/~mgk25/unicode.html">UTF-8 and Unicode FAQ</a>. - <a HREF="http://www.cl.cam.ac.uk/~mgk25/unicode.html">UTF-8 and Unicode FAQ</a>.
\section _plinks Old project links
- <a href="https://sourceforge.net/projects/jsoncpp/">https://sourceforge.net/projects/jsoncpp/</a>
- <a href="http://jsoncpp.sourceforge.net">http://jsoncpp.sourceforge.net</a>
- <a href="http://sourceforge.net/projects/jsoncpp/files/">http://sourceforge.net/projects/jsoncpp/files/</a>
- <a href="http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/">http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/</a>
- <a href="http://jsoncpp.sourceforge.net/old.html">http://jsoncpp.sourceforge.net/old.html</a>
\section _license License \section _license License
See file <a HREF="LICENSE">LICENSE</a> in the top-directory of the project. See file <a href="https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE"><code>LICENSE</code></a> in the top-directory of the project.
Basically JsonCpp is licensed under MIT license, or public domain if desired Basically JsonCpp is licensed under MIT license, or public domain if desired
and recognized in your jurisdiction. and recognized in your jurisdiction.
\author Baptiste Lepilleur <blep@users.sourceforge.net> \author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
*/ */

View File

@@ -1,37 +1,3 @@
/*! \page roadmap JsonCpp roadmap /*! \page roadmap JsonCpp roadmap
\section ms_release Makes JsonCpp ready for release Moved to: https://github.com/open-source-parsers/jsoncpp/wiki/Roadmap
- Build system clean-up:
- Fix build on Windows (shared-library build is broken)
- Add enable/disable flag for static and shared library build
- Enhance help
- Platform portability check: (Notes: was ok on last check)
- linux/gcc,
- solaris/cc,
- windows/msvc678,
- aix/vacpp
- Add JsonCpp version to header as numeric for use in preprocessor test
- Remove buggy experimental hash stuff
\section ms_strict Adds a strict mode to reader/parser
Strict JSON support as specific in RFC 4627 (http://www.ietf.org/rfc/rfc4627.txt?number=4627).
- Enforce only object or array as root element
- Disable comment support
- Get jsonchecker failing tests to pass in strict mode
\section ms_writer Writter control
Provides more control to determine how specific items are serialized when JSON allow choice:
- Optionally allow escaping of non-ASCII characters using unicode escape sequence "\\u".
- Optionally allow escaping of "/" using "\/".
\section ms_separation Expose json reader/writer API that do not impose using Json::Value.
Some typical use-case involve an application specific structure to/from a JSON document.
- Event base parser to allow unserializing a Json document directly in datastructure instead of
using the intermediate Json::Value.
- Stream based parser to serialized a Json document without using Json::Value as input.
- Performance oriented parser/writer:
- Provides an event based parser. Should allow pulling & skipping events for ease of use.
- Provides a JSON document builder: fast only.
\section ms_perfo Performance tuning
- Provides support for static property name definition avoiding allocation
- Static property dictionnary can be provided to JSON reader
- Performance scenario & benchmarking
\section testing Testing
- Adds more tests for unicode parsing (e.g. including surrogate and error detection).
*/ */

View File

@@ -1,12 +1,12 @@
"""Script to generate doxygen documentation. """Script to generate doxygen documentation.
""" """
from __future__ import print_function
from devtools import tarball
import re import re
import os import os
import os.path import os.path
import sys import sys
import shutil import shutil
from devtools import tarball
def find_program(*filenames): def find_program(*filenames):
"""find a program in folders path_lst, and sets env[var] """find a program in folders path_lst, and sets env[var]
@@ -33,9 +33,9 @@ def do_subst_in_file(targetfile, sourcefile, dict):
contents = f.read() contents = f.read()
f.close() f.close()
except: except:
print "Can't read source file %s"%sourcefile print("Can't read source file %s"%sourcefile)
raise raise
for (k,v) in dict.items(): for (k,v) in list(dict.items()):
v = v.replace('\\','\\\\') v = v.replace('\\','\\\\')
contents = re.sub(k, v, contents) contents = re.sub(k, v, contents)
try: try:
@@ -43,7 +43,7 @@ def do_subst_in_file(targetfile, sourcefile, dict):
f.write(contents) f.write(contents)
f.close() f.close()
except: except:
print "Can't write target file %s"%targetfile print("Can't write target file %s"%targetfile)
raise raise
def run_doxygen(doxygen_path, config_file, working_dir, is_silent): def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
@@ -53,12 +53,12 @@ def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
try: try:
os.chdir( working_dir ) os.chdir( working_dir )
cmd = [doxygen_path, config_file] cmd = [doxygen_path, config_file]
print 'Running:', ' '.join( cmd ) print('Running:', ' '.join( cmd ))
try: try:
import subprocess import subprocess
except: except:
if os.system( ' '.join( cmd ) ) != 0: if os.system( ' '.join( cmd ) ) != 0:
print 'Documentation generation failed' print('Documentation generation failed')
return False return False
else: else:
if is_silent: if is_silent:
@@ -67,8 +67,8 @@ def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
process = subprocess.Popen( cmd ) process = subprocess.Popen( cmd )
stdout, _ = process.communicate() stdout, _ = process.communicate()
if process.returncode: if process.returncode:
print 'Documentation generation failed:' print('Documentation generation failed:')
print stdout print(stdout)
return False return False
return True return True
finally: finally:
@@ -107,7 +107,7 @@ def build_doc( options, make_release=False ):
} }
if os.path.isdir( output_dir ): if os.path.isdir( output_dir ):
print 'Deleting directory:', output_dir print('Deleting directory:', output_dir)
shutil.rmtree( output_dir ) shutil.rmtree( output_dir )
if not os.path.isdir( output_dir ): if not os.path.isdir( output_dir ):
os.makedirs( output_dir ) os.makedirs( output_dir )
@@ -115,15 +115,15 @@ def build_doc( options, make_release=False ):
do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys ) do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent ) ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
if not options.silent: if not options.silent:
print open(warning_log_path, 'rb').read() print(open(warning_log_path, 'rb').read())
index_path = os.path.abspath(os.path.join(subst_keys['%HTML_OUTPUT%'], 'index.html')) index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
print 'Generated documentation can be found in:' print('Generated documentation can be found in:')
print index_path print(index_path)
if options.open: if options.open:
import webbrowser import webbrowser
webbrowser.open( 'file://' + index_path ) webbrowser.open( 'file://' + index_path )
if options.make_tarball: if options.make_tarball:
print 'Generating doc tarball to', tarball_path print('Generating doc tarball to', tarball_path)
tarball_sources = [ tarball_sources = [
output_dir, output_dir,
'README.txt', 'README.txt',

2
include/CMakeLists.txt Normal file
View File

@@ -0,0 +1,2 @@
FILE(GLOB INCLUDE_FILES "json/*.h")
INSTALL(FILES ${INCLUDE_FILES} DESTINATION ${INCLUDE_INSTALL_DIR}/json)

41
include/json/assertions.h Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
#include <stdlib.h>
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#if JSON_USE_EXCEPTION
#include <stdexcept>
#define JSON_ASSERT(condition) \
assert(condition); // @todo <= change this into an exception throw
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
#else // JSON_USE_EXCEPTION
#define JSON_ASSERT(condition) assert(condition);
// The call to assert() will show the failure message in debug builds. In
// release bugs we write to invalid memory in order to crash hard, so that a
// debugger or crash reporter gets the chance to take over. We still call exit()
// afterward in order to tell the compiler that this macro doesn't return.
#define JSON_FAIL_MESSAGE(message) \
{ \
assert(false&& message); \
strcpy(reinterpret_cast<char*>(666), message); \
exit(123); \
}
#endif
#define JSON_ASSERT_MESSAGE(condition, message) \
if (!(condition)) { \
JSON_FAIL_MESSAGE(message) \
}
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED

View File

@@ -12,7 +12,8 @@
#include <cpptl/cpptl_autolink.h> #include <cpptl/cpptl_autolink.h>
#endif #endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) #if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
!defined(JSON_IN_CPPTL)
#define CPPTL_AUTOLINK_NAME "json" #define CPPTL_AUTOLINK_NAME "json"
#undef CPPTL_AUTOLINK_DLL #undef CPPTL_AUTOLINK_DLL
#ifdef JSON_DLL #ifdef JSON_DLL

View File

@@ -11,29 +11,33 @@
/// If defined, indicates that json may leverage CppTL library /// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1 //# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map /// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container. /// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1 //# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used /// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator). /// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 /// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
//# define JSON_VALUE_USE_INTERNAL_MAP 1 //# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. /// Force usage of standard new/malloc based allocator instead of memory pool
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink /// based allocator.
/// The memory pools allocator used optimization (initializing Value and
/// ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors. /// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation // If non-zero, the library uses exceptions to report bad input instead of C
/// instead of C assert macro. // assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1 #define JSON_USE_EXCEPTION 1
#endif
/// If defined, indicates that the source file is amalgated /// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion. /// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgated header. /// Remarks: it is automatically defined in the generated amalgated header.
// #define JSON_IS_AMALGAMATION // #define JSON_IS_AMALGAMATION
#ifdef JSON_IN_CPPTL #ifdef JSON_IN_CPPTL
#include <cpptl/config.h> #include <cpptl/config.h>
#ifndef JSON_USE_CPPTL #ifndef JSON_USE_CPPTL
@@ -44,14 +48,22 @@
#ifdef JSON_IN_CPPTL #ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API #define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD) #elif defined(JSON_DLL_BUILD)
#if defined(_MSC_VER)
#define JSON_API __declspec(dllexport) #define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#elif defined(JSON_DLL) #elif defined(JSON_DLL)
#if defined(_MSC_VER)
#define JSON_API __declspec(dllimport) #define JSON_API __declspec(dllimport)
# else #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_IN_CPPTL
#if !defined(JSON_API)
#define JSON_API #define JSON_API
#endif #endif
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
// integer
// Storages, and 64 bits integer support is disabled. // Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1 // #define JSON_NO_INT64 1
@@ -59,6 +71,11 @@
// Microsoft Visual Studio 6 only support conversion from __int64 to double // Microsoft Visual Studio 6 only support conversion from __int64 to double
// (no conversion from unsigned __int64). // (no conversion from unsigned __int64).
#define JSON_USE_INT64_DOUBLE_CONVERSION 1 #define JSON_USE_INT64_DOUBLE_CONVERSION 1
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
// characters in the debug information)
// All projects I've ever seen with VS6 were using this globally (not bothering
// with pragma push/pop).
#pragma warning(disable : 4786)
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 #endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 #if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
@@ -92,5 +109,4 @@ namespace Json {
#endif // if defined(JSON_NO_INT64) #endif // if defined(JSON_NO_INT64)
} // end namespace Json } // end namespace Json
#endif // JSON_CONFIG_H_INCLUDED #endif // JSON_CONFIG_H_INCLUDED

View File

@@ -16,17 +16,18 @@ namespace Json {
* This configuration object can be used to force the Reader or Writer * This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way. * to behave in a standard conforming way.
*/ */
class JSON_API Features class JSON_API Features {
{
public: public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8. /** \brief A configuration that allows all features and assumes all strings
* are UTF-8.
* - C & C++ comments are allowed * - C & C++ comments are allowed
* - Root object can be any JSON value * - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8 * - Assumes Value strings are encoded in UTF-8
*/ */
static Features all(); static Features all();
/** \brief A configuration that is strictly compatible with the JSON specification. /** \brief A configuration that is strictly compatible with the JSON
* specification.
* - Comments are forbidden. * - Comments are forbidden.
* - Root object must be either an array or an object value. * - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8 * - Assumes Value strings are encoded in UTF-8
@@ -40,8 +41,15 @@ namespace Json {
/// \c true if comments are allowed. Default: \c true. /// \c true if comments are allowed. Default: \c true.
bool allowComments_; bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false. /// \c true if root must be either an array or an object value. Default: \c
/// false.
bool strictRoot_; bool strictRoot_;
/// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_;
/// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_;
}; };
} // namespace Json } // namespace Json

View File

@@ -40,5 +40,4 @@ namespace Json {
} // namespace Json } // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED #endif // JSON_FORWARDS_H_INCLUDED

View File

@@ -11,21 +11,40 @@
#include "value.h" #include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <deque> #include <deque>
#include <iosfwd>
#include <stack> #include <stack>
#include <string> #include <string>
# include <iostream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
namespace Json { namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value. /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
*Value.
* *
*/ */
class JSON_API Reader class JSON_API Reader {
{
public: public:
typedef char Char; typedef char Char;
typedef const Char* Location; typedef const Char* Location;
/** \brief An error tagged with where in the JSON text it was encountered.
*
* The offsets give the [start, limit) range of bytes within the text. Note
* that this is bytes, not codepoints.
*
*/
struct StructuredError {
size_t offset_start;
size_t offset_limit;
std::string message;
};
/** \brief Constructs a Reader allowing all features /** \brief Constructs a Reader allowing all features
* for parsing. * for parsing.
*/ */
@@ -36,61 +55,106 @@ namespace Json {
*/ */
Reader(const Features& features); Reader(const Features& features);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document.
* \param document UTF-8 encoded string containing the document to read. * \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was * \param root [out] Contains the root value of the document if it was
* successfully parsed. * successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during * \param collectComments \c true to collect comment and allow writing them
* back during
* serialization, \c false to discard comments. * serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_ * This parameter is ignored if
* Features::allowComments_
* is \c false. * is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred. * \return \c true if the document was successfully parsed, \c false if an
* error occurred.
*/ */
bool parse( const std::string &document, bool
Value &root, parse(const std::string& document, Value& root, bool collectComments = true);
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. document.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
\ Must be >= beginDoc. \ Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was * \param root [out] Contains the root value of the document if it was
* successfully parsed. * successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during * \param collectComments \c true to collect comment and allow writing them
back during
* serialization, \c false to discard comments. * serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_ * This parameter is ignored if
Features::allowComments_
* is \c false. * is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred. * \return \c true if the document was successfully parsed, \c false if an
error occurred.
*/ */
bool parse( const char *beginDoc, const char *endDoc, bool parse(const char* beginDoc,
const char* endDoc,
Value& root, Value& root,
bool collectComments = true); bool collectComments = true);
/// \brief Parse from input stream. /// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&). /// \see Json::operator>>(std::istream&, Json::Value&).
bool parse( std::istream &is, bool parse(std::istream& is, Value& root, bool collectComments = true);
Value &root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document. /** \brief Returns a user friendly string that list errors in the parsed
* \return Formatted error message with the list of errors with their location in * document.
* the parsed document. An empty string is returned if no error occurred * \return Formatted error message with the list of errors with their location
* in
* the parsed document. An empty string is returned if no error
* occurred
* during parsing. * during parsing.
* \deprecated Use getFormattedErrorMessages() instead (typo fix). * \deprecated Use getFormattedErrorMessages() instead (typo fix).
*/ */
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
std::string getFormatedErrorMessages() const; std::string getFormatedErrorMessages() const;
/** \brief Returns a user friendly string that list errors in the parsed document. /** \brief Returns a user friendly string that list errors in the parsed
* \return Formatted error message with the list of errors with their location in * document.
* the parsed document. An empty string is returned if no error occurred * \return Formatted error message with the list of errors with their location
* in
* the parsed document. An empty string is returned if no error
* occurred
* during parsing. * during parsing.
*/ */
std::string getFormattedErrorMessages() const; std::string getFormattedErrorMessages() const;
/** \brief Returns a vector of structured erros encounted while parsing.
* \return A (possibly empty) vector of StructuredError objects. Currently
* only one error can be returned, but the caller should tolerate
* multiple
* errors. This can occur if the parser recovers from a non-fatal
* parse error and then encounters additional errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
/** \brief Add a semantic error message.
* \param value JSON Value location associated with the error
* \param message The error message.
* \return \c true if the error was successfully added, \c false if the
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const std::string& message);
/** \brief Add a semantic error message with extra context.
* \param value JSON Value location associated with the error
* \param message The error message.
* \param extra Additional JSON Value location to contextualize the error
* \return \c true if the error was successfully added, \c false if either
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const std::string& message, const Value& extra);
/** \brief Return whether there are any errors.
* \return \c true if there are no errors to report \c false if
* errors have occurred.
*/
bool good() const;
private: private:
enum TokenType enum TokenType {
{
tokenEndOfStream = 0, tokenEndOfStream = 0,
tokenObjectBegin, tokenObjectBegin,
tokenObjectEnd, tokenObjectEnd,
@@ -107,16 +171,14 @@ namespace Json {
tokenError tokenError
}; };
class Token class Token {
{
public: public:
TokenType type_; TokenType type_;
Location start_; Location start_;
Location end_; Location end_;
}; };
class ErrorInfo class ErrorInfo {
{
public: public:
Token token_; Token token_;
std::string message_; std::string message_;
@@ -128,8 +190,7 @@ namespace Json {
bool expectToken(TokenType type, Token& token, const char* message); bool expectToken(TokenType type, Token& token, const char* message);
bool readToken(Token& token); bool readToken(Token& token);
void skipSpaces(); void skipSpaces();
bool match( Location pattern, bool match(Location pattern, int patternLength);
int patternLength );
bool readComment(); bool readComment();
bool readCStyleComment(); bool readCStyleComment();
bool readCppStyleComment(); bool readCppStyleComment();
@@ -139,9 +200,11 @@ namespace Json {
bool readObject(Token& token); bool readObject(Token& token);
bool readArray(Token& token); bool readArray(Token& token);
bool decodeNumber(Token& token); bool decodeNumber(Token& token);
bool decodeNumber(Token& token, Value& decoded);
bool decodeString(Token& token); bool decodeString(Token& token);
bool decodeString(Token& token, std::string& decoded); bool decodeString(Token& token, std::string& decoded);
bool decodeDouble(Token& token); bool decodeDouble(Token& token);
bool decodeDouble(Token& token, Value& decoded);
bool decodeUnicodeCodePoint(Token& token, bool decodeUnicodeCodePoint(Token& token,
Location& current, Location& current,
Location end, Location end,
@@ -150,9 +213,7 @@ namespace Json {
Location& current, Location& current,
Location end, Location end,
unsigned int& unicode); unsigned int& unicode);
bool addError( const std::string &message, bool addError(const std::string& message, Token& token, Location extra = 0);
Token &token,
Location extra = 0 );
bool recoverFromError(TokenType skipUntilToken); bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const std::string& message, bool addErrorAndRecover(const std::string& message,
Token& token, Token& token,
@@ -160,13 +221,10 @@ namespace Json {
void skipUntilSpace(); void skipUntilSpace();
Value& currentValue(); Value& currentValue();
Char getNextChar(); Char getNextChar();
void getLocationLineAndColumn( Location location, void
int &line, getLocationLineAndColumn(Location location, int& line, int& column) const;
int &column ) const;
std::string getLocationLineAndColumn(Location location) const; std::string getLocationLineAndColumn(Location location) const;
void addComment( Location begin, void addComment(Location begin, Location end, CommentPlacement placement);
Location end,
CommentPlacement placement );
void skipCommentTokens(Token& token); void skipCommentTokens(Token& token);
typedef std::stack<Value*> Nodes; typedef std::stack<Value*> Nodes;
@@ -207,8 +265,12 @@ namespace Json {
\throw std::exception on parse error. \throw std::exception on parse error.
\see Json::operator<<() \see Json::operator<<()
*/ */
std::istream& operator>>( std::istream&, Value& ); JSON_API std::istream& operator>>(std::istream&, Value&);
} // namespace Json } // namespace Json
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_READER_H_INCLUDED #endif // CPPTL_JSON_READER_H_INCLUDED

View File

@@ -21,14 +21,20 @@
#include <cpptl/forwards.h> #include <cpptl/forwards.h>
#endif #endif
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
/** \brief JSON (JavaScript Object Notation). /** \brief JSON (JavaScript Object Notation).
*/ */
namespace Json { namespace Json {
/** \brief Type of the value held by a Value object. /** \brief Type of the value held by a Value object.
*/ */
enum ValueType enum ValueType {
{
nullValue = 0, ///< 'null' value nullValue = 0, ///< 'null' value
intValue, ///< signed integer value intValue, ///< signed integer value
uintValue, ///< unsigned integer value uintValue, ///< unsigned integer value
@@ -39,11 +45,11 @@ namespace Json {
objectValue ///< object value (collection of name/value pairs). objectValue ///< object value (collection of name/value pairs).
}; };
enum CommentPlacement enum CommentPlacement {
{
commentBefore = 0, ///< a comment placed on the line before a value commentBefore = 0, ///< a comment placed on the line before a value
commentAfterOnSameLine, ///< a comment just after a value on the same line commentAfterOnSameLine, ///< a comment just after a value on the same line
commentAfter, ///< a comment on the line after a value (only make sense for root value) commentAfter, ///< a comment on the line after a value (only make sense for
/// root value)
numberOfCommentPlacement numberOfCommentPlacement
}; };
@@ -66,23 +72,13 @@ namespace Json {
* object[code] = 1234; * object[code] = 1234;
* \endcode * \endcode
*/ */
class JSON_API StaticString class JSON_API StaticString {
{
public: public:
explicit StaticString( const char *czstring ) explicit StaticString(const char* czstring) : str_(czstring) {}
: str_( czstring )
{
}
operator const char *() const operator const char*() const { return str_; }
{
return str_;
}
const char *c_str() const const char* c_str() const { return str_; }
{
return str_;
}
private: private:
const char* str_; const char* str_;
@@ -103,20 +99,21 @@ namespace Json {
* The type of the held value is represented by a #ValueType and * The type of the held value is represented by a #ValueType and
* can be obtained using type(). * can be obtained using type().
* *
* values of an #objectValue or #arrayValue can be accessed using operator[]() methods. * values of an #objectValue or #arrayValue can be accessed using operator[]()
*methods.
* Non const methods will automatically create the a #nullValue element * Non const methods will automatically create the a #nullValue element
* if it does not exist. * if it does not exist.
* The sequence of an #arrayValue will be automatically resize and initialized * The sequence of an #arrayValue will be automatically resize and initialized
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
* *
* The get() methods can be used to obtanis default value in the case the required element * The get() methods can be used to obtanis default value in the case the
*required element
* does not exist. * does not exist.
* *
* It is possible to iterate over the list of a #objectValue values using * It is possible to iterate over the list of a #objectValue values using
* the getMemberNames() method. * the getMemberNames() method.
*/ */
class JSON_API Value class JSON_API Value {
{
friend class ValueIteratorBase; friend class ValueIteratorBase;
#ifdef JSON_VALUE_USE_INTERNAL_MAP #ifdef JSON_VALUE_USE_INTERNAL_MAP
friend class ValueInternalLink; friend class ValueInternalLink;
@@ -136,7 +133,7 @@ namespace Json {
typedef Json::LargestUInt LargestUInt; typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex; typedef Json::ArrayIndex ArrayIndex;
static const Value null; static const Value& null;
/// Minimum signed integer value that can be stored in a Json::Value. /// Minimum signed integer value that can be stored in a Json::Value.
static const LargestInt minLargestInt; static const LargestInt minLargestInt;
/// Maximum signed integer value that can be stored in a Json::Value. /// Maximum signed integer value that can be stored in a Json::Value.
@@ -151,21 +148,21 @@ namespace Json {
/// Maximum unsigned int value that can be stored in a Json::Value. /// Maximum unsigned int value that can be stored in a Json::Value.
static const UInt maxUInt; static const UInt maxUInt;
#if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value. /// Minimum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 minInt64; static const Int64 minInt64;
/// Maximum signed 64 bits int value that can be stored in a Json::Value. /// Maximum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 maxInt64; static const Int64 maxInt64;
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value. /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static const UInt64 maxUInt64; static const UInt64 maxUInt64;
#endif // defined(JSON_HAS_INT64)
private: private:
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
class CZString class CZString {
{
public: public:
enum DuplicationPolicy enum DuplicationPolicy {
{
noDuplication = 0, noDuplication = 0,
duplicate, duplicate,
duplicateOnCopy duplicateOnCopy
@@ -174,12 +171,13 @@ namespace Json {
CZString(const char* cstr, DuplicationPolicy allocate); CZString(const char* cstr, DuplicationPolicy allocate);
CZString(const CZString& other); CZString(const CZString& other);
~CZString(); ~CZString();
CZString &operator =( const CZString &other ); CZString& operator=(CZString other);
bool operator<(const CZString& other) const; bool operator<(const CZString& other) const;
bool operator==(const CZString& other) const; bool operator==(const CZString& other) const;
ArrayIndex index() const; ArrayIndex index() const;
const char* c_str() const; const char* c_str() const;
bool isStaticString() const; bool isStaticString() const;
private: private:
void swap(CZString& other); void swap(CZString& other);
const char* cstr_; const char* cstr_;
@@ -240,7 +238,7 @@ namespace Json {
Value(const Value& other); Value(const Value& other);
~Value(); ~Value();
Value &operator=( const Value &other ); Value& operator=(Value other);
/// Swap values. /// Swap values.
/// \note Currently, comments are intentionally not swapped, for /// \note Currently, comments are intentionally not swapped, for
/// both logic and efficiency. /// both logic and efficiency.
@@ -265,8 +263,10 @@ namespace Json {
#endif #endif
Int asInt() const; Int asInt() const;
UInt asUInt() const; UInt asUInt() const;
#if defined(JSON_HAS_INT64)
Int64 asInt64() const; Int64 asInt64() const;
UInt64 asUInt64() const; UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)
LargestInt asLargestInt() const; LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const; LargestUInt asLargestUInt() const;
float asFloat() const; float asFloat() const;
@@ -276,7 +276,9 @@ namespace Json {
bool isNull() const; bool isNull() const;
bool isBool() const; bool isBool() const;
bool isInt() const; bool isInt() const;
bool isInt64() const;
bool isUInt() const; bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const; bool isIntegral() const;
bool isDouble() const; bool isDouble() const;
bool isNumeric() const; bool isNumeric() const;
@@ -309,14 +311,16 @@ namespace Json {
void resize(ArrayIndex size); void resize(ArrayIndex size);
/// Access an array element (zero based index ). /// Access an array element (zero based index ).
/// If the array contains less than index element, then null value are inserted /// If the array contains less than index element, then null value are
/// inserted
/// in the array so that its size is index+1. /// in the array so that its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish /// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index); Value& operator[](ArrayIndex index);
/// Access an array element (zero based index ). /// Access an array element (zero based index ).
/// If the array contains less than index element, then null value are inserted /// If the array contains less than index element, then null value are
/// inserted
/// in the array so that its size is index+1. /// in the array so that its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish /// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
@@ -332,10 +336,10 @@ namespace Json {
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
const Value& operator[](int index) const; const Value& operator[](int index) const;
/// If the array contains at least index+1 elements, returns the element value, /// If the array contains at least index+1 elements, returns the element
/// value,
/// otherwise returns defaultValue. /// otherwise returns defaultValue.
Value get( ArrayIndex index, Value get(ArrayIndex index, const Value& defaultValue) const;
const Value &defaultValue ) const;
/// Return true if index < size(). /// Return true if index < size().
bool isValidIndex(ArrayIndex index) const; bool isValidIndex(ArrayIndex index) const;
/// \brief Append value to array at the end. /// \brief Append value to array at the end.
@@ -345,13 +349,16 @@ namespace Json {
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
Value& operator[](const char* key); Value& operator[](const char* key);
/// Access an object value by name, returns null if there is no member with that name. /// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const char* key) const; const Value& operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
Value& operator[](const std::string& key); Value& operator[](const std::string& key);
/// Access an object value by name, returns null if there is no member with that name. /// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const std::string& key) const; const Value& operator[](const std::string& key) const;
/** \brief Access an object value by name, create a null member if it does not exist. /** \brief Access an object value by name, create a null member if it does not
exist.
* If the object as no entry for that name, then the member name used to store * If the object as no entry for that name, then the member name used to store
* the new entry is not duplicated. * the new entry is not duplicated.
@@ -366,19 +373,17 @@ namespace Json {
#ifdef JSON_USE_CPPTL #ifdef JSON_USE_CPPTL
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
Value& operator[](const CppTL::ConstString& key); Value& operator[](const CppTL::ConstString& key);
/// Access an object value by name, returns null if there is no member with that name. /// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const CppTL::ConstString& key) const; const Value& operator[](const CppTL::ConstString& key) const;
#endif #endif
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
Value get( const char *key, Value get(const char* key, const Value& defaultValue) const;
const Value &defaultValue ) const;
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
Value get( const std::string &key, Value get(const std::string& key, const Value& defaultValue) const;
const Value &defaultValue ) const;
#ifdef JSON_USE_CPPTL #ifdef JSON_USE_CPPTL
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
Value get( const CppTL::ConstString &key, Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
const Value &defaultValue ) const;
#endif #endif
/// \brief Remove and return the named member. /// \brief Remove and return the named member.
/// ///
@@ -412,11 +417,9 @@ namespace Json {
//# endif //# endif
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment( const char *comment, void setComment(const char* comment, CommentPlacement placement);
CommentPlacement placement );
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment( const std::string &comment, void setComment(const std::string& comment, CommentPlacement placement);
CommentPlacement placement );
bool hasComment(CommentPlacement placement) const; bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines. /// Include delimiters and embedded newlines.
std::string getComment(CommentPlacement placement) const; std::string getComment(CommentPlacement placement) const;
@@ -429,35 +432,32 @@ namespace Json {
iterator begin(); iterator begin();
iterator end(); iterator end();
// Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any.
void setOffsetStart(size_t start);
void setOffsetLimit(size_t limit);
size_t getOffsetStart() const;
size_t getOffsetLimit() const;
private: private:
Value &resolveReference( const char *key, void initBasic(ValueType type, bool allocated = false);
bool isStatic );
Value& resolveReference(const char* key, bool isStatic);
#ifdef JSON_VALUE_USE_INTERNAL_MAP #ifdef JSON_VALUE_USE_INTERNAL_MAP
inline bool isItemAvailable() const inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
{
return itemIsUsed_ == 0;
}
inline void setItemUsed( bool isUsed = true ) inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
{
itemIsUsed_ = isUsed ? 1 : 0;
}
inline bool isMemberNameStatic() const inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
{
return memberNameIsStatic_ == 0;
}
inline void setMemberNameIsStatic( bool isStatic ) inline void setMemberNameIsStatic(bool isStatic) {
{
memberNameIsStatic_ = isStatic ? 1 : 0; memberNameIsStatic_ = isStatic ? 1 : 0;
} }
#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP #endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
private: private:
struct CommentInfo struct CommentInfo {
{
CommentInfo(); CommentInfo();
~CommentInfo(); ~CommentInfo();
@@ -475,8 +475,7 @@ namespace Json {
// } // }
//}; //};
union ValueHolder union ValueHolder {
{
LargestInt int_; LargestInt int_;
LargestUInt uint_; LargestUInt uint_;
double real_; double real_;
@@ -496,13 +495,17 @@ namespace Json {
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
#endif #endif
CommentInfo* comments_; CommentInfo* comments_;
// [start, limit) byte offsets in the source JSON text from which this Value
// was extracted.
size_t start_;
size_t limit_;
}; };
/** \brief Experimental and untested: represents an element of the "path" to
/** \brief Experimental and untested: represents an element of the "path" to access a node. * access a node.
*/ */
class PathArgument class JSON_API PathArgument {
{
public: public:
friend class Path; friend class Path;
@@ -512,8 +515,7 @@ namespace Json {
PathArgument(const std::string& key); PathArgument(const std::string& key);
private: private:
enum Kind enum Kind {
{
kindNone = 0, kindNone = 0,
kindIndex, kindIndex,
kindKey kindKey
@@ -534,8 +536,7 @@ namespace Json {
* - ".%" => member name is provided as parameter * - ".%" => member name is provided as parameter
* - ".[%]" => index is provied as parameter * - ".[%]" => index is provied as parameter
*/ */
class Path class JSON_API Path {
{
public: public:
Path(const std::string& path, Path(const std::string& path,
const PathArgument& a1 = PathArgument(), const PathArgument& a1 = PathArgument(),
@@ -545,32 +546,29 @@ namespace Json {
const PathArgument& a5 = PathArgument()); const PathArgument& a5 = PathArgument());
const Value& resolve(const Value& root) const; const Value& resolve(const Value& root) const;
Value resolve( const Value &root, Value resolve(const Value& root, const Value& defaultValue) const;
const Value &defaultValue ) const; /// Creates the "path" to access the specified node and returns a reference on
/// Creates the "path" to access the specified node and returns a reference on the node. /// the node.
Value& make(Value& root) const; Value& make(Value& root) const;
private: private:
typedef std::vector<const PathArgument*> InArgs; typedef std::vector<const PathArgument*> InArgs;
typedef std::vector<PathArgument> Args; typedef std::vector<PathArgument> Args;
void makePath( const std::string &path, void makePath(const std::string& path, const InArgs& in);
const InArgs &in );
void addPathInArg(const std::string& path, void addPathInArg(const std::string& path,
const InArgs& in, const InArgs& in,
InArgs::const_iterator& itInArg, InArgs::const_iterator& itInArg,
PathArgument::Kind kind); PathArgument::Kind kind);
void invalidPath( const std::string &path, void invalidPath(const std::string& path, int location);
int location );
Args args_; Args args_;
}; };
#ifdef JSON_VALUE_USE_INTERNAL_MAP #ifdef JSON_VALUE_USE_INTERNAL_MAP
/** \brief Allocator to customize Value internal map. /** \brief Allocator to customize Value internal map.
* Below is an example of a simple implementation (default implementation actually * Below is an example of a simple implementation (default implementation
actually
* use memory pool for speed). * use memory pool for speed).
* \code * \code
class DefaultValueMapAllocator : public ValueMapAllocator class DefaultValueMapAllocator : public ValueMapAllocator
@@ -613,8 +611,7 @@ namespace Json {
}; };
* \endcode * \endcode
*/ */
class JSON_API ValueMapAllocator class JSON_API ValueMapAllocator {
{
public: public:
virtual ~ValueMapAllocator(); virtual ~ValueMapAllocator();
virtual ValueInternalMap* newMap() = 0; virtual ValueInternalMap* newMap() = 0;
@@ -629,10 +626,11 @@ namespace Json {
/** \brief ValueInternalMap hash-map bucket chain link (for internal use only). /** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
* \internal previous_ & next_ allows for bidirectional traversal. * \internal previous_ & next_ allows for bidirectional traversal.
*/ */
class JSON_API ValueInternalLink class JSON_API ValueInternalLink {
{
public: public:
enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. enum {
itemPerLink = 6
}; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
enum InternalFlags { enum InternalFlags {
flagAvailable = 0, flagAvailable = 0,
flagUsed = 1 flagUsed = 1
@@ -648,37 +646,34 @@ namespace Json {
ValueInternalLink* next_; ValueInternalLink* next_;
}; };
/** \brief A linked page based hash-table implementation used internally by
/** \brief A linked page based hash-table implementation used internally by Value. *Value.
* \internal ValueInternalMap is a tradional bucket based hash-table, with a linked * \internal ValueInternalMap is a tradional bucket based hash-table, with a
*linked
* list in each bucket to handle collision. There is an addional twist in that * list in each bucket to handle collision. There is an addional twist in that
* each node of the collision linked list is a page containing a fixed amount of * each node of the collision linked list is a page containing a fixed amount of
* value. This provides a better compromise between memory usage and speed. * value. This provides a better compromise between memory usage and speed.
* *
* Each bucket is made up of a chained list of ValueInternalLink. The last * Each bucket is made up of a chained list of ValueInternalLink. The last
* link of a given bucket can be found in the 'previous_' field of the following bucket. * link of a given bucket can be found in the 'previous_' field of the following
* The last link of the last bucket is stored in tailLink_ as it has no following bucket. *bucket.
* Only the last link of a bucket may contains 'available' item. The last link always * The last link of the last bucket is stored in tailLink_ as it has no
*following bucket.
* Only the last link of a bucket may contains 'available' item. The last link
*always
* contains at least one element unless is it the bucket one very first link. * contains at least one element unless is it the bucket one very first link.
*/ */
class JSON_API ValueInternalMap class JSON_API ValueInternalMap {
{
friend class ValueIteratorBase; friend class ValueIteratorBase;
friend class Value; friend class Value;
public: public:
typedef unsigned int HashKey; typedef unsigned int HashKey;
typedef unsigned int BucketIndex; typedef unsigned int BucketIndex;
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
struct IteratorState struct IteratorState {
{ IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
IteratorState()
: map_(0)
, link_(0)
, itemIndex_(0)
, bucketIndex_(0)
{
}
ValueInternalMap* map_; ValueInternalMap* map_;
ValueInternalLink* link_; ValueInternalLink* link_;
BucketIndex itemIndex_; BucketIndex itemIndex_;
@@ -688,7 +683,7 @@ namespace Json {
ValueInternalMap(); ValueInternalMap();
ValueInternalMap(const ValueInternalMap& other); ValueInternalMap(const ValueInternalMap& other);
ValueInternalMap &operator =( const ValueInternalMap &other ); ValueInternalMap& operator=(ValueInternalMap other);
~ValueInternalMap(); ~ValueInternalMap();
void swap(ValueInternalMap& other); void swap(ValueInternalMap& other);
@@ -705,8 +700,7 @@ namespace Json {
Value* find(const char* key); Value* find(const char* key);
Value &resolveReference( const char *key, Value& resolveReference(const char* key, bool isStatic);
bool isStatic );
void remove(const char* key); void remove(const char* key);
@@ -721,9 +715,7 @@ namespace Json {
ValueInternalLink* link, ValueInternalLink* link,
BucketIndex index); BucketIndex index);
Value &unsafeAdd( const char *key, Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey);
bool isStatic,
HashKey hashedKey );
HashKey hash(const char* key) const; HashKey hash(const char* key) const;
@@ -750,33 +742,33 @@ namespace Json {
/** \brief A simplified deque implementation used internally by Value. /** \brief A simplified deque implementation used internally by Value.
* \internal * \internal
* It is based on a list of fixed "page", each page contains a fixed number of items. * It is based on a list of fixed "page", each page contains a fixed number of
* Instead of using a linked-list, a array of pointer is used for fast item look-up. *items.
* Instead of using a linked-list, a array of pointer is used for fast item
*look-up.
* Look-up for an element is as follow: * Look-up for an element is as follow:
* - compute page index: pageIndex = itemIndex / itemsPerPage * - compute page index: pageIndex = itemIndex / itemsPerPage
* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
* *
* Insertion is amortized constant time (only the array containing the index of pointers * Insertion is amortized constant time (only the array containing the index of
*pointers
* need to be reallocated when items are appended). * need to be reallocated when items are appended).
*/ */
class JSON_API ValueInternalArray class JSON_API ValueInternalArray {
{
friend class Value; friend class Value;
friend class ValueIteratorBase; friend class ValueIteratorBase;
public: public:
enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. enum {
itemsPerPage = 8
}; // should be a power of 2 for fast divide and modulo.
typedef Value::ArrayIndex ArrayIndex; typedef Value::ArrayIndex ArrayIndex;
typedef unsigned int PageIndex; typedef unsigned int PageIndex;
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
struct IteratorState // Must be a POD struct IteratorState // Must be a POD
{ {
IteratorState() IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
: array_(0)
, currentPageIndex_(0)
, currentItemIndex_(0)
{
}
ValueInternalArray* array_; ValueInternalArray* array_;
Value** currentPageIndex_; Value** currentPageIndex_;
unsigned int currentItemIndex_; unsigned int currentItemIndex_;
@@ -785,7 +777,7 @@ namespace Json {
ValueInternalArray(); ValueInternalArray();
ValueInternalArray(const ValueInternalArray& other); ValueInternalArray(const ValueInternalArray& other);
ValueInternalArray &operator =( const ValueInternalArray &other ); ValueInternalArray& operator=(ValueInternalArray other);
~ValueInternalArray(); ~ValueInternalArray();
void swap(ValueInternalArray& other); void swap(ValueInternalArray& other);
@@ -819,7 +811,8 @@ namespace Json {
PageIndex pageCount_; PageIndex pageCount_;
}; };
/** \brief Experimental: do not use. Allocator to customize Value internal array. /** \brief Experimental: do not use. Allocator to customize Value internal
array.
* Below is an example of a simple implementation (actual implementation use * Below is an example of a simple implementation (actual implementation use
* memory pool). * memory pool).
\code \code
@@ -846,8 +839,10 @@ public: // overridden from ValueArrayAllocator
} }
virtual void reallocateArrayPageIndex( Value **&indexes, virtual void reallocateArrayPageIndex( Value **&indexes,
ValueInternalArray::PageIndex &indexCount, ValueInternalArray::PageIndex
ValueInternalArray::PageIndex minNewIndexCount ) &indexCount,
ValueInternalArray::PageIndex
minNewIndexCount )
{ {
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
if ( minNewIndexCount > newIndexCount ) if ( minNewIndexCount > newIndexCount )
@@ -867,7 +862,8 @@ public: // overridden from ValueArrayAllocator
virtual Value *allocateArrayPage() virtual Value *allocateArrayPage()
{ {
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); return static_cast<Value *>( malloc( sizeof(Value) *
ValueInternalArray::itemsPerPage ) );
} }
virtual void releaseArrayPage( Value *value ) virtual void releaseArrayPage( Value *value )
@@ -878,8 +874,7 @@ public: // overridden from ValueArrayAllocator
}; };
\endcode \endcode
*/ */
class JSON_API ValueArrayAllocator class JSON_API ValueArrayAllocator {
{
public: public:
virtual ~ValueArrayAllocator(); virtual ~ValueArrayAllocator();
virtual ValueInternalArray* newArray() = 0; virtual ValueInternalArray* newArray() = 0;
@@ -893,26 +888,28 @@ public: // overridden from ValueArrayAllocator
* \param indexCount [input] current number of pages in the index. * \param indexCount [input] current number of pages in the index.
* [output] number of page the reallocated index can handle. * [output] number of page the reallocated index can handle.
* \b MUST be >= \a minNewIndexCount. * \b MUST be >= \a minNewIndexCount.
* \param minNewIndexCount Minimum number of page the new index must be able to * \param minNewIndexCount Minimum number of page the new index must be able
* to
* handle. * handle.
*/ */
virtual void reallocateArrayPageIndex( Value **&indexes, virtual void
reallocateArrayPageIndex(Value**& indexes,
ValueInternalArray::PageIndex& indexCount, ValueInternalArray::PageIndex& indexCount,
ValueInternalArray::PageIndex minNewIndexCount) = 0; ValueInternalArray::PageIndex minNewIndexCount) = 0;
virtual void releaseArrayPageIndex( Value **indexes, virtual void
releaseArrayPageIndex(Value** indexes,
ValueInternalArray::PageIndex indexCount) = 0; ValueInternalArray::PageIndex indexCount) = 0;
virtual Value* allocateArrayPage() = 0; virtual Value* allocateArrayPage() = 0;
virtual void releaseArrayPage(Value* value) = 0; virtual void releaseArrayPage(Value* value) = 0;
}; };
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
/** \brief base class for Value iterators. /** \brief base class for Value iterators.
* *
*/ */
class ValueIteratorBase class JSON_API ValueIteratorBase {
{
public: public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef unsigned int size_t; typedef unsigned int size_t;
typedef int difference_type; typedef int difference_type;
typedef ValueIteratorBase SelfType; typedef ValueIteratorBase SelfType;
@@ -925,28 +922,23 @@ public: // overridden from ValueArrayAllocator
ValueIteratorBase(const ValueInternalMap::IteratorState& state); ValueIteratorBase(const ValueInternalMap::IteratorState& state);
#endif #endif
bool operator ==( const SelfType &other ) const bool operator==(const SelfType& other) const { return isEqual(other); }
{
return isEqual( other );
}
bool operator !=( const SelfType &other ) const bool operator!=(const SelfType& other) const { return !isEqual(other); }
{
return !isEqual( other );
}
difference_type operator -( const SelfType &other ) const difference_type operator-(const SelfType& other) const {
{
return computeDistance(other); return computeDistance(other);
} }
/// Return either the index or the member name of the referenced value as a Value. /// Return either the index or the member name of the referenced value as a
/// Value.
Value key() const; Value key() const;
/// Return the index of the referenced Value. -1 if it is not an arrayValue. /// Return the index of the referenced Value. -1 if it is not an arrayValue.
UInt index() const; UInt index() const;
/// Return the member name of the referenced Value. "" if it is not an objectValue. /// Return the member name of the referenced Value. "" if it is not an
/// objectValue.
const char* memberName() const; const char* memberName() const;
protected: protected:
@@ -968,8 +960,7 @@ public: // overridden from ValueArrayAllocator
// Indicates that iterator is for a null value. // Indicates that iterator is for a null value.
bool isNull_; bool isNull_;
#else #else
union union {
{
ValueInternalArray::IteratorState array_; ValueInternalArray::IteratorState array_;
ValueInternalMap::IteratorState map_; ValueInternalMap::IteratorState map_;
} iterator_; } iterator_;
@@ -980,10 +971,11 @@ public: // overridden from ValueArrayAllocator
/** \brief const iterator for object and array value. /** \brief const iterator for object and array value.
* *
*/ */
class ValueConstIterator : public ValueIteratorBase class JSON_API ValueConstIterator : public ValueIteratorBase {
{
friend class Value; friend class Value;
public: public:
typedef const Value value_type;
typedef unsigned int size_t; typedef unsigned int size_t;
typedef int difference_type; typedef int difference_type;
typedef const Value& reference; typedef const Value& reference;
@@ -991,6 +983,7 @@ public: // overridden from ValueArrayAllocator
typedef ValueConstIterator SelfType; typedef ValueConstIterator SelfType;
ValueConstIterator(); ValueConstIterator();
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
@@ -1003,45 +996,40 @@ public: // overridden from ValueArrayAllocator
public: public:
SelfType& operator=(const ValueIteratorBase& other); SelfType& operator=(const ValueIteratorBase& other);
SelfType operator++( int ) SelfType operator++(int) {
{
SelfType temp(*this); SelfType temp(*this);
++*this; ++*this;
return temp; return temp;
} }
SelfType operator--( int ) SelfType operator--(int) {
{
SelfType temp(*this); SelfType temp(*this);
--*this; --*this;
return temp; return temp;
} }
SelfType &operator--() SelfType& operator--() {
{
decrement(); decrement();
return *this; return *this;
} }
SelfType &operator++() SelfType& operator++() {
{
increment(); increment();
return *this; return *this;
} }
reference operator *() const reference operator*() const { return deref(); }
{
return deref();
}
};
pointer operator->() const { return &deref(); }
};
/** \brief Iterator for object and array value. /** \brief Iterator for object and array value.
*/ */
class ValueIterator : public ValueIteratorBase class JSON_API ValueIterator : public ValueIteratorBase {
{
friend class Value; friend class Value;
public: public:
typedef Value value_type;
typedef unsigned int size_t; typedef unsigned int size_t;
typedef int difference_type; typedef int difference_type;
typedef Value& reference; typedef Value& reference;
@@ -1051,6 +1039,7 @@ public: // overridden from ValueArrayAllocator
ValueIterator(); ValueIterator();
ValueIterator(const ValueConstIterator& other); ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other); ValueIterator(const ValueIterator& other);
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
@@ -1061,43 +1050,39 @@ public: // overridden from ValueArrayAllocator
ValueIterator(const ValueInternalMap::IteratorState& state); ValueIterator(const ValueInternalMap::IteratorState& state);
#endif #endif
public: public:
SelfType& operator=(const SelfType& other); SelfType& operator=(const SelfType& other);
SelfType operator++( int ) SelfType operator++(int) {
{
SelfType temp(*this); SelfType temp(*this);
++*this; ++*this;
return temp; return temp;
} }
SelfType operator--( int ) SelfType operator--(int) {
{
SelfType temp(*this); SelfType temp(*this);
--*this; --*this;
return temp; return temp;
} }
SelfType &operator--() SelfType& operator--() {
{
decrement(); decrement();
return *this; return *this;
} }
SelfType &operator++() SelfType& operator++() {
{
increment(); increment();
return *this; return *this;
} }
reference operator *() const reference operator*() const { return deref(); }
{
return deref();
}
};
pointer operator->() const { return &deref(); }
};
} // namespace Json } // namespace Json
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_H_INCLUDED #endif // CPPTL_JSON_H_INCLUDED

14
include/json/version.h Normal file
View File

@@ -0,0 +1,14 @@
// DO NOT EDIT. This file is generated by CMake from "version"
// and "version.h.in" files.
// Run CMake configure step to update it.
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.0.0"
# define JSONCPP_VERSION_MAJOR 1
# define JSONCPP_VERSION_MINOR 0
# define JSONCPP_VERSION_PATCH 0
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
#endif // JSON_VERSION_H_INCLUDED

View File

@@ -11,7 +11,13 @@
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <vector> #include <vector>
#include <string> #include <string>
# include <iostream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
namespace Json { namespace Json {
@@ -19,28 +25,37 @@ namespace Json {
/** \brief Abstract class for writers. /** \brief Abstract class for writers.
*/ */
class JSON_API Writer class JSON_API Writer {
{
public: public:
virtual ~Writer(); virtual ~Writer();
virtual std::string write(const Value& root) = 0; virtual std::string write(const Value& root) = 0;
}; };
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly). /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
*without formatting (not human friendly).
* *
* The JSON document is written in a single line. It is not intended for 'human' consumption, * The JSON document is written in a single line. It is not intended for 'human'
*consumption,
* but may be usefull to support feature such as RPC where bandwith is limited. * but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value * \sa Reader, Value
*/ */
class JSON_API FastWriter : public Writer class JSON_API FastWriter : public Writer {
{
public: public:
FastWriter(); FastWriter();
virtual ~FastWriter() {} virtual ~FastWriter() {}
void enableYAMLCompatibility(); void enableYAMLCompatibility();
/** \brief Drop the "null" string from the writer's output for nullValues.
* Strictly speaking, this is not valid JSON. But when the output is being
* fed to a browser's Javascript, it makes for smaller output and the
* browser can handle the output just fine.
*/
void dropNullPlaceholders();
void omitEndingLineFeed();
public: // overridden from Writer public: // overridden from Writer
virtual std::string write(const Value& root); virtual std::string write(const Value& root);
@@ -49,28 +64,34 @@ namespace Json {
std::string document_; std::string document_;
bool yamlCompatiblityEnabled_; bool yamlCompatiblityEnabled_;
bool dropNullPlaceholders_;
bool omitEndingLineFeed_;
}; };
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way. /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
*human friendly way.
* *
* The rules for line break and indent are as follow: * The rules for line break and indent are as follow:
* - Object value: * - Object value:
* - if empty then print {} without indent and line break * - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line * - if not empty the print '{', line break & indent, print one value per
*line
* and then unindent and line break and print '}'. * and then unindent and line break and print '}'.
* - Array value: * - Array value:
* - if empty then print [] without indent and line break * - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types, * - if the array contains no object value, empty array or some other value
* and all the values fit on one lines, then print the array on a single line. *types,
* and all the values fit on one lines, then print the array on a single
*line.
* - otherwise, it the values do not fit on one line, or the array contains * - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line. * object or non empty array, then print one value per line.
* *
* If the Value have comments then they are outputed according to their #CommentPlacement. * If the Value have comments then they are outputed according to their
*#CommentPlacement.
* *
* \sa Reader, Value, Value::setComment() * \sa Reader, Value, Value::setComment()
*/ */
class JSON_API StyledWriter: public Writer class JSON_API StyledWriter : public Writer {
{
public: public:
StyledWriter(); StyledWriter();
virtual ~StyledWriter() {} virtual ~StyledWriter() {}
@@ -106,28 +127,32 @@ namespace Json {
bool addChildValues_; bool addChildValues_;
}; };
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way, /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
human friendly way,
to a stream rather than to a string. to a stream rather than to a string.
* *
* The rules for line break and indent are as follow: * The rules for line break and indent are as follow:
* - Object value: * - Object value:
* - if empty then print {} without indent and line break * - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line * - if not empty the print '{', line break & indent, print one value per
line
* and then unindent and line break and print '}'. * and then unindent and line break and print '}'.
* - Array value: * - Array value:
* - if empty then print [] without indent and line break * - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types, * - if the array contains no object value, empty array or some other value
* and all the values fit on one lines, then print the array on a single line. types,
* and all the values fit on one lines, then print the array on a single
line.
* - otherwise, it the values do not fit on one line, or the array contains * - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line. * object or non empty array, then print one value per line.
* *
* If the Value have comments then they are outputed according to their #CommentPlacement. * If the Value have comments then they are outputed according to their
#CommentPlacement.
* *
* \param indentation Each level will be indented by this amount extra. * \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment() * \sa Reader, Value, Value::setComment()
*/ */
class JSON_API StyledStreamWriter class JSON_API StyledStreamWriter {
{
public: public:
StyledStreamWriter(std::string indentation = "\t"); StyledStreamWriter(std::string indentation = "\t");
~StyledStreamWriter() {} ~StyledStreamWriter() {}
@@ -136,7 +161,8 @@ namespace Json {
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.) * \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize. * \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value. * \note There is no point in deriving from Writer, since write() should not
* return a value.
*/ */
void write(std::ostream& out, const Value& root); void write(std::ostream& out, const Value& root);
@@ -176,10 +202,12 @@ namespace Json {
/// \brief Output using the StyledStreamWriter. /// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>() /// \see Json::operator>>()
std::ostream& operator<<( std::ostream&, const Value &root ); JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
} // namespace Json } // namespace Json
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_WRITER_H_INCLUDED #endif // JSON_WRITER_H_INCLUDED

View File

@@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "lib_json.vcxproj", "{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "jsontest.vcxproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_lib_json", "test_lib_json.vcxproj", "{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|Win32.ActiveCfg = Debug|Win32
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|Win32.Build.0 = Debug|Win32
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|x64.ActiveCfg = Debug|x64
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|x64.Build.0 = Debug|x64
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|Win32.ActiveCfg = Release|Win32
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|Win32.Build.0 = Release|Win32
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|x64.ActiveCfg = Release|x64
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|x64.Build.0 = Release|x64
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|Win32.ActiveCfg = Debug|Win32
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|Win32.Build.0 = Debug|Win32
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|x64.ActiveCfg = Debug|Win32
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|Win32.ActiveCfg = Release|Win32
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|Win32.Build.0 = Release|Win32
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|x64.ActiveCfg = Release|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|Win32.ActiveCfg = Debug|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|Win32.Build.0 = Debug|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|x64.ActiveCfg = Debug|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|Win32.ActiveCfg = Release|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|Win32.Build.0 = Release|Win32
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{25AF2DD2-D396-4668-B188-488C33B8E620}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/jsontest\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/jsontest\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/jsontest\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/jsontest\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)jsontest.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)jsontest.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)jsontest.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\jsontestrunner\main.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="lib_json.vcxproj">
<Project>{1e6c2c1c-6453-4129-ae3f-0ee8e6599c89}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{903591b3-ade3-4ce4-b1f9-1e175e62b014}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\jsontestrunner\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\lib_json\json_reader.cpp" />
<ClCompile Include="..\..\src\lib_json\json_value.cpp" />
<ClCompile Include="..\..\src\lib_json\json_writer.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\json\reader.h" />
<ClInclude Include="..\..\include\json\value.h" />
<ClInclude Include="..\..\include\json\writer.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>jsoncpp</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{c110bc57-c46e-476c-97ea-84d8014f431c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{ed718592-5acf-47b5-8f2b-b8224590da6a}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\lib_json\json_reader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\lib_json\json_value.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\lib_json\json_writer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\json\reader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\json\value.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\json\writer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}</ProjectGuid>
<RootNamespace>test_lib_json</RootNamespace>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/test_lib_json\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/test_lib_json\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/test_lib_json\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/test_lib_json\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)test_lib_json.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)test_lib_json.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PostBuildEvent>
<Message>Running all unit tests</Message>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)test_lib_json.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PostBuildEvent>
<Message>Running all unit tests</Message>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\test_lib_json\jsontest.cpp" />
<ClCompile Include="..\..\src\test_lib_json\main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\test_lib_json\jsontest.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="lib_json.vcxproj">
<Project>{1e6c2c1c-6453-4129-ae3f-0ee8e6599c89}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\src\test_lib_json\jsontest.cpp">
<Filter>Source Filter</Filter>
</ClCompile>
<ClCompile Include="..\..\src\test_lib_json\main.cpp">
<Filter>Source Filter</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Filter">
<UniqueIdentifier>{bf40cbfc-8e98-40b4-b9f3-7e8d579cbae2}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{5fd39074-89e6-4939-aa3f-694fefd296b1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\test_lib_json\jsontest.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -10,7 +10,11 @@ python makerelease.py --force --retag --platform=msvc6,msvc71,msvc80,mingw -uble
Example of invocation when doing a release: Example of invocation when doing a release:
python makerelease.py 0.5.0 0.6.0-dev python makerelease.py 0.5.0 0.6.0-dev
Note: This was for Subversion. Now that we are in GitHub, we do not
need to build versioned tarballs anymore, so makerelease.py is defunct.
""" """
from __future__ import print_function
import os.path import os.path
import subprocess import subprocess
import sys import sys
@@ -43,7 +47,7 @@ class SVNError(Exception):
def svn_command( command, *args ): def svn_command( command, *args ):
cmd = ['svn', '--non-interactive', command] + list(args) cmd = ['svn', '--non-interactive', command] + list(args)
print 'Running:', ' '.join( cmd ) print('Running:', ' '.join( cmd ))
process = subprocess.Popen( cmd, process = subprocess.Popen( cmd,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT ) stderr=subprocess.STDOUT )
@@ -81,7 +85,7 @@ def svn_check_if_tag_exist( tag_url ):
""" """
try: try:
list_stdout = svn_command( 'list', tag_url ) list_stdout = svn_command( 'list', tag_url )
except SVNError, e: except SVNError as e:
if e.returncode != 1 or not str(e).find('tag_url'): if e.returncode != 1 or not str(e).find('tag_url'):
raise e raise e
# otherwise ignore error, meaning tag does not exist # otherwise ignore error, meaning tag does not exist
@@ -114,7 +118,7 @@ def svn_export( tag_url, export_dir ):
def fix_sources_eol( dist_dir ): def fix_sources_eol( dist_dir ):
"""Set file EOL for tarball distribution. """Set file EOL for tarball distribution.
""" """
print 'Preparing exported source file EOL for distribution...' print('Preparing exported source file EOL for distribution...')
prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
win_sources = antglob.glob( dist_dir, win_sources = antglob.glob( dist_dir,
includes = '**/*.sln **/*.vcproj', includes = '**/*.sln **/*.vcproj',
@@ -145,7 +149,7 @@ def download( url, target_path ):
def check_compile( distcheck_top_dir, platform ): def check_compile( distcheck_top_dir, platform ):
cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check'] cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
print 'Running:', ' '.join( cmd ) print('Running:', ' '.join( cmd ))
log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform ) log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
flog = open( log_path, 'wb' ) flog = open( log_path, 'wb' )
try: try:
@@ -176,9 +180,9 @@ def run_sftp_batch( userhost, sftp, batch, retry=0 ):
# psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc # psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost] cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
error = None error = None
for retry_index in xrange(0, max(1,retry)): for retry_index in range(0, max(1,retry)):
heading = retry_index == 0 and 'Running:' or 'Retrying:' heading = retry_index == 0 and 'Running:' or 'Retrying:'
print heading, ' '.join( cmd ) print(heading, ' '.join( cmd ))
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
stdout = process.communicate()[0] stdout = process.communicate()[0]
if process.returncode != 0: if process.returncode != 0:
@@ -216,21 +220,21 @@ exit
upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] ) upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
paths_to_remove = existing_paths - upload_paths paths_to_remove = existing_paths - upload_paths
if paths_to_remove: if paths_to_remove:
print 'Removing the following file from web:' print('Removing the following file from web:')
print '\n'.join( paths_to_remove ) print('\n'.join( paths_to_remove ))
stdout = run_sftp_batch( userhost, sftp, """cd htdocs stdout = run_sftp_batch( userhost, sftp, """cd htdocs
rm %s rm %s
exit""" % ' '.join(paths_to_remove) ) exit""" % ' '.join(paths_to_remove) )
print 'Uploading %d files:' % len(upload_paths) print('Uploading %d files:' % len(upload_paths))
batch_size = 10 batch_size = 10
upload_paths = list(upload_paths) upload_paths = list(upload_paths)
start_time = time.time() start_time = time.time()
for index in xrange(0,len(upload_paths),batch_size): for index in range(0,len(upload_paths),batch_size):
paths = upload_paths[index:index+batch_size] paths = upload_paths[index:index+batch_size]
file_per_sec = (time.time() - start_time) / (index+1) file_per_sec = (time.time() - start_time) / (index+1)
remaining_files = len(upload_paths) - index remaining_files = len(upload_paths) - index
remaining_sec = file_per_sec * remaining_files remaining_sec = file_per_sec * remaining_files
print '%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec) print('%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec))
run_sftp_batch( userhost, sftp, """cd htdocs run_sftp_batch( userhost, sftp, """cd htdocs
lcd %s lcd %s
mput %s mput %s
@@ -294,7 +298,7 @@ Warning: --force should only be used when developping/testing the release script
else: else:
msg = check_no_pending_commit() msg = check_no_pending_commit()
if not msg: if not msg:
print 'Setting version to', release_version print('Setting version to', release_version)
set_version( release_version ) set_version( release_version )
svn_commit( 'Release ' + release_version ) svn_commit( 'Release ' + release_version )
tag_url = svn_join_url( SVN_TAG_ROOT, release_version ) tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
@@ -302,11 +306,11 @@ Warning: --force should only be used when developping/testing the release script
if options.retag_release: if options.retag_release:
svn_remove_tag( tag_url, 'Overwriting previous tag' ) svn_remove_tag( tag_url, 'Overwriting previous tag' )
else: else:
print 'Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url print('Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url)
sys.exit( 1 ) sys.exit( 1 )
svn_tag_sandbox( tag_url, 'Release ' + release_version ) svn_tag_sandbox( tag_url, 'Release ' + release_version )
print 'Generated doxygen document...' print('Generated doxygen document...')
## doc_dirname = r'jsoncpp-api-html-0.5.0' ## doc_dirname = r'jsoncpp-api-html-0.5.0'
## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz' ## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True ) doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
@@ -320,11 +324,11 @@ Warning: --force should only be used when developping/testing the release script
source_dir = 'jsoncpp-src-' + release_version source_dir = 'jsoncpp-src-' + release_version
source_tarball_path = 'dist/%s.tar.gz' % source_dir source_tarball_path = 'dist/%s.tar.gz' % source_dir
print 'Generating source tarball to', source_tarball_path print('Generating source tarball to', source_tarball_path)
tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir ) tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir
print 'Generating amalgamation source tarball to', amalgamation_tarball_path print('Generating amalgamation source tarball to', amalgamation_tarball_path)
amalgamation_dir = 'dist/amalgamation' amalgamation_dir = 'dist/amalgamation'
amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' ) amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' )
amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version
@@ -334,41 +338,41 @@ Warning: --force should only be used when developping/testing the release script
# Decompress source tarball, download and install scons-local # Decompress source tarball, download and install scons-local
distcheck_dir = 'dist/distcheck' distcheck_dir = 'dist/distcheck'
distcheck_top_dir = distcheck_dir + '/' + source_dir distcheck_top_dir = distcheck_dir + '/' + source_dir
print 'Decompressing source tarball to', distcheck_dir print('Decompressing source tarball to', distcheck_dir)
rmdir_if_exist( distcheck_dir ) rmdir_if_exist( distcheck_dir )
tarball.decompress( source_tarball_path, distcheck_dir ) tarball.decompress( source_tarball_path, distcheck_dir )
scons_local_path = 'dist/scons-local.tar.gz' scons_local_path = 'dist/scons-local.tar.gz'
print 'Downloading scons-local to', scons_local_path print('Downloading scons-local to', scons_local_path)
download( SCONS_LOCAL_URL, scons_local_path ) download( SCONS_LOCAL_URL, scons_local_path )
print 'Decompressing scons-local to', distcheck_top_dir print('Decompressing scons-local to', distcheck_top_dir)
tarball.decompress( scons_local_path, distcheck_top_dir ) tarball.decompress( scons_local_path, distcheck_top_dir )
# Run compilation # Run compilation
print 'Compiling decompressed tarball' print('Compiling decompressed tarball')
all_build_status = True all_build_status = True
for platform in options.platforms.split(','): for platform in options.platforms.split(','):
print 'Testing platform:', platform print('Testing platform:', platform)
build_status, log_path = check_compile( distcheck_top_dir, platform ) build_status, log_path = check_compile( distcheck_top_dir, platform )
print 'see build log:', log_path print('see build log:', log_path)
print build_status and '=> ok' or '=> FAILED' print(build_status and '=> ok' or '=> FAILED')
all_build_status = all_build_status and build_status all_build_status = all_build_status and build_status
if not build_status: if not build_status:
print 'Testing failed on at least one platform, aborting...' print('Testing failed on at least one platform, aborting...')
svn_remove_tag( tag_url, 'Removing tag due to failed testing' ) svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
sys.exit(1) sys.exit(1)
if options.user: if options.user:
if not options.no_web: if not options.no_web:
print 'Uploading documentation using user', options.user print('Uploading documentation using user', options.user)
sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp ) sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
print 'Completed documentation upload' print('Completed documentation upload')
print 'Uploading source and documentation tarballs for release using user', options.user print('Uploading source and documentation tarballs for release using user', options.user)
sourceforge_release_tarball( SOURCEFORGE_PROJECT, sourceforge_release_tarball( SOURCEFORGE_PROJECT,
[source_tarball_path, doc_tarball_path], [source_tarball_path, doc_tarball_path],
user=options.user, sftp=options.sftp ) user=options.user, sftp=options.sftp )
print 'Source and doc release tarballs uploaded' print('Source and doc release tarballs uploaded')
else: else:
print 'No upload user specified. Web site and download tarbal were not uploaded.' print('No upload user specified. Web site and download tarbal were not uploaded.')
print 'Tarball can be found at:', doc_tarball_path print('Tarball can be found at:', doc_tarball_path)
# Set next version number and commit # Set next version number and commit
set_version( next_version ) set_version( next_version )

11
pkg-config/jsoncpp.pc.in Normal file
View File

@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/@INCLUDE_INSTALL_DIR@
Name: jsoncpp
Description: A C++ library for interacting with JSON
Version: @JSONCPP_VERSION@
URL: https://github.com/open-source-parsers/jsoncpp
Libs: -L${libdir} -ljsoncpp
Cflags: -I${includedir}

View File

@@ -1,5 +1,6 @@
import re import re
from SCons.Script import * # the usual scons stuff you get in a SConscript from SCons.Script import * # the usual scons stuff you get in a SConscript
import collections
def generate(env): def generate(env):
""" """
@@ -25,28 +26,28 @@ def generate(env):
contents = f.read() contents = f.read()
f.close() f.close()
except: except:
raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile raise SCons.Errors.UserError("Can't read source file %s"%sourcefile)
for (k,v) in dict.items(): for (k,v) in list(dict.items()):
contents = re.sub(k, v, contents) contents = re.sub(k, v, contents)
try: try:
f = open(targetfile, 'wb') f = open(targetfile, 'wb')
f.write(contents) f.write(contents)
f.close() f.close()
except: except:
raise SCons.Errors.UserError, "Can't write target file %s"%targetfile raise SCons.Errors.UserError("Can't write target file %s"%targetfile)
return 0 # success return 0 # success
def subst_in_file(target, source, env): def subst_in_file(target, source, env):
if not env.has_key('SUBST_DICT'): if 'SUBST_DICT' not in env:
raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." raise SCons.Errors.UserError("SubstInFile requires SUBST_DICT to be set.")
d = dict(env['SUBST_DICT']) # copy it d = dict(env['SUBST_DICT']) # copy it
for (k,v) in d.items(): for (k,v) in list(d.items()):
if callable(v): if isinstance(v, collections.Callable):
d[k] = env.subst(v()).replace('\\','\\\\') d[k] = env.subst(v()).replace('\\','\\\\')
elif SCons.Util.is_String(v): elif SCons.Util.is_String(v):
d[k] = env.subst(v).replace('\\','\\\\') d[k] = env.subst(v).replace('\\','\\\\')
else: else:
raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) raise SCons.Errors.UserError("SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)))
for (t,s) in zip(target, source): for (t,s) in zip(target, source):
return do_subst_in_file(str(t), str(s), d) return do_subst_in_file(str(t), str(s), d)
@@ -60,8 +61,8 @@ def generate(env):
Returns original target, source tuple unchanged. Returns original target, source tuple unchanged.
""" """
d = env['SUBST_DICT'].copy() # copy it d = env['SUBST_DICT'].copy() # copy it
for (k,v) in d.items(): for (k,v) in list(d.items()):
if callable(v): if isinstance(v, collections.Callable):
d[k] = env.subst(v()) d[k] = env.subst(v())
elif SCons.Util.is_String(v): elif SCons.Util.is_String(v):
d[k]=env.subst(v) d[k]=env.subst(v)

5
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,5 @@
ADD_SUBDIRECTORY(lib_json)
IF(JSONCPP_WITH_TESTS)
ADD_SUBDIRECTORY(jsontestrunner)
ADD_SUBDIRECTORY(test_lib_json)
ENDIF(JSONCPP_WITH_TESTS)

View File

@@ -0,0 +1,22 @@
FIND_PACKAGE(PythonInterp 2.6 REQUIRED)
IF(JSONCPP_LIB_BUILD_SHARED)
ADD_DEFINITIONS( -DJSON_DLL )
ENDIF(JSONCPP_LIB_BUILD_SHARED)
ADD_EXECUTABLE(jsontestrunner_exe
main.cpp
)
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
IF(PYTHONINTERP_FOUND)
# Run end to end parser/writer tests
SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test)
SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py)
ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests ALL
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
DEPENDS jsontestrunner_exe jsoncpp_test
)
ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests)
ENDIF(PYTHONINTERP_FOUND)

View File

@@ -6,7 +6,6 @@
/* This executable is used for testing parser/writer using real JSON files. /* This executable is used for testing parser/writer using real JSON files.
*/ */
#include <json/json.h> #include <json/json.h>
#include <algorithm> // sort #include <algorithm> // sort
#include <stdio.h> #include <stdio.h>
@@ -15,9 +14,35 @@
#pragma warning(disable : 4996) // disable fopen deprecation warning #pragma warning(disable : 4996) // disable fopen deprecation warning
#endif #endif
static std::string static std::string normalizeFloatingPointStr(double value) {
readInputTestFile( const char *path ) char buffer[32];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
#else
snprintf(buffer, sizeof(buffer), "%.16g", value);
#endif
buffer[sizeof(buffer) - 1] = 0;
std::string s(buffer);
std::string::size_type index = s.find_last_of("eE");
if (index != std::string::npos) {
std::string::size_type hasSign =
(s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
std::string::size_type exponentStartIndex = index + 1 + hasSign;
std::string normalized = s.substr(0, exponentStartIndex);
std::string::size_type indexDigit =
s.find_first_not_of('0', exponentStartIndex);
std::string exponent = "0";
if (indexDigit !=
std::string::npos) // There is an exponent different from 0
{ {
exponent = s.substr(indexDigit);
}
return normalized + exponent;
}
return s;
}
static std::string readInputTestFile(const char* path) {
FILE* file = fopen(path, "rb"); FILE* file = fopen(path, "rb");
if (!file) if (!file)
return std::string(""); return std::string("");
@@ -34,23 +59,32 @@ readInputTestFile( const char *path )
return text; return text;
} }
static void static void
printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." ) printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
{ if (value.hasComment(Json::commentBefore)) {
switch ( value.type() ) fprintf(fout, "%s\n", value.getComment(Json::commentBefore).c_str());
{ }
switch (value.type()) {
case Json::nullValue: case Json::nullValue:
fprintf(fout, "%s=null\n", path.c_str()); fprintf(fout, "%s=null\n", path.c_str());
break; break;
case Json::intValue: case Json::intValue:
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() ); fprintf(fout,
"%s=%s\n",
path.c_str(),
Json::valueToString(value.asLargestInt()).c_str());
break; break;
case Json::uintValue: case Json::uintValue:
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() ); fprintf(fout,
"%s=%s\n",
path.c_str(),
Json::valueToString(value.asLargestUInt()).c_str());
break; break;
case Json::realValue: case Json::realValue:
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() ); fprintf(fout,
"%s=%s\n",
path.c_str(),
normalizeFloatingPointStr(value.asDouble()).c_str());
break; break;
case Json::stringValue: case Json::stringValue:
fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str()); fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str());
@@ -58,62 +92,58 @@ printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
case Json::booleanValue: case Json::booleanValue:
fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false"); fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false");
break; break;
case Json::arrayValue: case Json::arrayValue: {
{
fprintf(fout, "%s=[]\n", path.c_str()); fprintf(fout, "%s=[]\n", path.c_str());
int size = value.size(); int size = value.size();
for ( int index =0; index < size; ++index ) for (int index = 0; index < size; ++index) {
{
static char buffer[16]; static char buffer[16];
sprintf( buffer, "[%d]", index ); #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
sprintf_s(buffer, sizeof(buffer), "[%d]", index);
#else
snprintf(buffer, sizeof(buffer), "[%d]", index);
#endif
printValueTree(fout, value[index], path + buffer); printValueTree(fout, value[index], path + buffer);
} }
} } break;
break; case Json::objectValue: {
case Json::objectValue:
{
fprintf(fout, "%s={}\n", path.c_str()); fprintf(fout, "%s={}\n", path.c_str());
Json::Value::Members members(value.getMemberNames()); Json::Value::Members members(value.getMemberNames());
std::sort(members.begin(), members.end()); std::sort(members.begin(), members.end());
std::string suffix = *(path.end() - 1) == '.' ? "" : "."; std::string suffix = *(path.end() - 1) == '.' ? "" : ".";
for (Json::Value::Members::iterator it = members.begin(); for (Json::Value::Members::iterator it = members.begin();
it != members.end(); it != members.end();
++it ) ++it) {
{
const std::string& name = *it; const std::string& name = *it;
printValueTree(fout, value[name], path + suffix + name); printValueTree(fout, value[name], path + suffix + name);
} }
} } break;
break;
default: default:
break; break;
} }
if (value.hasComment(Json::commentAfter)) {
fprintf(fout, "%s\n", value.getComment(Json::commentAfter).c_str());
}
} }
static int parseAndSaveValueTree(const std::string& input,
static int
parseAndSaveValueTree( const std::string &input,
const std::string& actual, const std::string& actual,
const std::string& kind, const std::string& kind,
Json::Value& root, Json::Value& root,
const Json::Features& features, const Json::Features& features,
bool parseOnly ) bool parseOnly) {
{
Json::Reader reader(features); Json::Reader reader(features);
bool parsingSuccessful = reader.parse(input, root); bool parsingSuccessful = reader.parse(input, root);
if ( !parsingSuccessful ) if (!parsingSuccessful) {
{
printf("Failed to parse %s file: \n%s\n", printf("Failed to parse %s file: \n%s\n",
kind.c_str(), kind.c_str(),
reader.getFormattedErrorMessages().c_str()); reader.getFormattedErrorMessages().c_str());
return 1; return 1;
} }
if ( !parseOnly ) if (!parseOnly) {
{
FILE* factual = fopen(actual.c_str(), "wt"); FILE* factual = fopen(actual.c_str(), "wt");
if ( !factual ) if (!factual) {
{
printf("Failed to create %s actual file.\n", kind.c_str()); printf("Failed to create %s actual file.\n", kind.c_str());
return 2; return 2;
} }
@@ -123,19 +153,15 @@ parseAndSaveValueTree( const std::string &input,
return 0; return 0;
} }
static int rewriteValueTree(const std::string& rewritePath,
static int
rewriteValueTree( const std::string &rewritePath,
const Json::Value& root, const Json::Value& root,
std::string &rewrite ) std::string& rewrite) {
{
// Json::FastWriter writer; // Json::FastWriter writer;
// writer.enableYAMLCompatibility(); // writer.enableYAMLCompatibility();
Json::StyledWriter writer; Json::StyledWriter writer;
rewrite = writer.write(root); rewrite = writer.write(root);
FILE* fout = fopen(rewritePath.c_str(), "wt"); FILE* fout = fopen(rewritePath.c_str(), "wt");
if ( !fout ) if (!fout) {
{
printf("Failed to create rewrite file: %s\n", rewritePath.c_str()); printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
return 2; return 2;
} }
@@ -144,11 +170,8 @@ rewriteValueTree( const std::string &rewritePath,
return 0; return 0;
} }
static std::string removeSuffix(const std::string& path,
static std::string const std::string& extension) {
removeSuffix( const std::string &path,
const std::string &extension )
{
if (extension.length() >= path.length()) if (extension.length() >= path.length())
return std::string(""); return std::string("");
std::string suffix = path.substr(path.length() - extension.length()); std::string suffix = path.substr(path.length() - extension.length());
@@ -157,10 +180,7 @@ removeSuffix( const std::string &path,
return path.substr(0, path.length() - extension.length()); return path.substr(0, path.length() - extension.length());
} }
static void printConfig() {
static void
printConfig()
{
// Print the configuration used to compile JsonCpp // Print the configuration used to compile JsonCpp
#if defined(JSON_NO_INT64) #if defined(JSON_NO_INT64)
printf("JSON_NO_INT64=1\n"); printf("JSON_NO_INT64=1\n");
@@ -169,42 +189,34 @@ printConfig()
#endif #endif
} }
static int printUsage(const char* argv[]) {
static int
printUsage( const char *argv[] )
{
printf("Usage: %s [--strict] input-json-file", argv[0]); printf("Usage: %s [--strict] input-json-file", argv[0]);
return 3; return 3;
} }
int parseCommandLine(int argc,
int const char* argv[],
parseCommandLine( int argc, const char *argv[], Json::Features& features,
Json::Features &features, std::string &path, std::string& path,
bool &parseOnly ) bool& parseOnly) {
{
parseOnly = false; parseOnly = false;
if ( argc < 2 ) if (argc < 2) {
{
return printUsage(argv); return printUsage(argv);
} }
int index = 1; int index = 1;
if ( std::string(argv[1]) == "--json-checker" ) if (std::string(argv[1]) == "--json-checker") {
{
features = Json::Features::strictMode(); features = Json::Features::strictMode();
parseOnly = true; parseOnly = true;
++index; ++index;
} }
if ( std::string(argv[1]) == "--json-config" ) if (std::string(argv[1]) == "--json-config") {
{
printConfig(); printConfig();
return 3; return 3;
} }
if ( index == argc || index + 1 < argc ) if (index == argc || index + 1 < argc) {
{
return printUsage(argv); return printUsage(argv);
} }
@@ -212,31 +224,26 @@ parseCommandLine( int argc, const char *argv[],
return 0; return 0;
} }
int main(int argc, const char* argv[]) {
int main( int argc, const char *argv[] )
{
std::string path; std::string path;
Json::Features features; Json::Features features;
bool parseOnly; bool parseOnly;
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly); int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
if ( exitCode != 0 ) if (exitCode != 0) {
{
return exitCode; return exitCode;
} }
try try {
{
std::string input = readInputTestFile(path.c_str()); std::string input = readInputTestFile(path.c_str());
if ( input.empty() ) if (input.empty()) {
{
printf("Failed to read input or empty input: %s\n", path.c_str()); printf("Failed to read input or empty input: %s\n", path.c_str());
return 3; return 3;
} }
std::string basePath = removeSuffix(argv[1], ".json"); std::string basePath = removeSuffix(argv[1], ".json");
if ( !parseOnly && basePath.empty() ) if (!parseOnly && basePath.empty()) {
{ printf("Bad input path. Path does not end with '.expected':\n%s\n",
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() ); path.c_str());
return 3; return 3;
} }
@@ -245,25 +252,26 @@ int main( int argc, const char *argv[] )
std::string rewriteActualPath = basePath + ".actual-rewrite"; std::string rewriteActualPath = basePath + ".actual-rewrite";
Json::Value root; Json::Value root;
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly ); exitCode = parseAndSaveValueTree(
if ( exitCode == 0 && !parseOnly ) input, actualPath, "input", root, features, parseOnly);
{ if (exitCode == 0 && !parseOnly) {
std::string rewrite; std::string rewrite;
exitCode = rewriteValueTree(rewritePath, root, rewrite); exitCode = rewriteValueTree(rewritePath, root, rewrite);
if ( exitCode == 0 ) if (exitCode == 0) {
{
Json::Value rewriteRoot; Json::Value rewriteRoot;
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, exitCode = parseAndSaveValueTree(rewrite,
"rewrite", rewriteRoot, features, parseOnly ); rewriteActualPath,
"rewrite",
rewriteRoot,
features,
parseOnly);
} }
} }
} }
catch ( const std::exception &e ) catch (const std::exception& e) {
{
printf("Unhandled exception:\n%s\n", e.what()); printf("Unhandled exception:\n%s\n", e.what());
exitCode = 1; exitCode = 1;
} }
return exitCode; return exitCode;
} }

View File

@@ -0,0 +1,57 @@
OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF)
IF(JSONCPP_LIB_BUILD_SHARED)
SET(JSONCPP_LIB_TYPE SHARED)
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
ELSE(JSONCPP_LIB_BUILD_SHARED)
SET(JSONCPP_LIB_TYPE STATIC)
ENDIF(JSONCPP_LIB_BUILD_SHARED)
if( CMAKE_COMPILER_IS_GNUCXX )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
endif( CMAKE_COMPILER_IS_GNUCXX )
SET( JSONCPP_INCLUDE_DIR ../../include )
SET( PUBLIC_HEADERS
${JSONCPP_INCLUDE_DIR}/json/config.h
${JSONCPP_INCLUDE_DIR}/json/forwards.h
${JSONCPP_INCLUDE_DIR}/json/features.h
${JSONCPP_INCLUDE_DIR}/json/value.h
${JSONCPP_INCLUDE_DIR}/json/reader.h
${JSONCPP_INCLUDE_DIR}/json/writer.h
${JSONCPP_INCLUDE_DIR}/json/assertions.h
${JSONCPP_INCLUDE_DIR}/json/version.h
)
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE}
${PUBLIC_HEADERS}
json_tool.h
json_reader.cpp
json_batchallocator.h
json_valueiterator.inl
json_value.cpp
json_writer.cpp
version.h.in
)
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR} )
# Install instructions for this target
IF(JSONCPP_WITH_CMAKE_PACKAGE)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib
PUBLIC $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSON_INCLUDE_DIR}>
)
SET(INSTALL_EXPORT EXPORT jsoncpp)
ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT)
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}
)

View File

@@ -18,35 +18,30 @@ namespace Json {
* This memory allocator allocates memory for a batch of object (specified by * This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page). * the page size, the number of object in each page).
* *
* It does not allow the destruction of a single object. All the allocated objects * It does not allow the destruction of a single object. All the allocated
* can be destroyed at once. The memory can be either released or reused for future * objects can be destroyed at once. The memory can be either released or reused
* allocation. * for future allocation.
* *
* The in-place new operator must be used to construct the object using the pointer * The in-place new operator must be used to construct the object using the
* returned by allocate. * pointer returned by allocate.
*/ */
template<typename AllocatedType template <typename AllocatedType, const unsigned int objectPerAllocation>
,const unsigned int objectPerAllocation> class BatchAllocator {
class BatchAllocator
{
public: public:
typedef AllocatedType Type;
BatchAllocator(unsigned int objectsPerPage = 255) BatchAllocator(unsigned int objectsPerPage = 255)
: freeHead_( 0 ) : freeHead_(0), objectsPerPage_(objectsPerPage) {
, objectsPerPage_( objectsPerPage ) // printf( "Size: %d => %s\n", sizeof(AllocatedType),
{ // typeid(AllocatedType).name() );
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); assert(sizeof(AllocatedType) * objectPerAllocation >=
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. sizeof(AllocatedType*)); // We must be able to store a slist in the
// object free space.
assert(objectsPerPage >= 16); assert(objectsPerPage >= 16);
batches_ = allocateBatch(0); // allocated a dummy page batches_ = allocateBatch(0); // allocated a dummy page
currentBatch_ = batches_; currentBatch_ = batches_;
} }
~BatchAllocator() ~BatchAllocator() {
{ for (BatchInfo* batch = batches_; batch;) {
for ( BatchInfo *batch = batches_; batch; )
{
BatchInfo* nextBatch = batch->next_; BatchInfo* nextBatch = batch->next_;
free(batch); free(batch);
batch = nextBatch; batch = nextBatch;
@@ -54,17 +49,16 @@ public:
} }
/// allocate space for an array of objectPerAllocation object. /// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors. /// @warning it is the responsability of the caller to call objects
AllocatedType *allocate() /// constructors.
{ AllocatedType* allocate() {
if (freeHead_) // returns node from free list. if (freeHead_) // returns node from free list.
{ {
AllocatedType* object = freeHead_; AllocatedType* object = freeHead_;
freeHead_ = *(AllocatedType**)object; freeHead_ = *(AllocatedType**)object;
return object; return object;
} }
if ( currentBatch_->used_ == currentBatch_->end_ ) if (currentBatch_->used_ == currentBatch_->end_) {
{
currentBatch_ = currentBatch_->next_; currentBatch_ = currentBatch_->next_;
while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_) while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
currentBatch_ = currentBatch_->next_; currentBatch_ = currentBatch_->next_;
@@ -82,17 +76,16 @@ public:
} }
/// Release the object. /// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object. /// @warning it is the responsability of the caller to actually destruct the
void release( AllocatedType *object ) /// object.
{ void release(AllocatedType* object) {
assert(object != 0); assert(object != 0);
*(AllocatedType**)object = freeHead_; *(AllocatedType**)object = freeHead_;
freeHead_ = object; freeHead_ = object;
} }
private: private:
struct BatchInfo struct BatchInfo {
{
BatchInfo* next_; BatchInfo* next_;
AllocatedType* used_; AllocatedType* used_;
AllocatedType* end_; AllocatedType* end_;
@@ -103,10 +96,10 @@ private:
BatchAllocator(const BatchAllocator&); BatchAllocator(const BatchAllocator&);
void operator=(const BatchAllocator&); void operator=(const BatchAllocator&);
static BatchInfo *allocateBatch( unsigned int objectsPerPage ) static BatchInfo* allocateBatch(unsigned int objectsPerPage) {
{ const unsigned int mallocSize =
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize)); BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize));
batch->next_ = 0; batch->next_ = 0;
batch->used_ = batch->buffer_; batch->used_ = batch->buffer_;
@@ -121,10 +114,8 @@ private:
unsigned int objectsPerPage_; unsigned int objectsPerPage_;
}; };
} // namespace Json } // namespace Json
#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED

View File

@@ -15,63 +15,48 @@ namespace Json {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueArrayAllocator::~ValueArrayAllocator() ValueArrayAllocator::~ValueArrayAllocator() {}
{
}
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// class DefaultValueArrayAllocator // class DefaultValueArrayAllocator
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
class DefaultValueArrayAllocator : public ValueArrayAllocator class DefaultValueArrayAllocator : public ValueArrayAllocator {
{
public: // overridden from ValueArrayAllocator public: // overridden from ValueArrayAllocator
virtual ~DefaultValueArrayAllocator() virtual ~DefaultValueArrayAllocator() {}
{
}
virtual ValueInternalArray *newArray() virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
{
return new ValueInternalArray();
}
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
{
return new ValueInternalArray(other); return new ValueInternalArray(other);
} }
virtual void destructArray( ValueInternalArray *array ) virtual void destructArray(ValueInternalArray* array) { delete array; }
{
delete array;
}
virtual void reallocateArrayPageIndex( Value **&indexes, virtual void
reallocateArrayPageIndex(Value**& indexes,
ValueInternalArray::PageIndex& indexCount, ValueInternalArray::PageIndex& indexCount,
ValueInternalArray::PageIndex minNewIndexCount ) ValueInternalArray::PageIndex minNewIndexCount) {
{
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1; ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
if (minNewIndexCount > newIndexCount) if (minNewIndexCount > newIndexCount)
newIndexCount = minNewIndexCount; newIndexCount = minNewIndexCount;
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount); void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
if ( !newIndexes ) JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
throw std::bad_alloc();
indexCount = newIndexCount; indexCount = newIndexCount;
indexes = static_cast<Value**>(newIndexes); indexes = static_cast<Value**>(newIndexes);
} }
virtual void releaseArrayPageIndex(Value** indexes, virtual void releaseArrayPageIndex(Value** indexes,
ValueInternalArray::PageIndex indexCount ) ValueInternalArray::PageIndex indexCount) {
{
if (indexes) if (indexes)
free(indexes); free(indexes);
} }
virtual Value *allocateArrayPage() virtual Value* allocateArrayPage() {
{ return static_cast<Value*>(
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
} }
virtual void releaseArrayPage( Value *value ) virtual void releaseArrayPage(Value* value) {
{
if (value) if (value)
free(value); free(value);
} }
@@ -79,188 +64,145 @@ public: // overridden from ValueArrayAllocator
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
/// @todo make this thread-safe (lock when accessign batch allocator) /// @todo make this thread-safe (lock when accessign batch allocator)
class DefaultValueArrayAllocator : public ValueArrayAllocator class DefaultValueArrayAllocator : public ValueArrayAllocator {
{
public: // overridden from ValueArrayAllocator public: // overridden from ValueArrayAllocator
virtual ~DefaultValueArrayAllocator() virtual ~DefaultValueArrayAllocator() {}
{
}
virtual ValueInternalArray *newArray() virtual ValueInternalArray* newArray() {
{
ValueInternalArray* array = arraysAllocator_.allocate(); ValueInternalArray* array = arraysAllocator_.allocate();
new (array) ValueInternalArray(); // placement new new (array) ValueInternalArray(); // placement new
return array; return array;
} }
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
{
ValueInternalArray* array = arraysAllocator_.allocate(); ValueInternalArray* array = arraysAllocator_.allocate();
new (array) ValueInternalArray(other); // placement new new (array) ValueInternalArray(other); // placement new
return array; return array;
} }
virtual void destructArray( ValueInternalArray *array ) virtual void destructArray(ValueInternalArray* array) {
{ if (array) {
if ( array )
{
array->~ValueInternalArray(); array->~ValueInternalArray();
arraysAllocator_.release(array); arraysAllocator_.release(array);
} }
} }
virtual void reallocateArrayPageIndex( Value **&indexes, virtual void
reallocateArrayPageIndex(Value**& indexes,
ValueInternalArray::PageIndex& indexCount, ValueInternalArray::PageIndex& indexCount,
ValueInternalArray::PageIndex minNewIndexCount ) ValueInternalArray::PageIndex minNewIndexCount) {
{
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1; ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
if (minNewIndexCount > newIndexCount) if (minNewIndexCount > newIndexCount)
newIndexCount = minNewIndexCount; newIndexCount = minNewIndexCount;
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount); void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
if ( !newIndexes ) JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
throw std::bad_alloc();
indexCount = newIndexCount; indexCount = newIndexCount;
indexes = static_cast<Value**>(newIndexes); indexes = static_cast<Value**>(newIndexes);
} }
virtual void releaseArrayPageIndex(Value** indexes, virtual void releaseArrayPageIndex(Value** indexes,
ValueInternalArray::PageIndex indexCount ) ValueInternalArray::PageIndex indexCount) {
{
if (indexes) if (indexes)
free(indexes); free(indexes);
} }
virtual Value *allocateArrayPage() virtual Value* allocateArrayPage() {
{
return static_cast<Value*>(pagesAllocator_.allocate()); return static_cast<Value*>(pagesAllocator_.allocate());
} }
virtual void releaseArrayPage( Value *value ) virtual void releaseArrayPage(Value* value) {
{
if (value) if (value)
pagesAllocator_.release(value); pagesAllocator_.release(value);
} }
private: private:
BatchAllocator<ValueInternalArray, 1> arraysAllocator_; BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_; BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
}; };
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
static ValueArrayAllocator *&arrayAllocator() static ValueArrayAllocator*& arrayAllocator() {
{
static DefaultValueArrayAllocator defaultAllocator; static DefaultValueArrayAllocator defaultAllocator;
static ValueArrayAllocator* arrayAllocator = &defaultAllocator; static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
return arrayAllocator; return arrayAllocator;
} }
static struct DummyArrayAllocatorInitializer { static struct DummyArrayAllocatorInitializer {
DummyArrayAllocatorInitializer() DummyArrayAllocatorInitializer() {
{ arrayAllocator(); // ensure arrayAllocator() statics are initialized before
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). // main().
} }
} dummyArrayAllocatorInitializer; } dummyArrayAllocatorInitializer;
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// class ValueInternalArray // class ValueInternalArray
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
bool bool ValueInternalArray::equals(const IteratorState& x,
ValueInternalArray::equals( const IteratorState &x, const IteratorState& other) {
const IteratorState &other ) return x.array_ == other.array_ &&
{ x.currentItemIndex_ == other.currentItemIndex_ &&
return x.array_ == other.array_ x.currentPageIndex_ == other.currentPageIndex_;
&& x.currentItemIndex_ == other.currentItemIndex_
&& x.currentPageIndex_ == other.currentPageIndex_;
} }
void ValueInternalArray::increment(IteratorState& it) {
void JSON_ASSERT_MESSAGE(
ValueInternalArray::increment( IteratorState &it ) it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
{ it.currentItemIndex_ !=
JSON_ASSERT_MESSAGE( it.array_ && it.array_->size_,
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
!= it.array_->size_,
"ValueInternalArray::increment(): moving iterator beyond end"); "ValueInternalArray::increment(): moving iterator beyond end");
++(it.currentItemIndex_); ++(it.currentItemIndex_);
if ( it.currentItemIndex_ == itemsPerPage ) if (it.currentItemIndex_ == itemsPerPage) {
{
it.currentItemIndex_ = 0; it.currentItemIndex_ = 0;
++(it.currentPageIndex_); ++(it.currentPageIndex_);
} }
} }
void ValueInternalArray::decrement(IteratorState& it) {
void JSON_ASSERT_MESSAGE(
ValueInternalArray::decrement( IteratorState &it ) it.array_ && it.currentPageIndex_ == it.array_->pages_ &&
{ it.currentItemIndex_ == 0,
JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
&& it.currentItemIndex_ == 0,
"ValueInternalArray::decrement(): moving iterator beyond end"); "ValueInternalArray::decrement(): moving iterator beyond end");
if ( it.currentItemIndex_ == 0 ) if (it.currentItemIndex_ == 0) {
{
it.currentItemIndex_ = itemsPerPage - 1; it.currentItemIndex_ = itemsPerPage - 1;
--(it.currentPageIndex_); --(it.currentPageIndex_);
} } else {
else
{
--(it.currentItemIndex_); --(it.currentItemIndex_);
} }
} }
Value& ValueInternalArray::unsafeDereference(const IteratorState& it) {
Value &
ValueInternalArray::unsafeDereference( const IteratorState &it )
{
return (*(it.currentPageIndex_))[it.currentItemIndex_]; return (*(it.currentPageIndex_))[it.currentItemIndex_];
} }
Value& ValueInternalArray::dereference(const IteratorState& it) {
Value & JSON_ASSERT_MESSAGE(
ValueInternalArray::dereference( const IteratorState &it ) it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
{ it.currentItemIndex_ <
JSON_ASSERT_MESSAGE( it.array_ && it.array_->size_,
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
< it.array_->size_,
"ValueInternalArray::dereference(): dereferencing invalid iterator"); "ValueInternalArray::dereference(): dereferencing invalid iterator");
return unsafeDereference(it); return unsafeDereference(it);
} }
void void ValueInternalArray::makeBeginIterator(IteratorState& it) const {
ValueInternalArray::makeBeginIterator( IteratorState &it ) const
{
it.array_ = const_cast<ValueInternalArray*>(this); it.array_ = const_cast<ValueInternalArray*>(this);
it.currentItemIndex_ = 0; it.currentItemIndex_ = 0;
it.currentPageIndex_ = pages_; it.currentPageIndex_ = pages_;
} }
void ValueInternalArray::makeIterator(IteratorState& it,
void ArrayIndex index) const {
ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
{
it.array_ = const_cast<ValueInternalArray*>(this); it.array_ = const_cast<ValueInternalArray*>(this);
it.currentItemIndex_ = index % itemsPerPage; it.currentItemIndex_ = index % itemsPerPage;
it.currentPageIndex_ = pages_ + index / itemsPerPage; it.currentPageIndex_ = pages_ + index / itemsPerPage;
} }
void ValueInternalArray::makeEndIterator(IteratorState& it) const {
void
ValueInternalArray::makeEndIterator( IteratorState &it ) const
{
makeIterator(it, size_); makeIterator(it, size_);
} }
ValueInternalArray::ValueInternalArray() : pages_(0), size_(0), pageCount_(0) {}
ValueInternalArray::ValueInternalArray()
: pages_( 0 )
, size_( 0 )
, pageCount_( 0 )
{
}
ValueInternalArray::ValueInternalArray(const ValueInternalArray& other) ValueInternalArray::ValueInternalArray(const ValueInternalArray& other)
: pages_( 0 ) : pages_(0), size_(other.size_), pageCount_(0) {
, pageCount_( 0 )
, size_( other.size_ )
{
PageIndex minNewPages = other.size_ / itemsPerPage; PageIndex minNewPages = other.size_ / itemsPerPage;
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages); arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages, JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
@@ -268,10 +210,8 @@ ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
IteratorState itOther; IteratorState itOther;
other.makeBeginIterator(itOther); other.makeBeginIterator(itOther);
Value* value; Value* value;
for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) for (ArrayIndex index = 0; index < size_; ++index, increment(itOther)) {
{ if (index % itemsPerPage == 0) {
if ( index % itemsPerPage == 0 )
{
PageIndex pageIndex = index / itemsPerPage; PageIndex pageIndex = index / itemsPerPage;
value = arrayAllocator()->allocateArrayPage(); value = arrayAllocator()->allocateArrayPage();
pages_[pageIndex] = value; pages_[pageIndex] = value;
@@ -280,25 +220,18 @@ ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
} }
} }
ValueInternalArray& ValueInternalArray::operator=(ValueInternalArray other) {
ValueInternalArray & swap(other);
ValueInternalArray::operator =( const ValueInternalArray &other )
{
ValueInternalArray temp( other );
swap( temp );
return *this; return *this;
} }
ValueInternalArray::~ValueInternalArray() {
ValueInternalArray::~ValueInternalArray()
{
// destroy all constructed items // destroy all constructed items
IteratorState it; IteratorState it;
IteratorState itEnd; IteratorState itEnd;
makeBeginIterator(it); makeBeginIterator(it);
makeEndIterator(itEnd); makeEndIterator(itEnd);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
Value* value = &dereference(it); Value* value = &dereference(it);
value->~Value(); value->~Value();
} }
@@ -310,10 +243,7 @@ ValueInternalArray::~ValueInternalArray()
arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_); arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_);
} }
void ValueInternalArray::swap(ValueInternalArray& other) {
void
ValueInternalArray::swap( ValueInternalArray &other )
{
Value** tempPages = pages_; Value** tempPages = pages_;
pages_ = other.pages_; pages_ = other.pages_;
other.pages_ = tempPages; other.pages_ = tempPages;
@@ -325,27 +255,20 @@ ValueInternalArray::swap( ValueInternalArray &other )
other.pageCount_ = tempPageCount; other.pageCount_ = tempPageCount;
} }
void void ValueInternalArray::clear() {
ValueInternalArray::clear()
{
ValueInternalArray dummy; ValueInternalArray dummy;
swap(dummy); swap(dummy);
} }
void ValueInternalArray::resize(ArrayIndex newSize) {
void
ValueInternalArray::resize( ArrayIndex newSize )
{
if (newSize == 0) if (newSize == 0)
clear(); clear();
else if ( newSize < size_ ) else if (newSize < size_) {
{
IteratorState it; IteratorState it;
IteratorState itEnd; IteratorState itEnd;
makeIterator(it, newSize); makeIterator(it, newSize);
makeIterator(itEnd, size_); makeIterator(itEnd, size_);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
Value* value = &dereference(it); Value* value = &dereference(it);
value->~Value(); value->~Value();
} }
@@ -354,29 +277,24 @@ ValueInternalArray::resize( ArrayIndex newSize )
for (; pageIndex < lastPageIndex; ++pageIndex) for (; pageIndex < lastPageIndex; ++pageIndex)
arrayAllocator()->releaseArrayPage(pages_[pageIndex]); arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
size_ = newSize; size_ = newSize;
} } else if (newSize > size_)
else if ( newSize > size_ )
resolveReference(newSize); resolveReference(newSize);
} }
void ValueInternalArray::makeIndexValid(ArrayIndex index) {
void
ValueInternalArray::makeIndexValid( ArrayIndex index )
{
// Need to enlarge page index ? // Need to enlarge page index ?
if ( index >= pageCount_ * itemsPerPage ) if (index >= pageCount_ * itemsPerPage) {
{
PageIndex minNewPages = (index + 1) / itemsPerPage; PageIndex minNewPages = (index + 1) / itemsPerPage;
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages); arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
"ValueInternalArray::reserve(): bad reallocation");
} }
// Need to allocate new pages ? // Need to allocate new pages ?
ArrayIndex nextPageIndex = ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0
(size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage ? size_ - (size_ % itemsPerPage) + itemsPerPage
: size_; : size_;
if ( nextPageIndex <= index ) if (nextPageIndex <= index) {
{
PageIndex pageIndex = nextPageIndex / itemsPerPage; PageIndex pageIndex = nextPageIndex / itemsPerPage;
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
for (; pageToAllocate-- > 0; ++pageIndex) for (; pageToAllocate-- > 0; ++pageIndex)
@@ -389,62 +307,48 @@ ValueInternalArray::makeIndexValid( ArrayIndex index )
makeIterator(it, size_); makeIterator(it, size_);
size_ = index + 1; size_ = index + 1;
makeIterator(itEnd, size_); makeIterator(itEnd, size_);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
Value* value = &dereference(it); Value* value = &dereference(it);
new (value) Value(); // Construct a default value using placement new new (value) Value(); // Construct a default value using placement new
} }
} }
Value & Value& ValueInternalArray::resolveReference(ArrayIndex index) {
ValueInternalArray::resolveReference( ArrayIndex index )
{
if (index >= size_) if (index >= size_)
makeIndexValid(index); makeIndexValid(index);
return pages_[index / itemsPerPage][index % itemsPerPage]; return pages_[index / itemsPerPage][index % itemsPerPage];
} }
Value * Value* ValueInternalArray::find(ArrayIndex index) const {
ValueInternalArray::find( ArrayIndex index ) const
{
if (index >= size_) if (index >= size_)
return 0; return 0;
return &(pages_[index / itemsPerPage][index % itemsPerPage]); return &(pages_[index / itemsPerPage][index % itemsPerPage]);
} }
ValueInternalArray::ArrayIndex ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
ValueInternalArray::size() const
{
return size_; return size_;
} }
int int ValueInternalArray::distance(const IteratorState& x,
ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) const IteratorState& y) {
{
return indexOf(y) - indexOf(x); return indexOf(y) - indexOf(x);
} }
ValueInternalArray::ArrayIndex ValueInternalArray::ArrayIndex
ValueInternalArray::indexOf( const IteratorState &iterator ) ValueInternalArray::indexOf(const IteratorState& iterator) {
{
if (!iterator.array_) if (!iterator.array_)
return ArrayIndex(-1); return ArrayIndex(-1);
return ArrayIndex( return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
(iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage itemsPerPage +
+ iterator.currentItemIndex_ ); iterator.currentItemIndex_);
} }
int ValueInternalArray::compare(const ValueInternalArray& other) const {
int
ValueInternalArray::compare( const ValueInternalArray &other ) const
{
int sizeDiff(size_ - other.size_); int sizeDiff(size_ - other.size_);
if (sizeDiff != 0) if (sizeDiff != 0)
return sizeDiff; return sizeDiff;
for ( ArrayIndex index =0; index < size_; ++index ) for (ArrayIndex index = 0; index < size_; ++index) {
{
int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare( int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare(
other.pages_[index / itemsPerPage][index % itemsPerPage]); other.pages_[index / itemsPerPage][index % itemsPerPage]);
if (diff != 0) if (diff != 0)

View File

@@ -15,146 +15,106 @@ namespace Json {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); /** \internal MUST be safely initialized using memset( this, 0,
* sizeof(ValueInternalLink) );
* This optimization is used by the fast allocator. * This optimization is used by the fast allocator.
*/ */
ValueInternalLink::ValueInternalLink() ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {}
: previous_( 0 )
, next_( 0 )
{
}
ValueInternalLink::~ValueInternalLink() ValueInternalLink::~ValueInternalLink() {
{ for (int index = 0; index < itemPerLink; ++index) {
for ( int index =0; index < itemPerLink; ++index ) if (!items_[index].isItemAvailable()) {
{
if ( !items_[index].isItemAvailable() )
{
if (!items_[index].isMemberNameStatic()) if (!items_[index].isMemberNameStatic())
free(keys_[index]); free(keys_[index]);
} } else
else
break; break;
} }
} }
ValueMapAllocator::~ValueMapAllocator() {}
ValueMapAllocator::~ValueMapAllocator()
{
}
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
class DefaultValueMapAllocator : public ValueMapAllocator class DefaultValueMapAllocator : public ValueMapAllocator {
{
public: // overridden from ValueMapAllocator public: // overridden from ValueMapAllocator
virtual ValueInternalMap *newMap() virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
{
return new ValueInternalMap();
}
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
{
return new ValueInternalMap(other); return new ValueInternalMap(other);
} }
virtual void destructMap( ValueInternalMap *map ) virtual void destructMap(ValueInternalMap* map) { delete map; }
{
delete map;
}
virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
{
return new ValueInternalLink[size]; return new ValueInternalLink[size];
} }
virtual void releaseMapBuckets( ValueInternalLink *links ) virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
{
delete [] links;
}
virtual ValueInternalLink *allocateMapLink() virtual ValueInternalLink* allocateMapLink() {
{
return new ValueInternalLink(); return new ValueInternalLink();
} }
virtual void releaseMapLink( ValueInternalLink *link ) virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
{
delete link;
}
}; };
#else #else
/// @todo make this thread-safe (lock when accessign batch allocator) /// @todo make this thread-safe (lock when accessign batch allocator)
class DefaultValueMapAllocator : public ValueMapAllocator class DefaultValueMapAllocator : public ValueMapAllocator {
{
public: // overridden from ValueMapAllocator public: // overridden from ValueMapAllocator
virtual ValueInternalMap *newMap() virtual ValueInternalMap* newMap() {
{
ValueInternalMap* map = mapsAllocator_.allocate(); ValueInternalMap* map = mapsAllocator_.allocate();
new (map) ValueInternalMap(); // placement new new (map) ValueInternalMap(); // placement new
return map; return map;
} }
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
{
ValueInternalMap* map = mapsAllocator_.allocate(); ValueInternalMap* map = mapsAllocator_.allocate();
new (map) ValueInternalMap(other); // placement new new (map) ValueInternalMap(other); // placement new
return map; return map;
} }
virtual void destructMap( ValueInternalMap *map ) virtual void destructMap(ValueInternalMap* map) {
{ if (map) {
if ( map )
{
map->~ValueInternalMap(); map->~ValueInternalMap();
mapsAllocator_.release(map); mapsAllocator_.release(map);
} }
} }
virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
{
return new ValueInternalLink[size]; return new ValueInternalLink[size];
} }
virtual void releaseMapBuckets( ValueInternalLink *links ) virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
{
delete [] links;
}
virtual ValueInternalLink *allocateMapLink() virtual ValueInternalLink* allocateMapLink() {
{
ValueInternalLink* link = linksAllocator_.allocate(); ValueInternalLink* link = linksAllocator_.allocate();
memset(link, 0, sizeof(ValueInternalLink)); memset(link, 0, sizeof(ValueInternalLink));
return link; return link;
} }
virtual void releaseMapLink( ValueInternalLink *link ) virtual void releaseMapLink(ValueInternalLink* link) {
{
link->~ValueInternalLink(); link->~ValueInternalLink();
linksAllocator_.release(link); linksAllocator_.release(link);
} }
private: private:
BatchAllocator<ValueInternalMap, 1> mapsAllocator_; BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
BatchAllocator<ValueInternalLink, 1> linksAllocator_; BatchAllocator<ValueInternalLink, 1> linksAllocator_;
}; };
#endif #endif
static ValueMapAllocator *&mapAllocator() static ValueMapAllocator*& mapAllocator() {
{
static DefaultValueMapAllocator defaultAllocator; static DefaultValueMapAllocator defaultAllocator;
static ValueMapAllocator* mapAllocator = &defaultAllocator; static ValueMapAllocator* mapAllocator = &defaultAllocator;
return mapAllocator; return mapAllocator;
} }
static struct DummyMapAllocatorInitializer { static struct DummyMapAllocatorInitializer {
DummyMapAllocatorInitializer() DummyMapAllocatorInitializer() {
{ mapAllocator(); // ensure mapAllocator() statics are initialized before
mapAllocator(); // ensure mapAllocator() statics are initialized before main(). // main().
} }
} dummyMapAllocatorInitializer; } dummyMapAllocatorInitializer;
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
/* /*
@@ -164,29 +124,17 @@ linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
value have extra state: valid, available, deleted value have extra state: valid, available, deleted
*/ */
ValueInternalMap::ValueInternalMap() ValueInternalMap::ValueInternalMap()
: buckets_( 0 ) : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {}
, tailLink_( 0 )
, bucketsSize_( 0 )
, itemCount_( 0 )
{
}
ValueInternalMap::ValueInternalMap(const ValueInternalMap& other) ValueInternalMap::ValueInternalMap(const ValueInternalMap& other)
: buckets_( 0 ) : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {
, tailLink_( 0 )
, bucketsSize_( 0 )
, itemCount_( 0 )
{
reserve(other.itemCount_); reserve(other.itemCount_);
IteratorState it; IteratorState it;
IteratorState itEnd; IteratorState itEnd;
other.makeBeginIterator(it); other.makeBeginIterator(it);
other.makeEndIterator(itEnd); other.makeEndIterator(itEnd);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
bool isStatic; bool isStatic;
const char* memberName = key(it, isStatic); const char* memberName = key(it, isStatic);
const Value& aValue = value(it); const Value& aValue = value(it);
@@ -194,25 +142,17 @@ ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
} }
} }
ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) {
ValueInternalMap & swap(other);
ValueInternalMap::operator =( const ValueInternalMap &other )
{
ValueInternalMap dummy( other );
swap( dummy );
return *this; return *this;
} }
ValueInternalMap::~ValueInternalMap() {
ValueInternalMap::~ValueInternalMap() if (buckets_) {
{ for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
if ( buckets_ ) ++bucketIndex) {
{
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
{
ValueInternalLink* link = buckets_[bucketIndex].next_; ValueInternalLink* link = buckets_[bucketIndex].next_;
while ( link ) while (link) {
{
ValueInternalLink* linkToRelease = link; ValueInternalLink* linkToRelease = link;
link = link->next_; link = link->next_;
mapAllocator()->releaseMapLink(linkToRelease); mapAllocator()->releaseMapLink(linkToRelease);
@@ -222,10 +162,7 @@ ValueInternalMap::~ValueInternalMap()
} }
} }
void ValueInternalMap::swap(ValueInternalMap& other) {
void
ValueInternalMap::swap( ValueInternalMap &other )
{
ValueInternalLink* tempBuckets = buckets_; ValueInternalLink* tempBuckets = buckets_;
buckets_ = other.buckets_; buckets_ = other.buckets_;
other.buckets_ = tempBuckets; other.buckets_ = tempBuckets;
@@ -240,54 +177,39 @@ ValueInternalMap::swap( ValueInternalMap &other )
other.itemCount_ = tempItemCount; other.itemCount_ = tempItemCount;
} }
void ValueInternalMap::clear() {
void
ValueInternalMap::clear()
{
ValueInternalMap dummy; ValueInternalMap dummy;
swap(dummy); swap(dummy);
} }
ValueInternalMap::BucketIndex ValueInternalMap::size() const {
ValueInternalMap::BucketIndex
ValueInternalMap::size() const
{
return itemCount_; return itemCount_;
} }
bool bool ValueInternalMap::reserveDelta(BucketIndex growth) {
ValueInternalMap::reserveDelta( BucketIndex growth )
{
return reserve(itemCount_ + growth); return reserve(itemCount_ + growth);
} }
bool bool ValueInternalMap::reserve(BucketIndex newItemCount) {
ValueInternalMap::reserve( BucketIndex newItemCount ) if (!buckets_ && newItemCount > 0) {
{
if ( !buckets_ && newItemCount > 0 )
{
buckets_ = mapAllocator()->allocateMapBuckets(1); buckets_ = mapAllocator()->allocateMapBuckets(1);
bucketsSize_ = 1; bucketsSize_ = 1;
tailLink_ = &buckets_[0]; tailLink_ = &buckets_[0];
} }
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; // BucketIndex idealBucketCount = (newItemCount +
// ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
return true; return true;
} }
const Value* ValueInternalMap::find(const char* key) const {
const Value *
ValueInternalMap::find( const char *key ) const
{
if (!bucketsSize_) if (!bucketsSize_)
return 0; return 0;
HashKey hashedKey = hash(key); HashKey hashedKey = hash(key);
BucketIndex bucketIndex = hashedKey % bucketsSize_; BucketIndex bucketIndex = hashedKey % bucketsSize_;
for ( const ValueInternalLink *current = &buckets_[bucketIndex]; for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
current != 0; current = current->next_) {
current = current->next_ ) for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
{ ++index) {
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
{
if (current->items_[index].isItemAvailable()) if (current->items_[index].isItemAvailable())
return 0; return 0;
if (strcmp(key, current->keys_[index]) == 0) if (strcmp(key, current->keys_[index]) == 0)
@@ -297,31 +219,20 @@ ValueInternalMap::find( const char *key ) const
return 0; return 0;
} }
Value* ValueInternalMap::find(const char* key) {
Value *
ValueInternalMap::find( const char *key )
{
const ValueInternalMap* constThis = this; const ValueInternalMap* constThis = this;
return const_cast<Value*>(constThis->find(key)); return const_cast<Value*>(constThis->find(key));
} }
Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) {
Value &
ValueInternalMap::resolveReference( const char *key,
bool isStatic )
{
HashKey hashedKey = hash(key); HashKey hashedKey = hash(key);
if ( bucketsSize_ ) if (bucketsSize_) {
{
BucketIndex bucketIndex = hashedKey % bucketsSize_; BucketIndex bucketIndex = hashedKey % bucketsSize_;
ValueInternalLink** previous = 0; ValueInternalLink** previous = 0;
BucketIndex index; BucketIndex index;
for ( ValueInternalLink *current = &buckets_[bucketIndex]; for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
current != 0; previous = &current->next_, current = current->next_) {
previous = &current->next_, current = current->next_ ) for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
{
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
{
if (current->items_[index].isItemAvailable()) if (current->items_[index].isItemAvailable())
return setNewItem(key, isStatic, current, index); return setNewItem(key, isStatic, current, index);
if (strcmp(key, current->keys_[index]) == 0) if (strcmp(key, current->keys_[index]) == 0)
@@ -334,25 +245,18 @@ ValueInternalMap::resolveReference( const char *key,
return unsafeAdd(key, isStatic, hashedKey); return unsafeAdd(key, isStatic, hashedKey);
} }
void ValueInternalMap::remove(const char* key) {
void
ValueInternalMap::remove( const char *key )
{
HashKey hashedKey = hash(key); HashKey hashedKey = hash(key);
if (!bucketsSize_) if (!bucketsSize_)
return; return;
BucketIndex bucketIndex = hashedKey % bucketsSize_; BucketIndex bucketIndex = hashedKey % bucketsSize_;
for ( ValueInternalLink *link = &buckets_[bucketIndex]; for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
link != 0; link = link->next_) {
link = link->next_ )
{
BucketIndex index; BucketIndex index;
for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
{
if (link->items_[index].isItemAvailable()) if (link->items_[index].isItemAvailable())
return; return;
if ( strcmp( key, link->keys_[index] ) == 0 ) if (strcmp(key, link->keys_[index]) == 0) {
{
doActualRemove(link, index, bucketIndex); doActualRemove(link, index, bucketIndex);
return; return;
} }
@@ -360,18 +264,16 @@ ValueInternalMap::remove( const char *key )
} }
} }
void void ValueInternalMap::doActualRemove(ValueInternalLink* link,
ValueInternalMap::doActualRemove( ValueInternalLink *link,
BucketIndex index, BucketIndex index,
BucketIndex bucketIndex ) BucketIndex bucketIndex) {
{
// find last item of the bucket and swap it with the 'removed' one. // find last item of the bucket and swap it with the 'removed' one.
// set removed items flags to 'available'. // set removed items flags to 'available'.
// if last page only contains 'available' items, then desallocate it (it's empty) // if last page only contains 'available' items, then desallocate it (it's
// empty)
ValueInternalLink*& lastLink = getLastLinkInBucket(index); ValueInternalLink*& lastLink = getLastLinkInBucket(index);
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
for ( ; for (; lastItemIndex < ValueInternalLink::itemPerLink;
lastItemIndex < ValueInternalLink::itemPerLink;
++lastItemIndex) // may be optimized with dicotomic search ++lastItemIndex) // may be optimized with dicotomic search
{ {
if (lastLink->items_[lastItemIndex].isItemAvailable()) if (lastLink->items_[lastItemIndex].isItemAvailable())
@@ -392,9 +294,7 @@ ValueInternalMap::doActualRemove( ValueInternalLink *link,
linkPreviousToLast->next_ = 0; linkPreviousToLast->next_ = 0;
lastLink = linkPreviousToLast; lastLink = linkPreviousToLast;
} }
} } else {
else
{
Value dummy; Value dummy;
valueToPreserve->swap(dummy); // restore deleted to default Value. valueToPreserve->swap(dummy); // restore deleted to default Value.
valueToPreserve->setItemUsed(false); valueToPreserve->setItemUsed(false);
@@ -402,10 +302,8 @@ ValueInternalMap::doActualRemove( ValueInternalLink *link,
--itemCount_; --itemCount_;
} }
ValueInternalLink*& ValueInternalLink*&
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
{
if (bucketIndex == bucketsSize_ - 1) if (bucketIndex == bucketsSize_ - 1)
return tailLink_; return tailLink_;
ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_; ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
@@ -414,13 +312,10 @@ ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
return previous; return previous;
} }
Value& ValueInternalMap::setNewItem(const char* key,
Value &
ValueInternalMap::setNewItem( const char *key,
bool isStatic, bool isStatic,
ValueInternalLink* link, ValueInternalLink* link,
BucketIndex index ) BucketIndex index) {
{
char* duplicatedKey = makeMemberName(key); char* duplicatedKey = makeMemberName(key);
++itemCount_; ++itemCount_;
link->keys_[index] = duplicatedKey; link->keys_[index] = duplicatedKey;
@@ -429,19 +324,15 @@ ValueInternalMap::setNewItem( const char *key,
return link->items_[index]; // items already default constructed. return link->items_[index]; // items already default constructed.
} }
Value& Value&
ValueInternalMap::unsafeAdd( const char *key, ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) {
bool isStatic, JSON_ASSERT_MESSAGE(bucketsSize_ > 0,
HashKey hashedKey ) "ValueInternalMap::unsafeAdd(): internal logic error.");
{
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
BucketIndex bucketIndex = hashedKey % bucketsSize_; BucketIndex bucketIndex = hashedKey % bucketsSize_;
ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex); ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex);
ValueInternalLink* link = previousLink; ValueInternalLink* link = previousLink;
BucketIndex index; BucketIndex index;
for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
{
if (link->items_[index].isItemAvailable()) if (link->items_[index].isItemAvailable())
break; break;
} }
@@ -456,38 +347,31 @@ ValueInternalMap::unsafeAdd( const char *key,
return setNewItem(key, isStatic, link, index); return setNewItem(key, isStatic, link, index);
} }
ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const {
ValueInternalMap::HashKey
ValueInternalMap::hash( const char *key ) const
{
HashKey hash = 0; HashKey hash = 0;
while (*key) while (*key)
hash += *key++ * 37; hash += *key++ * 37;
return hash; return hash;
} }
int ValueInternalMap::compare(const ValueInternalMap& other) const {
int
ValueInternalMap::compare( const ValueInternalMap &other ) const
{
int sizeDiff(itemCount_ - other.itemCount_); int sizeDiff(itemCount_ - other.itemCount_);
if (sizeDiff != 0) if (sizeDiff != 0)
return sizeDiff; return sizeDiff;
// Strict order guaranty is required. Compare all keys FIRST, then compare values. // Strict order guaranty is required. Compare all keys FIRST, then compare
// values.
IteratorState it; IteratorState it;
IteratorState itEnd; IteratorState itEnd;
makeBeginIterator(it); makeBeginIterator(it);
makeEndIterator(itEnd); makeEndIterator(itEnd);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
if (!other.find(key(it))) if (!other.find(key(it)))
return 1; return 1;
} }
// All keys are equals, let's compare values // All keys are equals, let's compare values
makeBeginIterator(it); makeBeginIterator(it);
for ( ; !equals(it,itEnd); increment(it) ) for (; !equals(it, itEnd); increment(it)) {
{
const Value* otherValue = other.find(key(it)); const Value* otherValue = other.find(key(it));
int valueDiff = value(it).compare(*otherValue); int valueDiff = value(it).compare(*otherValue);
if (valueDiff != 0) if (valueDiff != 0)
@@ -496,42 +380,30 @@ ValueInternalMap::compare( const ValueInternalMap &other ) const
return 0; return 0;
} }
void ValueInternalMap::makeBeginIterator(IteratorState& it) const {
void
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
{
it.map_ = const_cast<ValueInternalMap*>(this); it.map_ = const_cast<ValueInternalMap*>(this);
it.bucketIndex_ = 0; it.bucketIndex_ = 0;
it.itemIndex_ = 0; it.itemIndex_ = 0;
it.link_ = buckets_; it.link_ = buckets_;
} }
void ValueInternalMap::makeEndIterator(IteratorState& it) const {
void
ValueInternalMap::makeEndIterator( IteratorState &it ) const
{
it.map_ = const_cast<ValueInternalMap*>(this); it.map_ = const_cast<ValueInternalMap*>(this);
it.bucketIndex_ = bucketsSize_; it.bucketIndex_ = bucketsSize_;
it.itemIndex_ = 0; it.itemIndex_ = 0;
it.link_ = 0; it.link_ = 0;
} }
bool ValueInternalMap::equals(const IteratorState& x,
bool const IteratorState& other) {
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ &&
{ x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_;
return x.map_ == other.map_
&& x.bucketIndex_ == other.bucketIndex_
&& x.link_ == other.link_
&& x.itemIndex_ == other.itemIndex_;
} }
void ValueInternalMap::incrementBucket(IteratorState& iterator) {
void
ValueInternalMap::incrementBucket( IteratorState &iterator )
{
++iterator.bucketIndex_; ++iterator.bucketIndex_;
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, JSON_ASSERT_MESSAGE(
iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
"ValueInternalMap::increment(): attempting to iterate beyond end."); "ValueInternalMap::increment(): attempting to iterate beyond end.");
if (iterator.bucketIndex_ == iterator.map_->bucketsSize_) if (iterator.bucketIndex_ == iterator.map_->bucketsSize_)
iterator.link_ = 0; iterator.link_ = 0;
@@ -540,36 +412,29 @@ ValueInternalMap::incrementBucket( IteratorState &iterator )
iterator.itemIndex_ = 0; iterator.itemIndex_ = 0;
} }
void ValueInternalMap::increment(IteratorState& iterator) {
void JSON_ASSERT_MESSAGE(iterator.map_,
ValueInternalMap::increment( IteratorState &iterator ) "Attempting to iterator using invalid iterator.");
{
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
++iterator.itemIndex_; ++iterator.itemIndex_;
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) {
{ JSON_ASSERT_MESSAGE(
JSON_ASSERT_MESSAGE( iterator.link_ != 0, iterator.link_ != 0,
"ValueInternalMap::increment(): attempting to iterate beyond end."); "ValueInternalMap::increment(): attempting to iterate beyond end.");
iterator.link_ = iterator.link_->next_; iterator.link_ = iterator.link_->next_;
if (iterator.link_ == 0) if (iterator.link_ == 0)
incrementBucket(iterator); incrementBucket(iterator);
} } else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) {
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
{
incrementBucket(iterator); incrementBucket(iterator);
} }
} }
void ValueInternalMap::decrement(IteratorState& iterator) {
void if (iterator.itemIndex_ == 0) {
ValueInternalMap::decrement( IteratorState &iterator ) JSON_ASSERT_MESSAGE(iterator.map_,
{ "Attempting to iterate using invalid iterator.");
if ( iterator.itemIndex_ == 0 ) if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) {
{ JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0,
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); "Attempting to iterate beyond beginning.");
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
{
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
--(iterator.bucketIndex_); --(iterator.bucketIndex_);
} }
iterator.link_ = iterator.link_->previous_; iterator.link_ = iterator.link_->previous_;
@@ -577,34 +442,27 @@ ValueInternalMap::decrement( IteratorState &iterator )
} }
} }
const char* ValueInternalMap::key(const IteratorState& iterator) {
const char * JSON_ASSERT_MESSAGE(iterator.link_,
ValueInternalMap::key( const IteratorState &iterator ) "Attempting to iterate using invalid iterator.");
{
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
return iterator.link_->keys_[iterator.itemIndex_]; return iterator.link_->keys_[iterator.itemIndex_];
} }
const char * const char* ValueInternalMap::key(const IteratorState& iterator,
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) bool& isStatic) {
{ JSON_ASSERT_MESSAGE(iterator.link_,
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); "Attempting to iterate using invalid iterator.");
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
return iterator.link_->keys_[iterator.itemIndex_]; return iterator.link_->keys_[iterator.itemIndex_];
} }
Value& ValueInternalMap::value(const IteratorState& iterator) {
Value & JSON_ASSERT_MESSAGE(iterator.link_,
ValueInternalMap::value( const IteratorState &iterator ) "Attempting to iterate using invalid iterator.");
{
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
return iterator.link_->items_[iterator.itemIndex_]; return iterator.link_->items_[iterator.itemIndex_];
} }
int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) {
int
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
{
int offset = 0; int offset = 0;
IteratorState it = x; IteratorState it = x;
while (!equals(it, y)) while (!equals(it, y))

File diff suppressed because it is too large Load Diff

View File

@@ -15,33 +15,24 @@
namespace Json { namespace Json {
/// Converts a unicode code-point to UTF-8. /// Converts a unicode code-point to UTF-8.
static inline std::string static inline std::string codePointToUTF8(unsigned int cp) {
codePointToUTF8(unsigned int cp)
{
std::string result; std::string result;
// based on description from http://en.wikipedia.org/wiki/UTF-8 // based on description from http://en.wikipedia.org/wiki/UTF-8
if (cp <= 0x7f) if (cp <= 0x7f) {
{
result.resize(1); result.resize(1);
result[0] = static_cast<char>(cp); result[0] = static_cast<char>(cp);
} } else if (cp <= 0x7FF) {
else if (cp <= 0x7FF)
{
result.resize(2); result.resize(2);
result[1] = static_cast<char>(0x80 | (0x3f & cp)); result[1] = static_cast<char>(0x80 | (0x3f & cp));
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
} } else if (cp <= 0xFFFF) {
else if (cp <= 0xFFFF)
{
result.resize(3); result.resize(3);
result[2] = static_cast<char>(0x80 | (0x3f & cp)); result[2] = static_cast<char>(0x80 | (0x3f & cp));
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
} } else if (cp <= 0x10FFFF) {
else if (cp <= 0x10FFFF)
{
result.resize(4); result.resize(4);
result[3] = static_cast<char>(0x80 | (0x3f & cp)); result[3] = static_cast<char>(0x80 | (0x3f & cp));
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
@@ -52,40 +43,43 @@ codePointToUTF8(unsigned int cp)
return result; return result;
} }
/// Returns true if ch is a control character (in range [0,32[). /// Returns true if ch is a control character (in range [0,32[).
static inline bool static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
isControlCharacter(char ch)
{
return ch > 0 && ch <= 0x1F;
}
enum { enum {
/// Constant that specify the size of the buffer that must be passed to uintToString. /// Constant that specify the size of the buffer that must be passed to
/// uintToString.
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
}; };
// Defines a char buffer for use with uintToString(). // Defines a char buffer for use with uintToString().
typedef char UIntToStringBuffer[uintToStringBufferSize]; typedef char UIntToStringBuffer[uintToStringBufferSize];
/** Converts an unsigned integer to string. /** Converts an unsigned integer to string.
* @param value Unsigned interger to convert to string * @param value Unsigned interger to convert to string
* @param current Input/Output string buffer. * @param current Input/Output string buffer.
* Must have at least uintToStringBufferSize chars free. * Must have at least uintToStringBufferSize chars free.
*/ */
static inline void static inline void uintToString(LargestUInt value, char*& current) {
uintToString( LargestUInt value,
char *&current )
{
*--current = 0; *--current = 0;
do do {
{
*--current = char(value % 10) + '0'; *--current = char(value % 10) + '0';
value /= 10; value /= 10;
} while (value != 0);
}
/** Change ',' to '.' everywhere in buffer.
*
* We had a sophisticated way, but it did not work in WinCE.
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
*/
static inline void fixNumericLocale(char* begin, char* end) {
while (begin < end) {
if (*begin == ',') {
*begin = '.';
}
++begin;
} }
while ( value != 0 );
} }
} // namespace Json { } // namespace Json {

File diff suppressed because it is too large Load Diff

View File

@@ -17,43 +17,33 @@ namespace Json {
ValueIteratorBase::ValueIteratorBase() ValueIteratorBase::ValueIteratorBase()
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
: current_() : current_(), isNull_(true) {
, isNull_( true )
{
} }
#else #else
: isArray_( true ) : isArray_(true), isNull_(true) {
, isNull_( true )
{
iterator_.array_ = ValueInternalArray::IteratorState(); iterator_.array_ = ValueInternalArray::IteratorState();
} }
#endif #endif
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current ) ValueIteratorBase::ValueIteratorBase(
: current_( current ) const Value::ObjectValues::iterator& current)
, isNull_( false ) : current_(current), isNull_(false) {}
{
}
#else #else
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) ValueIteratorBase::ValueIteratorBase(
: isArray_( true ) const ValueInternalArray::IteratorState& state)
{ : isArray_(true) {
iterator_.array_ = state; iterator_.array_ = state;
} }
ValueIteratorBase::ValueIteratorBase(
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) const ValueInternalMap::IteratorState& state)
: isArray_( false ) : isArray_(false) {
{
iterator_.map_ = state; iterator_.map_ = state;
} }
#endif #endif
Value & Value& ValueIteratorBase::deref() const {
ValueIteratorBase::deref() const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
return current_->second; return current_->second;
#else #else
@@ -63,10 +53,7 @@ ValueIteratorBase::deref() const
#endif #endif
} }
void ValueIteratorBase::increment() {
void
ValueIteratorBase::increment()
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
++current_; ++current_;
#else #else
@@ -76,10 +63,7 @@ ValueIteratorBase::increment()
#endif #endif
} }
void ValueIteratorBase::decrement() {
void
ValueIteratorBase::decrement()
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
--current_; --current_;
#else #else
@@ -89,10 +73,8 @@ ValueIteratorBase::decrement()
#endif #endif
} }
ValueIteratorBase::difference_type ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance( const SelfType &other ) const ValueIteratorBase::computeDistance(const SelfType& other) const {
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
#ifdef JSON_USE_CPPTL_SMALLMAP #ifdef JSON_USE_CPPTL_SMALLMAP
return current_ - other.current_; return current_ - other.current_;
@@ -102,37 +84,33 @@ ValueIteratorBase::computeDistance( const SelfType &other ) const
// std::map::iterator. As begin() and end() are two instance // std::map::iterator. As begin() and end() are two instance
// of the default std::map::iterator, they can not be compared. // of the default std::map::iterator, they can not be compared.
// To allow this, we handle this comparison specifically. // To allow this, we handle this comparison specifically.
if ( isNull_ && other.isNull_ ) if (isNull_ && other.isNull_) {
{
return 0; return 0;
} }
// Usage of std::distance is not portable (does not compile with Sun Studio 12
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, // RogueWave STL,
// which is the one used by default). // which is the one used by default).
// Using a portable hand-made version for non random iterator instead: // Using a portable hand-made version for non random iterator instead:
// return difference_type( std::distance( current_, other.current_ ) ); // return difference_type( std::distance( current_, other.current_ ) );
difference_type myDistance = 0; difference_type myDistance = 0;
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) for (Value::ObjectValues::iterator it = current_; it != other.current_;
{ ++it) {
++myDistance; ++myDistance;
} }
return myDistance; return myDistance;
#endif #endif
#else #else
if (isArray_) if (isArray_)
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); return ValueInternalArray::distance(iterator_.array_,
other.iterator_.array_);
return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_); return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
#endif #endif
} }
bool ValueIteratorBase::isEqual(const SelfType& other) const {
bool
ValueIteratorBase::isEqual( const SelfType &other ) const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
if ( isNull_ ) if (isNull_) {
{
return other.isNull_; return other.isNull_;
} }
return current_ == other.current_; return current_ == other.current_;
@@ -143,12 +121,10 @@ ValueIteratorBase::isEqual( const SelfType &other ) const
#endif #endif
} }
void ValueIteratorBase::copy(const SelfType& other) {
void
ValueIteratorBase::copy( const SelfType &other )
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
current_ = other.current_; current_ = other.current_;
isNull_ = other.isNull_;
#else #else
if (isArray_) if (isArray_)
iterator_.array_ = other.iterator_.array_; iterator_.array_ = other.iterator_.array_;
@@ -156,14 +132,10 @@ ValueIteratorBase::copy( const SelfType &other )
#endif #endif
} }
Value ValueIteratorBase::key() const {
Value
ValueIteratorBase::key() const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
const Value::CZString czstring = (*current_).first; const Value::CZString czstring = (*current_).first;
if ( czstring.c_str() ) if (czstring.c_str()) {
{
if (czstring.isStaticString()) if (czstring.isStaticString())
return Value(StaticString(czstring.c_str())); return Value(StaticString(czstring.c_str()));
return Value(czstring.c_str()); return Value(czstring.c_str());
@@ -180,10 +152,7 @@ ValueIteratorBase::key() const
#endif #endif
} }
UInt ValueIteratorBase::index() const {
UInt
ValueIteratorBase::index() const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
const Value::CZString czstring = (*current_).first; const Value::CZString czstring = (*current_).first;
if (!czstring.c_str()) if (!czstring.c_str())
@@ -196,10 +165,7 @@ ValueIteratorBase::index() const
#endif #endif
} }
const char* ValueIteratorBase::memberName() const {
const char *
ValueIteratorBase::memberName() const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
const char* name = (*current_).first.c_str(); const char* name = (*current_).first.c_str();
return name ? name : ""; return name ? name : "";
@@ -210,7 +176,6 @@ ValueIteratorBase::memberName() const
#endif #endif
} }
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
@@ -219,36 +184,28 @@ ValueIteratorBase::memberName() const
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator() ValueConstIterator::ValueConstIterator() {}
{
}
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current ) ValueConstIterator::ValueConstIterator(
: ValueIteratorBase( current ) const Value::ObjectValues::iterator& current)
{ : ValueIteratorBase(current) {}
}
#else #else
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) ValueConstIterator::ValueConstIterator(
: ValueIteratorBase( state ) const ValueInternalArray::IteratorState& state)
{ : ValueIteratorBase(state) {}
}
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) ValueConstIterator::ValueConstIterator(
: ValueIteratorBase( state ) const ValueInternalMap::IteratorState& state)
{ : ValueIteratorBase(state) {}
}
#endif #endif
ValueConstIterator & ValueConstIterator& ValueConstIterator::
ValueConstIterator::operator =( const ValueIteratorBase &other ) operator=(const ValueIteratorBase& other) {
{
copy(other); copy(other);
return *this; return *this;
} }
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
@@ -257,41 +214,26 @@ ValueConstIterator::operator =( const ValueIteratorBase &other )
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator() ValueIterator::ValueIterator() {}
{
}
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
: ValueIteratorBase( current ) : ValueIteratorBase(current) {}
{
}
#else #else
ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state) ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
: ValueIteratorBase( state ) : ValueIteratorBase(state) {}
{
}
ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state) ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
: ValueIteratorBase( state ) : ValueIteratorBase(state) {}
{
}
#endif #endif
ValueIterator::ValueIterator(const ValueConstIterator& other) ValueIterator::ValueIterator(const ValueConstIterator& other)
: ValueIteratorBase( other ) : ValueIteratorBase(other) {}
{
}
ValueIterator::ValueIterator(const ValueIterator& other) ValueIterator::ValueIterator(const ValueIterator& other)
: ValueIteratorBase( other ) : ValueIteratorBase(other) {}
{
}
ValueIterator & ValueIterator& ValueIterator::operator=(const SelfType& other) {
ValueIterator::operator =( const SelfType &other )
{
copy(other); copy(other);
return *this; return *this;
} }

View File

@@ -1,4 +1,4 @@
// Copyright 2007-2010 Baptiste Lepilleur // Copyright 2011 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and // Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction. // recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
@@ -11,29 +11,32 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <iostream>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <math.h>
#if _MSC_VER >= 1400 // VC++ 8.0 #if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. #include <float.h>
#define isfinite _finite
#define snprintf _snprintf
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
// Disable warning about strdup being deprecated.
#pragma warning(disable : 4996)
#endif #endif
namespace Json { namespace Json {
static bool containsControlCharacter( const char* str ) static bool containsControlCharacter(const char* str) {
{ while (*str) {
while ( *str )
{
if (isControlCharacter(*(str++))) if (isControlCharacter(*(str++)))
return true; return true;
} }
return false; return false;
} }
std::string valueToString(LargestInt value) {
std::string valueToString( LargestInt value )
{
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
char* current = buffer + sizeof(buffer); char* current = buffer + sizeof(buffer);
bool isNegative = value < 0; bool isNegative = value < 0;
@@ -46,9 +49,7 @@ std::string valueToString( LargestInt value )
return current; return current;
} }
std::string valueToString(LargestUInt value) {
std::string valueToString( LargestUInt value )
{
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
char* current = buffer + sizeof(buffer); char* current = buffer + sizeof(buffer);
uintToString(value, current); uintToString(value, current);
@@ -58,81 +59,72 @@ std::string valueToString( LargestUInt value )
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
std::string valueToString( Int value ) std::string valueToString(Int value) {
{
return valueToString(LargestInt(value)); return valueToString(LargestInt(value));
} }
std::string valueToString(UInt value) {
std::string valueToString( UInt value )
{
return valueToString(LargestUInt(value)); return valueToString(LargestUInt(value));
} }
#endif // # if defined(JSON_HAS_INT64) #endif // # if defined(JSON_HAS_INT64)
std::string valueToString(double value) {
std::string valueToString( double value ) // Allocate a buffer that is more than large enough to store the 16 digits of
{ // precision requested below.
char buffer[32]; char buffer[32];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. int len = -1;
sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
// Print into the buffer. We need not request the alternative representation
// that always has a decimal point because JSON doesn't distingish the
// concepts of reals and integers.
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with
// visual studio 2005 to
// avoid warning.
#if defined(WINCE)
len = _snprintf(buffer, sizeof(buffer), "%.16g", value);
#else #else
sprintf(buffer, "%#.16g", value); len = sprintf_s(buffer, sizeof(buffer), "%.16g", value);
#endif #endif
char* ch = buffer + strlen(buffer) - 1; #else
if (*ch != '0') return buffer; // nothing to truncate, so save time if (isfinite(value)) {
while(ch > buffer && *ch == '0'){ len = snprintf(buffer, sizeof(buffer), "%.16g", value);
--ch; } else {
} // IEEE standard states that NaN values will not compare to themselves
char* last_nonzero = ch; if (value != value) {
while(ch >= buffer){ len = snprintf(buffer, sizeof(buffer), "null");
switch(*ch){ } else if (value < 0) {
case '0': len = snprintf(buffer, sizeof(buffer), "-1e+9999");
case '1': } else {
case '2': len = snprintf(buffer, sizeof(buffer), "1e+9999");
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
--ch;
continue;
case '.':
// Truncate zeroes to save bytes in output, but keep one.
*(last_nonzero+2) = '\0';
return buffer;
default:
return buffer;
} }
// For those, we do not need to call fixNumLoc, but it is fast.
} }
#endif
assert(len >= 0);
fixNumericLocale(buffer, buffer + len);
return buffer; return buffer;
} }
std::string valueToString(bool value) { return value ? "true" : "false"; }
std::string valueToString( bool value ) std::string valueToQuotedString(const char* value) {
{ if (value == NULL)
return value ? "true" : "false"; return "";
}
std::string valueToQuotedString( const char *value )
{
// Not sure how to handle unicode... // Not sure how to handle unicode...
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
!containsControlCharacter(value))
return std::string("\"") + value + "\""; return std::string("\"") + value + "\"";
// We have to walk value and escape any special characters. // We have to walk value and escape any special characters.
// Appending to std::string is not efficient, but this should be rare. // Appending to std::string is not efficient, but this should be rare.
// (Note: forward slashes are *not* rare, but I am not escaping them.) // (Note: forward slashes are *not* rare, but I am not escaping them.)
std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL std::string::size_type maxsize =
strlen(value) * 2 + 3; // allescaped+quotes+NULL
std::string result; std::string result;
result.reserve(maxsize); // to avoid lots of mallocs result.reserve(maxsize); // to avoid lots of mallocs
result += "\""; result += "\"";
for (const char* c=value; *c != 0; ++c) for (const char* c = value; *c != 0; ++c) {
{ switch (*c) {
switch(*c)
{
case '\"': case '\"':
result += "\\\""; result += "\\\"";
break; break;
@@ -163,14 +155,12 @@ std::string valueToQuotedString( const char *value )
// Should add a flag to allow this compatibility mode and prevent this // Should add a flag to allow this compatibility mode and prevent this
// sequence from occurring. // sequence from occurring.
default: default:
if ( isControlCharacter( *c ) ) if (isControlCharacter(*c)) {
{
std::ostringstream oss; std::ostringstream oss;
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
<< std::setw(4) << static_cast<int>(*c);
result += oss.str(); result += oss.str();
} } else {
else
{
result += *c; result += *c;
} }
break; break;
@@ -182,43 +172,33 @@ std::string valueToQuotedString( const char *value )
// Class Writer // Class Writer
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Writer::~Writer() Writer::~Writer() {}
{
}
// Class FastWriter // Class FastWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
FastWriter::FastWriter() FastWriter::FastWriter()
: yamlCompatiblityEnabled_( false ) : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
{ omitEndingLineFeed_(false) {}
}
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
void void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
FastWriter::enableYAMLCompatibility()
{
yamlCompatiblityEnabled_ = true;
}
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
std::string std::string FastWriter::write(const Value& root) {
FastWriter::write( const Value &root )
{
document_ = ""; document_ = "";
writeValue(root); writeValue(root);
if (!omitEndingLineFeed_)
document_ += "\n"; document_ += "\n";
return document_; return document_;
} }
void FastWriter::writeValue(const Value& value) {
void switch (value.type()) {
FastWriter::writeValue( const Value &value )
{
switch ( value.type() )
{
case nullValue: case nullValue:
if (!dropNullPlaceholders_)
document_ += "null"; document_ += "null";
break; break;
case intValue: case intValue:
@@ -236,55 +216,40 @@ FastWriter::writeValue( const Value &value )
case booleanValue: case booleanValue:
document_ += valueToString(value.asBool()); document_ += valueToString(value.asBool());
break; break;
case arrayValue: case arrayValue: {
{ document_ += '[';
document_ += "[";
int size = value.size(); int size = value.size();
for ( int index =0; index < size; ++index ) for (int index = 0; index < size; ++index) {
{
if (index > 0) if (index > 0)
document_ += ","; document_ += ',';
writeValue(value[index]); writeValue(value[index]);
} }
document_ += "]"; document_ += ']';
} } break;
break; case objectValue: {
case objectValue:
{
Value::Members members(value.getMemberNames()); Value::Members members(value.getMemberNames());
document_ += "{"; document_ += '{';
for ( Value::Members::iterator it = members.begin(); for (Value::Members::iterator it = members.begin(); it != members.end();
it != members.end(); ++it) {
++it )
{
const std::string& name = *it; const std::string& name = *it;
if (it != members.begin()) if (it != members.begin())
document_ += ","; document_ += ',';
document_ += valueToQuotedString(name.c_str()); document_ += valueToQuotedString(name.c_str());
document_ += yamlCompatiblityEnabled_ ? ": " document_ += yamlCompatiblityEnabled_ ? ": " : ":";
: ":";
writeValue(value[name]); writeValue(value[name]);
} }
document_ += "}"; document_ += '}';
} } break;
break;
} }
} }
// Class StyledWriter // Class StyledWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledWriter::StyledWriter() StyledWriter::StyledWriter()
: rightMargin_( 74 ) : rightMargin_(74), indentSize_(3), addChildValues_() {}
, indentSize_( 3 )
{
}
std::string StyledWriter::write(const Value& root) {
std::string
StyledWriter::write( const Value &root )
{
document_ = ""; document_ = "";
addChildValues_ = false; addChildValues_ = false;
indentString_ = ""; indentString_ = "";
@@ -295,12 +260,8 @@ StyledWriter::write( const Value &root )
return document_; return document_;
} }
void StyledWriter::writeValue(const Value& value) {
void switch (value.type()) {
StyledWriter::writeValue( const Value &value )
{
switch ( value.type() )
{
case nullValue: case nullValue:
pushValue("null"); pushValue("null");
break; break;
@@ -322,84 +283,69 @@ StyledWriter::writeValue( const Value &value )
case arrayValue: case arrayValue:
writeArrayValue(value); writeArrayValue(value);
break; break;
case objectValue: case objectValue: {
{
Value::Members members(value.getMemberNames()); Value::Members members(value.getMemberNames());
if (members.empty()) if (members.empty())
pushValue("{}"); pushValue("{}");
else else {
{
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
Value::Members::iterator it = members.begin(); Value::Members::iterator it = members.begin();
for (;;) for (;;) {
{
const std::string& name = *it; const std::string& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str())); writeWithIndent(valueToQuotedString(name.c_str()));
document_ += " : "; document_ += " : ";
writeValue(childValue); writeValue(childValue);
if ( ++it == members.end() ) if (++it == members.end()) {
{
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
break; break;
} }
document_ += ","; document_ += ',';
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
} }
unindent(); unindent();
writeWithIndent("}"); writeWithIndent("}");
} }
} } break;
break;
} }
} }
void StyledWriter::writeArrayValue(const Value& value) {
void
StyledWriter::writeArrayValue( const Value &value )
{
unsigned size = value.size(); unsigned size = value.size();
if (size == 0) if (size == 0)
pushValue("[]"); pushValue("[]");
else else {
{
bool isArrayMultiLine = isMultineArray(value); bool isArrayMultiLine = isMultineArray(value);
if ( isArrayMultiLine ) if (isArrayMultiLine) {
{
writeWithIndent("["); writeWithIndent("[");
indent(); indent();
bool hasChildValue = !childValues_.empty(); bool hasChildValue = !childValues_.empty();
unsigned index = 0; unsigned index = 0;
for (;;) for (;;) {
{
const Value& childValue = value[index]; const Value& childValue = value[index];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
if (hasChildValue) if (hasChildValue)
writeWithIndent(childValues_[index]); writeWithIndent(childValues_[index]);
else else {
{
writeIndent(); writeIndent();
writeValue(childValue); writeValue(childValue);
} }
if ( ++index == size ) if (++index == size) {
{
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
break; break;
} }
document_ += ","; document_ += ',';
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
} }
unindent(); unindent();
writeWithIndent("]"); writeWithIndent("]");
} } else // output on a single line
else // output on a single line
{ {
assert(childValues_.size() == size); assert(childValues_.size() == size);
document_ += "[ "; document_ += "[ ";
for ( unsigned index =0; index < size; ++index ) for (unsigned index = 0; index < size; ++index) {
{
if (index > 0) if (index > 0)
document_ += ", "; document_ += ", ";
document_ += childValues_[index]; document_ += childValues_[index];
@@ -409,18 +355,14 @@ StyledWriter::writeArrayValue( const Value &value )
} }
} }
bool StyledWriter::isMultineArray(const Value& value) {
bool
StyledWriter::isMultineArray( const Value &value )
{
int size = value.size(); int size = value.size();
bool isMultiLine = size * 3 >= rightMargin_; bool isMultiLine = size * 3 >= rightMargin_;
childValues_.clear(); childValues_.clear();
for ( int index =0; index < size && !isMultiLine; ++index ) for (int index = 0; index < size && !isMultiLine; ++index) {
{
const Value& childValue = value[index]; const Value& childValue = value[index];
isMultiLine = isMultiLine || isMultiLine =
( (childValue.isArray() || childValue.isObject()) && isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
childValue.size() > 0); childValue.size() > 0);
} }
if (!isMultiLine) // check if line length > max line length if (!isMultiLine) // check if line length > max line length
@@ -428,11 +370,9 @@ StyledWriter::isMultineArray( const Value &value )
childValues_.reserve(size); childValues_.reserve(size);
addChildValues_ = true; addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for ( int index =0; index < size && !isMultiLine; ++index ) for (int index = 0; index < size; ++index) {
{
writeValue(value[index]); writeValue(value[index]);
lineLength += int(childValues_[index].length()); lineLength += int(childValues_[index].length());
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
} }
addChildValues_ = false; addChildValues_ = false;
isMultiLine = isMultiLine || lineLength >= rightMargin_; isMultiLine = isMultiLine || lineLength >= rightMargin_;
@@ -440,22 +380,15 @@ StyledWriter::isMultineArray( const Value &value )
return isMultiLine; return isMultiLine;
} }
void StyledWriter::pushValue(const std::string& value) {
void
StyledWriter::pushValue( const std::string &value )
{
if (addChildValues_) if (addChildValues_)
childValues_.push_back(value); childValues_.push_back(value);
else else
document_ += value; document_ += value;
} }
void StyledWriter::writeIndent() {
void if (!document_.empty()) {
StyledWriter::writeIndent()
{
if ( !document_.empty() )
{
char last = document_[document_.length() - 1]; char last = document_[document_.length() - 1];
if (last == ' ') // already indented if (last == ' ') // already indented
return; return;
@@ -465,102 +398,81 @@ StyledWriter::writeIndent()
document_ += indentString_; document_ += indentString_;
} }
void StyledWriter::writeWithIndent(const std::string& value) {
void
StyledWriter::writeWithIndent( const std::string &value )
{
writeIndent(); writeIndent();
document_ += value; document_ += value;
} }
void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
void void StyledWriter::unindent() {
StyledWriter::indent()
{
indentString_ += std::string( indentSize_, ' ' );
}
void
StyledWriter::unindent()
{
assert(int(indentString_.size()) >= indentSize_); assert(int(indentString_.size()) >= indentSize_);
indentString_.resize(indentString_.size() - indentSize_); indentString_.resize(indentString_.size() - indentSize_);
} }
void StyledWriter::writeCommentBeforeValue(const Value& root) {
void
StyledWriter::writeCommentBeforeValue( const Value &root )
{
if (!root.hasComment(commentBefore)) if (!root.hasComment(commentBefore))
return; return;
document_ += normalizeEOL( root.getComment( commentBefore ) );
document_ += "\n";
writeIndent();
std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
std::string::const_iterator iter = normalizedComment.begin();
while (iter != normalizedComment.end()) {
document_ += *iter;
if (*iter == '\n' && *(iter + 1) == '/')
writeIndent();
++iter;
}
// Comments are stripped of newlines, so add one here
document_ += "\n"; document_ += "\n";
} }
void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
void
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
{
if (root.hasComment(commentAfterOnSameLine)) if (root.hasComment(commentAfterOnSameLine))
document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
if ( root.hasComment( commentAfter ) ) if (root.hasComment(commentAfter)) {
{
document_ += "\n"; document_ += "\n";
document_ += normalizeEOL(root.getComment(commentAfter)); document_ += normalizeEOL(root.getComment(commentAfter));
document_ += "\n"; document_ += "\n";
} }
} }
bool StyledWriter::hasCommentForValue(const Value& value) {
bool return value.hasComment(commentBefore) ||
StyledWriter::hasCommentForValue( const Value &value ) value.hasComment(commentAfterOnSameLine) ||
{ value.hasComment(commentAfter);
return value.hasComment( commentBefore )
|| value.hasComment( commentAfterOnSameLine )
|| value.hasComment( commentAfter );
} }
std::string StyledWriter::normalizeEOL(const std::string& text) {
std::string
StyledWriter::normalizeEOL( const std::string &text )
{
std::string normalized; std::string normalized;
normalized.reserve(text.length()); normalized.reserve(text.length());
const char* begin = text.c_str(); const char* begin = text.c_str();
const char* end = begin + text.length(); const char* end = begin + text.length();
const char* current = begin; const char* current = begin;
while ( current != end ) while (current != end) {
{
char c = *current++; char c = *current++;
if (c == '\r') // mac or dos EOL if (c == '\r') // mac or dos EOL
{ {
if (*current == '\n') // convert dos EOL if (*current == '\n') // convert dos EOL
++current; ++current;
normalized += '\n'; normalized += '\n';
} } else // handle unix EOL & other char
else // handle unix EOL & other char
normalized += c; normalized += c;
} }
return normalized; return normalized;
} }
// Class StyledStreamWriter // Class StyledStreamWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledStreamWriter::StyledStreamWriter(std::string indentation) StyledStreamWriter::StyledStreamWriter(std::string indentation)
: document_(NULL) : document_(NULL), rightMargin_(74), indentation_(indentation),
, rightMargin_( 74 ) addChildValues_() {}
, indentation_( indentation )
{
}
void StyledStreamWriter::write(std::ostream& out, const Value& root) {
void
StyledStreamWriter::write( std::ostream &out, const Value &root )
{
document_ = &out; document_ = &out;
addChildValues_ = false; addChildValues_ = false;
indentString_ = ""; indentString_ = "";
@@ -571,12 +483,8 @@ StyledStreamWriter::write( std::ostream &out, const Value &root )
document_ = NULL; // Forget the stream, for safety. document_ = NULL; // Forget the stream, for safety.
} }
void StyledStreamWriter::writeValue(const Value& value) {
void switch (value.type()) {
StyledStreamWriter::writeValue( const Value &value )
{
switch ( value.type() )
{
case nullValue: case nullValue:
pushValue("null"); pushValue("null");
break; break;
@@ -598,26 +506,22 @@ StyledStreamWriter::writeValue( const Value &value )
case arrayValue: case arrayValue:
writeArrayValue(value); writeArrayValue(value);
break; break;
case objectValue: case objectValue: {
{
Value::Members members(value.getMemberNames()); Value::Members members(value.getMemberNames());
if (members.empty()) if (members.empty())
pushValue("{}"); pushValue("{}");
else else {
{
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
Value::Members::iterator it = members.begin(); Value::Members::iterator it = members.begin();
for (;;) for (;;) {
{
const std::string& name = *it; const std::string& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str())); writeWithIndent(valueToQuotedString(name.c_str()));
*document_ << " : "; *document_ << " : ";
writeValue(childValue); writeValue(childValue);
if ( ++it == members.end() ) if (++it == members.end()) {
{
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
break; break;
} }
@@ -627,40 +531,31 @@ StyledStreamWriter::writeValue( const Value &value )
unindent(); unindent();
writeWithIndent("}"); writeWithIndent("}");
} }
} } break;
break;
} }
} }
void StyledStreamWriter::writeArrayValue(const Value& value) {
void
StyledStreamWriter::writeArrayValue( const Value &value )
{
unsigned size = value.size(); unsigned size = value.size();
if (size == 0) if (size == 0)
pushValue("[]"); pushValue("[]");
else else {
{
bool isArrayMultiLine = isMultineArray(value); bool isArrayMultiLine = isMultineArray(value);
if ( isArrayMultiLine ) if (isArrayMultiLine) {
{
writeWithIndent("["); writeWithIndent("[");
indent(); indent();
bool hasChildValue = !childValues_.empty(); bool hasChildValue = !childValues_.empty();
unsigned index = 0; unsigned index = 0;
for (;;) for (;;) {
{
const Value& childValue = value[index]; const Value& childValue = value[index];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
if (hasChildValue) if (hasChildValue)
writeWithIndent(childValues_[index]); writeWithIndent(childValues_[index]);
else else {
{
writeIndent(); writeIndent();
writeValue(childValue); writeValue(childValue);
} }
if ( ++index == size ) if (++index == size) {
{
writeCommentAfterValueOnSameLine(childValue); writeCommentAfterValueOnSameLine(childValue);
break; break;
} }
@@ -669,13 +564,11 @@ StyledStreamWriter::writeArrayValue( const Value &value )
} }
unindent(); unindent();
writeWithIndent("]"); writeWithIndent("]");
} } else // output on a single line
else // output on a single line
{ {
assert(childValues_.size() == size); assert(childValues_.size() == size);
*document_ << "[ "; *document_ << "[ ";
for ( unsigned index =0; index < size; ++index ) for (unsigned index = 0; index < size; ++index) {
{
if (index > 0) if (index > 0)
*document_ << ", "; *document_ << ", ";
*document_ << childValues_[index]; *document_ << childValues_[index];
@@ -685,18 +578,14 @@ StyledStreamWriter::writeArrayValue( const Value &value )
} }
} }
bool StyledStreamWriter::isMultineArray(const Value& value) {
bool
StyledStreamWriter::isMultineArray( const Value &value )
{
int size = value.size(); int size = value.size();
bool isMultiLine = size * 3 >= rightMargin_; bool isMultiLine = size * 3 >= rightMargin_;
childValues_.clear(); childValues_.clear();
for ( int index =0; index < size && !isMultiLine; ++index ) for (int index = 0; index < size && !isMultiLine; ++index) {
{
const Value& childValue = value[index]; const Value& childValue = value[index];
isMultiLine = isMultiLine || isMultiLine =
( (childValue.isArray() || childValue.isObject()) && isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
childValue.size() > 0); childValue.size() > 0);
} }
if (!isMultiLine) // check if line length > max line length if (!isMultiLine) // check if line length > max line length
@@ -704,11 +593,9 @@ StyledStreamWriter::isMultineArray( const Value &value )
childValues_.reserve(size); childValues_.reserve(size);
addChildValues_ = true; addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for ( int index =0; index < size && !isMultiLine; ++index ) for (int index = 0; index < size; ++index) {
{
writeValue(value[index]); writeValue(value[index]);
lineLength += int(childValues_[index].length()); lineLength += int(childValues_[index].length());
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
} }
addChildValues_ = false; addChildValues_ = false;
isMultiLine = isMultiLine || lineLength >= rightMargin_; isMultiLine = isMultiLine || lineLength >= rightMargin_;
@@ -716,20 +603,14 @@ StyledStreamWriter::isMultineArray( const Value &value )
return isMultiLine; return isMultiLine;
} }
void StyledStreamWriter::pushValue(const std::string& value) {
void
StyledStreamWriter::pushValue( const std::string &value )
{
if (addChildValues_) if (addChildValues_)
childValues_.push_back(value); childValues_.push_back(value);
else else
*document_ << value; *document_ << value;
} }
void StyledStreamWriter::writeIndent() {
void
StyledStreamWriter::writeIndent()
{
/* /*
Some comments in this method would have been nice. ;-) Some comments in this method would have been nice. ;-)
@@ -745,94 +626,65 @@ StyledStreamWriter::writeIndent()
*document_ << '\n' << indentString_; *document_ << '\n' << indentString_;
} }
void StyledStreamWriter::writeWithIndent(const std::string& value) {
void
StyledStreamWriter::writeWithIndent( const std::string &value )
{
writeIndent(); writeIndent();
*document_ << value; *document_ << value;
} }
void StyledStreamWriter::indent() { indentString_ += indentation_; }
void void StyledStreamWriter::unindent() {
StyledStreamWriter::indent()
{
indentString_ += indentation_;
}
void
StyledStreamWriter::unindent()
{
assert(indentString_.size() >= indentation_.size()); assert(indentString_.size() >= indentation_.size());
indentString_.resize(indentString_.size() - indentation_.size()); indentString_.resize(indentString_.size() - indentation_.size());
} }
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
void
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
{
if (!root.hasComment(commentBefore)) if (!root.hasComment(commentBefore))
return; return;
*document_ << normalizeEOL(root.getComment(commentBefore)); *document_ << normalizeEOL(root.getComment(commentBefore));
*document_ << "\n"; *document_ << "\n";
} }
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
void
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
{
if (root.hasComment(commentAfterOnSameLine)) if (root.hasComment(commentAfterOnSameLine))
*document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
if ( root.hasComment( commentAfter ) ) if (root.hasComment(commentAfter)) {
{
*document_ << "\n"; *document_ << "\n";
*document_ << normalizeEOL(root.getComment(commentAfter)); *document_ << normalizeEOL(root.getComment(commentAfter));
*document_ << "\n"; *document_ << "\n";
} }
} }
bool StyledStreamWriter::hasCommentForValue(const Value& value) {
bool return value.hasComment(commentBefore) ||
StyledStreamWriter::hasCommentForValue( const Value &value ) value.hasComment(commentAfterOnSameLine) ||
{ value.hasComment(commentAfter);
return value.hasComment( commentBefore )
|| value.hasComment( commentAfterOnSameLine )
|| value.hasComment( commentAfter );
} }
std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
std::string
StyledStreamWriter::normalizeEOL( const std::string &text )
{
std::string normalized; std::string normalized;
normalized.reserve(text.length()); normalized.reserve(text.length());
const char* begin = text.c_str(); const char* begin = text.c_str();
const char* end = begin + text.length(); const char* end = begin + text.length();
const char* current = begin; const char* current = begin;
while ( current != end ) while (current != end) {
{
char c = *current++; char c = *current++;
if (c == '\r') // mac or dos EOL if (c == '\r') // mac or dos EOL
{ {
if (*current == '\n') // convert dos EOL if (*current == '\n') // convert dos EOL
++current; ++current;
normalized += '\n'; normalized += '\n';
} } else // handle unix EOL & other char
else // handle unix EOL & other char
normalized += c; normalized += c;
} }
return normalized; return normalized;
} }
std::ostream& operator<<(std::ostream& sout, const Value& root) {
std::ostream& operator<<( std::ostream &sout, const Value &root )
{
Json::StyledStreamWriter writer; Json::StyledStreamWriter writer;
writer.write(sout, root); writer.write(sout, root);
return sout; return sout;
} }
} // namespace Json } // namespace Json

14
src/lib_json/version.h.in Normal file
View File

@@ -0,0 +1,14 @@
// DO NOT EDIT. This file is generated by CMake from "version"
// and "version.h.in" files.
// Run CMake configure step to update it.
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "@JSONCPP_VERSION@"
# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@
# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@
# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
#endif // JSON_VERSION_H_INCLUDED

View File

@@ -0,0 +1,22 @@
IF(JSONCPP_LIB_BUILD_SHARED)
ADD_DEFINITIONS( -DJSON_DLL )
ENDIF(JSONCPP_LIB_BUILD_SHARED)
ADD_EXECUTABLE( jsoncpp_test
jsontest.cpp
jsontest.h
main.cpp
)
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
# Run unit tests in post-build
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
IF(JSONCPP_WITH_POST_BUILD_UNITTEST)
ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
POST_BUILD
COMMAND $<TARGET_FILE:jsoncpp_test>)
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST)
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)

View File

@@ -70,42 +70,31 @@
namespace JsonTest { namespace JsonTest {
// class TestResult // class TestResult
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestResult::TestResult() TestResult::TestResult()
: predicateId_( 1 ) : predicateId_(1), lastUsedPredicateId_(0), messageTarget_(0) {
, lastUsedPredicateId_( 0 )
, messageTarget_( 0 )
{
// The root predicate has id 0 // The root predicate has id 0
rootPredicateNode_.id_ = 0; rootPredicateNode_.id_ = 0;
rootPredicateNode_.next_ = 0; rootPredicateNode_.next_ = 0;
predicateStackTail_ = &rootPredicateNode_; predicateStackTail_ = &rootPredicateNode_;
} }
void TestResult::setTestName(const std::string& name) { name_ = name; }
void
TestResult::setTestName( const std::string &name )
{
name_ = name;
}
TestResult& TestResult&
TestResult::addFailure( const char *file, unsigned int line, TestResult::addFailure(const char* file, unsigned int line, const char* expr) {
const char *expr ) /// Walks the PredicateContext stack adding them to failures_ if not already
{ /// added.
/// Walks the PredicateContext stack adding them to failures_ if not already added.
unsigned int nestingLevel = 0; unsigned int nestingLevel = 0;
PredicateContext* lastNode = rootPredicateNode_.next_; PredicateContext* lastNode = rootPredicateNode_.next_;
for ( ; lastNode != 0; lastNode = lastNode->next_ ) for (; lastNode != 0; lastNode = lastNode->next_) {
{
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
{ {
lastUsedPredicateId_ = lastNode->id_; lastUsedPredicateId_ = lastNode->id_;
addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_, addFailureInfo(
nestingLevel ); lastNode->file_, lastNode->line_, lastNode->expr_, nestingLevel);
// Link the PredicateContext to the failure for message target when // Link the PredicateContext to the failure for message target when
// popping the PredicateContext. // popping the PredicateContext.
lastNode->failure_ = &(failures_.back()); lastNode->failure_ = &(failures_.back());
@@ -119,35 +108,28 @@ TestResult::addFailure( const char *file, unsigned int line,
return *this; return *this;
} }
void TestResult::addFailureInfo(const char* file,
void unsigned int line,
TestResult::addFailureInfo( const char *file, unsigned int line, const char* expr,
const char *expr, unsigned int nestingLevel ) unsigned int nestingLevel) {
{
Failure failure; Failure failure;
failure.file_ = file; failure.file_ = file;
failure.line_ = line; failure.line_ = line;
if ( expr ) if (expr) {
{
failure.expr_ = expr; failure.expr_ = expr;
} }
failure.nestingLevel_ = nestingLevel; failure.nestingLevel_ = nestingLevel;
failures_.push_back(failure); failures_.push_back(failure);
} }
TestResult& TestResult::popPredicateContext() {
TestResult &
TestResult::popPredicateContext()
{
PredicateContext* lastNode = &rootPredicateNode_; PredicateContext* lastNode = &rootPredicateNode_;
while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 ) while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) {
{
lastNode = lastNode->next_; lastNode = lastNode->next_;
} }
// Set message target to popped failure // Set message target to popped failure
PredicateContext* tail = lastNode->next_; PredicateContext* tail = lastNode->next_;
if ( tail != 0 && tail->failure_ != 0 ) if (tail != 0 && tail->failure_ != 0) {
{
messageTarget_ = tail->failure_; messageTarget_ = tail->failure_;
} }
// Remove tail from list // Remove tail from list
@@ -156,79 +138,54 @@ TestResult::popPredicateContext()
return *this; return *this;
} }
bool TestResult::failed() const { return !failures_.empty(); }
bool unsigned int TestResult::getAssertionNestingLevel() const {
TestResult::failed() const
{
return !failures_.empty();
}
unsigned int
TestResult::getAssertionNestingLevel() const
{
unsigned int level = 0; unsigned int level = 0;
const PredicateContext* lastNode = &rootPredicateNode_; const PredicateContext* lastNode = &rootPredicateNode_;
while ( lastNode->next_ != 0 ) while (lastNode->next_ != 0) {
{
lastNode = lastNode->next_; lastNode = lastNode->next_;
++level; ++level;
} }
return level; return level;
} }
void TestResult::printFailure(bool printTestName) const {
void if (failures_.empty()) {
TestResult::printFailure( bool printTestName ) const
{
if ( failures_.empty() )
{
return; return;
} }
if ( printTestName ) if (printTestName) {
{
printf("* Detail of %s test failure:\n", name_.c_str()); printf("* Detail of %s test failure:\n", name_.c_str());
} }
// Print in reverse to display the callstack in the right order // Print in reverse to display the callstack in the right order
Failures::const_iterator itEnd = failures_.end(); Failures::const_iterator itEnd = failures_.end();
for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it ) for (Failures::const_iterator it = failures_.begin(); it != itEnd; ++it) {
{
const Failure& failure = *it; const Failure& failure = *it;
std::string indent(failure.nestingLevel_ * 2, ' '); std::string indent(failure.nestingLevel_ * 2, ' ');
if ( failure.file_ ) if (failure.file_) {
{
printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_); printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_);
} }
if ( !failure.expr_.empty() ) if (!failure.expr_.empty()) {
{
printf("%s\n", failure.expr_.c_str()); printf("%s\n", failure.expr_.c_str());
} } else if (failure.file_) {
else if ( failure.file_ )
{
printf("\n"); printf("\n");
} }
if ( !failure.message_.empty() ) if (!failure.message_.empty()) {
{
std::string reindented = indentText(failure.message_, indent + " "); std::string reindented = indentText(failure.message_, indent + " ");
printf("%s\n", reindented.c_str()); printf("%s\n", reindented.c_str());
} }
} }
} }
std::string TestResult::indentText(const std::string& text,
std::string const std::string& indent) {
TestResult::indentText( const std::string &text,
const std::string &indent )
{
std::string reindented; std::string reindented;
std::string::size_type lastIndex = 0; std::string::size_type lastIndex = 0;
while ( lastIndex < text.size() ) while (lastIndex < text.size()) {
{
std::string::size_type nextIndex = text.find('\n', lastIndex); std::string::size_type nextIndex = text.find('\n', lastIndex);
if ( nextIndex == std::string::npos ) if (nextIndex == std::string::npos) {
{
nextIndex = text.size() - 1; nextIndex = text.size() - 1;
} }
reindented += indent; reindented += indent;
@@ -238,203 +195,119 @@ TestResult::indentText( const std::string &text,
return reindented; return reindented;
} }
TestResult& TestResult::addToLastFailure(const std::string& message) {
TestResult & if (messageTarget_ != 0) {
TestResult::addToLastFailure( const std::string &message )
{
if ( messageTarget_ != 0 )
{
messageTarget_->message_ += message; messageTarget_->message_ += message;
} }
return *this; return *this;
} }
TestResult& TestResult::operator<<(Json::Int64 value) {
return addToLastFailure(Json::valueToString(value));
}
TestResult & TestResult& TestResult::operator<<(Json::UInt64 value) {
TestResult::operator << ( bool value ) return addToLastFailure(Json::valueToString(value));
{ }
TestResult& TestResult::operator<<(bool value) {
return addToLastFailure(value ? "true" : "false"); return addToLastFailure(value ? "true" : "false");
} }
TestResult &
TestResult::operator << ( int value )
{
char buffer[32];
sprintf( buffer, "%d", value );
return addToLastFailure( buffer );
}
TestResult &
TestResult::operator << ( unsigned int value )
{
char buffer[32];
sprintf( buffer, "%u", value );
return addToLastFailure( buffer );
}
TestResult &
TestResult::operator << ( double value )
{
char buffer[32];
sprintf( buffer, "%16g", value );
return addToLastFailure( buffer );
}
TestResult &
TestResult::operator << ( const char *value )
{
return addToLastFailure( value ? value
: "<NULL>" );
}
TestResult &
TestResult::operator << ( const std::string &value )
{
return addToLastFailure( value );
}
// class TestCase // class TestCase
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestCase::TestCase() TestCase::TestCase() : result_(0) {}
: result_( 0 )
{
}
TestCase::~TestCase() {}
TestCase::~TestCase() void TestCase::run(TestResult& result) {
{
}
void
TestCase::run( TestResult &result )
{
result_ = &result; result_ = &result;
runTestCase(); runTestCase();
} }
// class Runner // class Runner
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Runner::Runner() Runner::Runner() {}
{
}
Runner& Runner::add(TestCaseFactory factory) {
Runner &
Runner::add( TestCaseFactory factory )
{
tests_.push_back(factory); tests_.push_back(factory);
return *this; return *this;
} }
unsigned int Runner::testCount() const {
unsigned int
Runner::testCount() const
{
return static_cast<unsigned int>(tests_.size()); return static_cast<unsigned int>(tests_.size());
} }
std::string Runner::testNameAt(unsigned int index) const {
std::string
Runner::testNameAt( unsigned int index ) const
{
TestCase* test = tests_[index](); TestCase* test = tests_[index]();
std::string name = test->testName(); std::string name = test->testName();
delete test; delete test;
return name; return name;
} }
void Runner::runTestAt(unsigned int index, TestResult& result) const {
void
Runner::runTestAt( unsigned int index, TestResult &result ) const
{
TestCase* test = tests_[index](); TestCase* test = tests_[index]();
result.setTestName(test->testName()); result.setTestName(test->testName());
printf("Testing %s: ", test->testName()); printf("Testing %s: ", test->testName());
fflush(stdout); fflush(stdout);
#if JSON_USE_EXCEPTION #if JSON_USE_EXCEPTION
try try {
{
#endif // if JSON_USE_EXCEPTION #endif // if JSON_USE_EXCEPTION
test->run(result); test->run(result);
#if JSON_USE_EXCEPTION #if JSON_USE_EXCEPTION
} }
catch ( const std::exception &e ) catch (const std::exception& e) {
{ result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
result.addFailure( __FILE__, __LINE__, << e.what();
"Unexpected exception caugth:" ) << e.what();
} }
#endif // if JSON_USE_EXCEPTION #endif // if JSON_USE_EXCEPTION
delete test; delete test;
const char *status = result.failed() ? "FAILED" const char* status = result.failed() ? "FAILED" : "OK";
: "OK";
printf("%s\n", status); printf("%s\n", status);
fflush(stdout); fflush(stdout);
} }
bool Runner::runAllTest(bool printSummary) const {
bool
Runner::runAllTest( bool printSummary ) const
{
unsigned int count = testCount(); unsigned int count = testCount();
std::deque<TestResult> failures; std::deque<TestResult> failures;
for ( unsigned int index = 0; index < count; ++index ) for (unsigned int index = 0; index < count; ++index) {
{
TestResult result; TestResult result;
runTestAt(index, result); runTestAt(index, result);
if ( result.failed() ) if (result.failed()) {
{
failures.push_back(result); failures.push_back(result);
} }
} }
if ( failures.empty() ) if (failures.empty()) {
{ if (printSummary) {
if ( printSummary )
{
printf("All %d tests passed\n", count); printf("All %d tests passed\n", count);
} }
return true; return true;
} } else {
else for (unsigned int index = 0; index < failures.size(); ++index) {
{
for ( unsigned int index = 0; index < failures.size(); ++index )
{
TestResult& result = failures[index]; TestResult& result = failures[index];
result.printFailure(count > 1); result.printFailure(count > 1);
} }
if ( printSummary ) if (printSummary) {
{
unsigned int failedCount = static_cast<unsigned int>(failures.size()); unsigned int failedCount = static_cast<unsigned int>(failures.size());
unsigned int passedCount = count - failedCount; unsigned int passedCount = count - failedCount;
printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount ); printf("%d/%d tests passed (%d failure(s))\n",
passedCount,
count,
failedCount);
} }
return false; return false;
} }
} }
bool Runner::testIndex(const std::string& testName,
bool unsigned int& indexOut) const {
Runner::testIndex( const std::string &testName,
unsigned int &indexOut ) const
{
unsigned int count = testCount(); unsigned int count = testCount();
for ( unsigned int index = 0; index < count; ++index ) for (unsigned int index = 0; index < count; ++index) {
{ if (testNameAt(index) == testName) {
if ( testNameAt(index) == testName )
{
indexOut = index; indexOut = index;
return true; return true;
} }
@@ -442,97 +315,67 @@ Runner::testIndex( const std::string &testName,
return false; return false;
} }
void Runner::listTests() const {
void
Runner::listTests() const
{
unsigned int count = testCount(); unsigned int count = testCount();
for ( unsigned int index = 0; index < count; ++index ) for (unsigned int index = 0; index < count; ++index) {
{
printf("%s\n", testNameAt(index).c_str()); printf("%s\n", testNameAt(index).c_str());
} }
} }
int Runner::runCommandLine(int argc, const char* argv[]) const {
int
Runner::runCommandLine( int argc, const char *argv[] ) const
{
typedef std::deque<std::string> TestNames; typedef std::deque<std::string> TestNames;
Runner subrunner; Runner subrunner;
for ( int index = 1; index < argc; ++index ) for (int index = 1; index < argc; ++index) {
{
std::string opt = argv[index]; std::string opt = argv[index];
if ( opt == "--list-tests" ) if (opt == "--list-tests") {
{
listTests(); listTests();
return 0; return 0;
} } else if (opt == "--test-auto") {
else if ( opt == "--test-auto" )
{
preventDialogOnCrash(); preventDialogOnCrash();
} } else if (opt == "--test") {
else if ( opt == "--test" )
{
++index; ++index;
if ( index < argc ) if (index < argc) {
{
unsigned int testNameIndex; unsigned int testNameIndex;
if ( testIndex( argv[index], testNameIndex ) ) if (testIndex(argv[index], testNameIndex)) {
{
subrunner.add(tests_[testNameIndex]); subrunner.add(tests_[testNameIndex]);
} } else {
else
{
fprintf(stderr, "Test '%s' does not exist!\n", argv[index]); fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
return 2; return 2;
} }
} } else {
else
{
printUsage(argv[0]); printUsage(argv[0]);
return 2; return 2;
} }
} } else {
else
{
printUsage(argv[0]); printUsage(argv[0]);
return 2; return 2;
} }
} }
bool succeeded; bool succeeded;
if ( subrunner.testCount() > 0 ) if (subrunner.testCount() > 0) {
{
succeeded = subrunner.runAllTest(subrunner.testCount() > 1); succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
} } else {
else
{
succeeded = runAllTest(true); succeeded = runAllTest(true);
} }
return succeeded ? 0 return succeeded ? 0 : 1;
: 1;
} }
#if defined(_MSC_VER) && defined(_DEBUG)
#if defined(_MSC_VER)
// Hook MSVCRT assertions to prevent dialog from appearing // Hook MSVCRT assertions to prevent dialog from appearing
static int static int
msvcrtSilentReportHook( int reportType, char *message, int *returnValue ) msvcrtSilentReportHook(int reportType, char* message, int* /*returnValue*/) {
{
// The default CRT handling of error and assertion is to display // The default CRT handling of error and assertion is to display
// an error dialog to the user. // an error dialog to the user.
// Instead, when an error or an assertion occurs, we force the // Instead, when an error or an assertion occurs, we force the
// application to terminate using abort() after display // application to terminate using abort() after display
// the message on stderr. // the message on stderr.
if ( reportType == _CRT_ERROR || if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
reportType == _CRT_ASSERT )
{
// calling abort() cause the ReportHook to be called // calling abort() cause the ReportHook to be called
// The following is used to detect this case and let's the // The following is used to detect this case and let's the
// error handler fallback on its default behaviour ( // error handler fallback on its default behaviour (
// display a warning message) // display a warning message)
static volatile bool isAborting = false; static volatile bool isAborting = false;
if ( isAborting ) if (isAborting) {
{
return TRUE; return TRUE;
} }
isAborting = true; isAborting = true;
@@ -546,13 +389,12 @@ msvcrtSilentReportHook( int reportType, char *message, int *returnValue )
} }
#endif // if defined(_MSC_VER) #endif // if defined(_MSC_VER)
void Runner::preventDialogOnCrash() {
void #if defined(_MSC_VER) && defined(_DEBUG)
Runner::preventDialogOnCrash()
{
#if defined(_MSC_VER)
// Install a hook to prevent MSVCRT error and assertion from // Install a hook to prevent MSVCRT error and assertion from
// popping a dialog. // popping a dialog
// This function a NO-OP in release configuration
// (which cause warning since msvcrtSilentReportHook is not referenced)
_CrtSetReportHook(&msvcrtSilentReportHook); _CrtSetReportHook(&msvcrtSilentReportHook);
#endif // if defined(_MSC_VER) #endif // if defined(_MSC_VER)
@@ -562,17 +404,13 @@ Runner::preventDialogOnCrash()
#if defined(_WIN32) #if defined(_WIN32)
// Prevents the system from popping a dialog for debugging if the // Prevents the system from popping a dialog for debugging if the
// application fails due to invalid memory access. // application fails due to invalid memory access.
SetErrorMode( SEM_FAILCRITICALERRORS SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
| SEM_NOGPFAULTERRORBOX SEM_NOOPENFILEERRORBOX);
| SEM_NOOPENFILEERRORBOX );
#endif // if defined(_WIN32) #endif // if defined(_WIN32)
} }
void void Runner::printUsage(const char* appName) {
Runner::printUsage( const char *appName ) printf("Usage: %s [options]\n"
{
printf(
"Usage: %s [options]\n"
"\n" "\n"
"If --test is not specified, then all the test cases be run.\n" "If --test is not specified, then all the test cases be run.\n"
"\n" "\n"
@@ -581,22 +419,20 @@ Runner::printUsage( const char *appName )
" output and exit.\n" " output and exit.\n"
"--test TESTNAME: executes the test case with the specified name.\n" "--test TESTNAME: executes the test case with the specified name.\n"
" May be repeated.\n" " May be repeated.\n"
"--test-auto: prevent dialog prompting for debugging on crash.\n" "--test-auto: prevent dialog prompting for debugging on crash.\n",
, appName ); appName);
} }
// Assertion functions // Assertion functions
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestResult & TestResult& checkStringEqual(TestResult& result,
checkStringEqual( TestResult &result, const std::string& expected,
const std::string &expected, const std::string &actual, const std::string& actual,
const char *file, unsigned int line, const char *expr ) const char* file,
{ unsigned int line,
if ( expected != actual ) const char* expr) {
{ if (expected != actual) {
result.addFailure(file, line, expr); result.addFailure(file, line, expr);
result << "Expected: '" << expected << "'\n"; result << "Expected: '" << expected << "'\n";
result << "Actual : '" << actual << "'"; result << "Actual : '" << actual << "'";
@@ -604,5 +440,4 @@ checkStringEqual( TestResult &result,
return result; return result;
} }
} // namespace JsonTest } // namespace JsonTest

View File

@@ -7,8 +7,11 @@
#define JSONTEST_H_INCLUDED #define JSONTEST_H_INCLUDED
#include <json/config.h> #include <json/config.h>
#include <json/value.h>
#include <json/writer.h>
#include <stdio.h> #include <stdio.h>
#include <deque> #include <deque>
#include <sstream>
#include <string> #include <string>
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
@@ -17,8 +20,6 @@
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
/** \brief Unit testing framework. /** \brief Unit testing framework.
* \warning: all assertions are non-aborting, test case execution will continue * \warning: all assertions are non-aborting, test case execution will continue
* even if an assertion namespace. * even if an assertion namespace.
@@ -27,9 +28,7 @@
*/ */
namespace JsonTest { namespace JsonTest {
class Failure {
class Failure
{
public: public:
const char* file_; const char* file_;
unsigned int line_; unsigned int line_;
@@ -38,12 +37,10 @@ namespace JsonTest {
unsigned int nestingLevel_; unsigned int nestingLevel_;
}; };
/// Context used to create the assertion callstack on failure. /// Context used to create the assertion callstack on failure.
/// Must be a POD to allow inline initialisation without stepping /// Must be a POD to allow inline initialisation without stepping
/// into the debugger. /// into the debugger.
struct PredicateContext struct PredicateContext {
{
typedef unsigned int Id; typedef unsigned int Id;
Id id_; Id id_;
const char* file_; const char* file_;
@@ -55,8 +52,7 @@ namespace JsonTest {
Failure* failure_; Failure* failure_;
}; };
class TestResult class TestResult {
{
public: public:
TestResult(); TestResult();
@@ -72,8 +68,8 @@ namespace JsonTest {
void setTestName(const std::string& name); void setTestName(const std::string& name);
/// Adds an assertion failure. /// Adds an assertion failure.
TestResult &addFailure( const char *file, unsigned int line, TestResult&
const char *expr = 0 ); addFailure(const char* file, unsigned int line, const char* expr = 0);
/// Removes the last PredicateContext added to the predicate stack /// Removes the last PredicateContext added to the predicate stack
/// chained list. /// chained list.
@@ -84,19 +80,29 @@ namespace JsonTest {
void printFailure(bool printTestName) const; void printFailure(bool printTestName) const;
// Generic operator that will work with anything ostream can deal with.
template <typename T> TestResult& operator<<(const T& value) {
std::ostringstream oss;
oss.precision(16);
oss.setf(std::ios_base::floatfield);
oss << value;
return addToLastFailure(oss.str());
}
// Specialized versions.
TestResult& operator<<(bool value); TestResult& operator<<(bool value);
TestResult &operator << ( int value ); // std:ostream does not support 64bits integers on all STL implementation
TestResult &operator << ( unsigned int value ); TestResult& operator<<(Json::Int64 value);
TestResult &operator << ( double value ); TestResult& operator<<(Json::UInt64 value);
TestResult &operator << ( const char *value );
TestResult &operator << ( const std::string &value );
private: private:
TestResult& addToLastFailure(const std::string& message); TestResult& addToLastFailure(const std::string& message);
unsigned int getAssertionNestingLevel() const; unsigned int getAssertionNestingLevel() const;
/// Adds a failure or a predicate context /// Adds a failure or a predicate context
void addFailureInfo( const char *file, unsigned int line, void addFailureInfo(const char* file,
const char *expr, unsigned int nestingLevel ); unsigned int line,
const char* expr,
unsigned int nestingLevel);
static std::string indentText(const std::string& text, static std::string indentText(const std::string& text,
const std::string& indent); const std::string& indent);
@@ -109,9 +115,7 @@ namespace JsonTest {
Failure* messageTarget_; Failure* messageTarget_;
}; };
class TestCase {
class TestCase
{
public: public:
TestCase(); TestCase();
@@ -131,8 +135,7 @@ namespace JsonTest {
/// Function pointer type for TestCase factory /// Function pointer type for TestCase factory
typedef TestCase* (*TestCaseFactory)(); typedef TestCase* (*TestCaseFactory)();
class Runner class Runner {
{
public: public:
Runner(); Runner();
@@ -173,78 +176,96 @@ namespace JsonTest {
Factories tests_; Factories tests_;
}; };
template<typename T> template <typename T, typename U>
TestResult & TestResult& checkEqual(TestResult& result,
checkEqual( TestResult &result, const T &expected, const T &actual, const T& expected,
const char *file, unsigned int line, const char *expr ) const U& actual,
{ const char* file,
if ( expected != actual ) unsigned int line,
{ const char* expr) {
if (static_cast<U>(expected) != actual) {
result.addFailure(file, line, expr); result.addFailure(file, line, expr);
result << "Expected: " << expected << "\n"; result << "Expected: " << static_cast<U>(expected) << "\n";
result << "Actual : " << actual; result << "Actual : " << actual;
} }
return result; return result;
} }
TestResult & TestResult& checkStringEqual(TestResult& result,
checkStringEqual( TestResult &result, const std::string& expected,
const std::string &expected, const std::string &actual, const std::string& actual,
const char *file, unsigned int line, const char *expr ); const char* file,
unsigned int line,
const char* expr);
} // namespace JsonTest } // namespace JsonTest
/// \brief Asserts that the given expression is true. /// \brief Asserts that the given expression is true.
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y; /// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
/// JSONTEST_ASSERT( x == y ); /// JSONTEST_ASSERT( x == y );
#define JSONTEST_ASSERT(expr) \ #define JSONTEST_ASSERT(expr) \
if ( expr ) \ if (expr) { \
{ \ } else \
} \
else \
result_->addFailure(__FILE__, __LINE__, #expr) result_->addFailure(__FILE__, __LINE__, #expr)
/// \brief Asserts that the given predicate is true. /// \brief Asserts that the given predicate is true.
/// The predicate may do other assertions and be a member function of the fixture. /// The predicate may do other assertions and be a member function of the
/// fixture.
#define JSONTEST_ASSERT_PRED(expr) \ #define JSONTEST_ASSERT_PRED(expr) \
{ \ { \
JsonTest::PredicateContext _minitest_Context = { \ JsonTest::PredicateContext _minitest_Context = { \
result_->predicateId_, __FILE__, __LINE__, #expr }; \ result_->predicateId_, __FILE__, __LINE__, #expr \
}; \
result_->predicateStackTail_->next_ = &_minitest_Context; \ result_->predicateStackTail_->next_ = &_minitest_Context; \
result_->predicateId_ += 1; \ result_->predicateId_ += 1; \
result_->predicateStackTail_ = &_minitest_Context; \ result_->predicateStackTail_ = &_minitest_Context; \
(expr); \ (expr); \
result_->popPredicateContext(); \ result_->popPredicateContext(); \
} \ }
*result_
/// \brief Asserts that two values are equals. /// \brief Asserts that two values are equals.
#define JSONTEST_ASSERT_EQUAL(expected, actual) \ #define JSONTEST_ASSERT_EQUAL(expected, actual) \
JsonTest::checkEqual( *result_, expected, actual, \ JsonTest::checkEqual(*result_, \
__FILE__, __LINE__, \ expected, \
actual, \
__FILE__, \
__LINE__, \
#expected " == " #actual) #expected " == " #actual)
/// \brief Asserts that two values are equals. /// \brief Asserts that two values are equals.
#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \ #define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
JsonTest::checkStringEqual(*result_, \ JsonTest::checkStringEqual(*result_, \
std::string(expected), std::string(actual), \ std::string(expected), \
std::string(actual), \
__FILE__, \
__LINE__, \
#expected " == " #actual) #expected " == " #actual)
/// \brief Asserts that a given expression throws an exception
#define JSONTEST_ASSERT_THROWS(expr) \
{ \
bool _threw = false; \
try { \
expr; \
} \
catch (...) { \
_threw = true; \
} \
if (!_threw) \
result_->addFailure( \
__FILE__, __LINE__, "expected exception thrown: " #expr); \
}
/// \brief Begin a fixture test case. /// \brief Begin a fixture test case.
#define JSONTEST_FIXTURE(FixtureType, name) \ #define JSONTEST_FIXTURE(FixtureType, name) \
class Test##FixtureType##name : public FixtureType \ class Test##FixtureType##name : public FixtureType { \
{ \
public: \ public: \
static JsonTest::TestCase *factory() \ static JsonTest::TestCase* factory() { \
{ \
return new Test##FixtureType##name(); \ return new Test##FixtureType##name(); \
} \ } \
\
public: /* overidden from TestCase */ \ public: /* overidden from TestCase */ \
virtual const char *testName() const \ virtual const char* testName() const { return #FixtureType "/" #name; } \
{ \
return #FixtureType "/" #name; \
} \
virtual void runTestCase(); \ virtual void runTestCase(); \
}; \ }; \
\ \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,3 @@
// C++ style comment
.=null .=null

View File

@@ -1,2 +1,4 @@
/* C style comment
*/
.=null .=null

View File

@@ -0,0 +1,14 @@
.={}
/* C-style comment
C-style-2 comment */
.c-test={}
.c-test.a=1
/* Internal comment c-style */
.c-test.b=2
// C++-style comment
.cpp-test={}
// Multiline comment cpp-style
// Second line
.cpp-test.c=3
.cpp-test.d=4

View File

@@ -0,0 +1,17 @@
{
/* C-style comment
C-style-2 comment */
"c-test" : {
"a" : 1,
/* Internal comment c-style */
"b" : 2
},
// C++-style comment
"cpp-test" : {
// Multiline comment cpp-style
// Second line
"c" : 3,
"d" : 4
}
}

View File

@@ -1 +1,2 @@
// Max signed integer
.=2147483647 .=2147483647

View File

@@ -1 +1,2 @@
// Min signed integer
.=-2147483648 .=-2147483648

View File

@@ -1 +1,2 @@
// Max unsigned integer
.=4294967295 .=4294967295

View File

@@ -1,2 +1,3 @@
// Min unsigned integer
.=0 .=0

View File

@@ -1,3 +1,11 @@
/* A comment
at the beginning of the file.
*/
.={} .={}
.first=1 .first=1
/* Comment before 'second'
*/
.second=2 .second=2
/* A comment at
the end of the file.
*/

View File

@@ -1,2 +1,3 @@
// 2^33 => out of integer range, switch to double
.=8589934592 .=8589934592

View File

@@ -1,2 +1,3 @@
// -2^32 => out of signed integer range, switch to double
.=-4294967295 .=-4294967295

View File

@@ -1,2 +1,3 @@
// -2^32 => out of signed integer range, switch to double
.=-4294967295 .=-4294967295

View File

@@ -1,2 +1,3 @@
// 1.2345678
.=1.2345678 .=1.2345678

View File

@@ -1,3 +1,4 @@
// 1234567.8
.=1234567.8 .=1234567.8

View File

@@ -1,3 +1,4 @@
// -1.2345678
.=-1.2345678 .=-1.2345678

View File

@@ -1,3 +1,4 @@
// -1234567.8
.=-1234567.8 .=-1234567.8

View File

@@ -0,0 +1,4 @@
// Out of 32-bit integer range, switch to double in 32-bit mode. Length the
// same as UINT_MAX in base 10 and digit less than UINT_MAX's last digit in
// order to catch a bug in the parsing code.
.=4300000001

View File

@@ -0,0 +1,4 @@
// Out of 32-bit integer range, switch to double in 32-bit mode. Length the
// same as UINT_MAX in base 10 and digit less than UINT_MAX's last digit in
// order to catch a bug in the parsing code.
4300000001

View File

@@ -0,0 +1,4 @@
// Out of 64-bit integer range, switch to double in all modes. Length the same
// as ULONG_MAX in base 10 and digit less than ULONG_MAX's last digit in order
// to catch a bug in the parsing code.
.=1.9e+19

View File

@@ -0,0 +1,4 @@
// Out of 64-bit integer range, switch to double in all modes. Length the same
// as ULONG_MAX in base 10 and digit less than ULONG_MAX's last digit in order
// to catch a bug in the parsing code.
19000000000000000001

View File

@@ -0,0 +1,4 @@
// Out of 32-bit signed integer range, switch to double in all modes. Length
// the same as INT_MIN in base 10 and digit less than INT_MIN's last digit in
// order to catch a bug in the parsing code.
.=-2200000001

View File

@@ -0,0 +1,4 @@
// Out of 32-bit signed integer range, switch to double in all modes. Length
// the same as INT_MIN in base 10 and digit less than INT_MIN's last digit in
// order to catch a bug in the parsing code.
-2200000001

View File

@@ -0,0 +1,4 @@
// Out of 64-bit signed integer range, switch to double in all modes. Length
// the same as LONG_MIN in base 10 and digit less than LONG_MIN's last digit in
// order to catch a bug in the parsing code.
.=-9.3e+18

View File

@@ -0,0 +1,4 @@
// Out of 64-bit signed integer range, switch to double in all modes. Length
// the same as LONG_MIN in base 10 and digit less than LONG_MIN's last digit in
// order to catch a bug in the parsing code.
-9300000000000000001

View File

@@ -0,0 +1,2 @@
// 2^64 -> switch to double.
.=1.844674407370955e+19

View File

@@ -0,0 +1,2 @@
// 2^64 -> switch to double.
18446744073709551616

View File

@@ -0,0 +1,2 @@
.=""abc\def""

View File

@@ -0,0 +1,2 @@
"\"abc\\def\""

View File

@@ -0,0 +1,2 @@
.="\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"

View File

@@ -0,0 +1,2 @@
"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"

View File

@@ -1,11 +1,12 @@
from __future__ import print_function
import glob import glob
import os.path import os.path
for path in glob.glob( '*.json' ): for path in glob.glob( '*.json' ):
text = file(path,'rt').read() text = file(path,'rt').read()
target = os.path.splitext(path)[0] + '.expected' target = os.path.splitext(path)[0] + '.expected'
if os.path.exists( target ): if os.path.exists( target ):
print 'skipping:', target print('skipping:', target)
else: else:
print 'creating:', target print('creating:', target)
file(target,'wt').write(text) file(target,'wt').write(text)

View File

@@ -1,12 +1,12 @@
# Simple implementation of a json test runner to run the test against json-py. # Simple implementation of a json test runner to run the test against json-py.
from __future__ import print_function
import sys import sys
import os.path import os.path
import json import json
import types import types
if len(sys.argv) != 2: if len(sys.argv) != 2:
print "Usage: %s input-json-file", sys.argv[0] print("Usage: %s input-json-file", sys.argv[0])
sys.exit(3) sys.exit(3)
input_path = sys.argv[1] input_path = sys.argv[1]

View File

@@ -1,3 +1,4 @@
from __future__ import print_function
import sys import sys
import os import os
import os.path import os.path
@@ -11,7 +12,7 @@ def compareOutputs( expected, actual, message ):
actual = actual.strip().replace('\r','').split('\n') actual = actual.strip().replace('\r','').split('\n')
diff_line = 0 diff_line = 0
max_line_to_compare = min( len(expected), len(actual) ) max_line_to_compare = min( len(expected), len(actual) )
for index in xrange(0,max_line_to_compare): for index in range(0,max_line_to_compare):
if expected[index].strip() != actual[index].strip(): if expected[index].strip() != actual[index].strip():
diff_line = index + 1 diff_line = index + 1
break break
@@ -34,7 +35,7 @@ def compareOutputs( expected, actual, message ):
def safeReadFile( path ): def safeReadFile( path ):
try: try:
return file( path, 'rt' ).read() return file( path, 'rt' ).read()
except IOError, e: except IOError as e:
return '<File "%s" is missing: %s>' % (path,e) return '<File "%s" is missing: %s>' % (path,e)
def runAllTests( jsontest_executable_path, input_dir = None, def runAllTests( jsontest_executable_path, input_dir = None,
@@ -51,7 +52,7 @@ def runAllTests( jsontest_executable_path, input_dir = None,
for input_path in tests + test_jsonchecker: for input_path in tests + test_jsonchecker:
expect_failure = os.path.basename( input_path ).startswith( 'fail' ) expect_failure = os.path.basename( input_path ).startswith( 'fail' )
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
print 'TESTING:', input_path, print('TESTING:', input_path, end=' ')
options = is_json_checker_test and '--json-checker' or '' options = is_json_checker_test and '--json-checker' or ''
pipe = os.popen( "%s%s %s %s" % ( pipe = os.popen( "%s%s %s %s" % (
valgrind_path, jsontest_executable_path, options, valgrind_path, jsontest_executable_path, options,
@@ -61,24 +62,24 @@ def runAllTests( jsontest_executable_path, input_dir = None,
if is_json_checker_test: if is_json_checker_test:
if expect_failure: if expect_failure:
if status is None: if status is None:
print 'FAILED' print('FAILED')
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' % failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
safeReadFile(input_path)) ) safeReadFile(input_path)) )
else: else:
print 'OK' print('OK')
else: else:
if status is not None: if status is not None:
print 'FAILED' print('FAILED')
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) ) failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
else: else:
print 'OK' print('OK')
else: else:
base_path = os.path.splitext(input_path)[0] base_path = os.path.splitext(input_path)[0]
actual_output = safeReadFile( base_path + '.actual' ) actual_output = safeReadFile( base_path + '.actual' )
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' ) actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
file(base_path + '.process-output','wt').write( process_output ) file(base_path + '.process-output','wt').write( process_output )
if status: if status:
print 'parsing failed' print('parsing failed')
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) ) failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
else: else:
expected_output_path = os.path.splitext(input_path)[0] + '.expected' expected_output_path = os.path.splitext(input_path)[0] + '.expected'
@@ -86,23 +87,23 @@ def runAllTests( jsontest_executable_path, input_dir = None,
detail = ( compareOutputs( expected_output, actual_output, 'input' ) detail = ( compareOutputs( expected_output, actual_output, 'input' )
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) ) or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
if detail: if detail:
print 'FAILED' print('FAILED')
failed_tests.append( (input_path, detail) ) failed_tests.append( (input_path, detail) )
else: else:
print 'OK' print('OK')
if failed_tests: if failed_tests:
print print()
print 'Failure details:' print('Failure details:')
for failed_test in failed_tests: for failed_test in failed_tests:
print '* Test', failed_test[0] print('* Test', failed_test[0])
print failed_test[1] print(failed_test[1])
print print()
print 'Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests), print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
len(failed_tests) ) len(failed_tests) ))
return 1 return 1
else: else:
print 'All %d tests passed.' % len(tests) print('All %d tests passed.' % len(tests))
return 0 return 0
def main(): def main():

View File

@@ -1,8 +1,9 @@
from __future__ import print_function
from glob import glob
import sys import sys
import os import os
import os.path import os.path
import subprocess import subprocess
from glob import glob
import optparse import optparse
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes' VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes'
@@ -28,29 +29,29 @@ def runAllTests( exe_path, use_valgrind=False ):
test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind ) test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
status, test_names = test_proxy.run( ['--list-tests'] ) status, test_names = test_proxy.run( ['--list-tests'] )
if not status: if not status:
print >> sys.stderr, "Failed to obtain unit tests list:\n" + test_names print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
return 1 return 1
test_names = [name.strip() for name in test_names.strip().split('\n')] test_names = [name.strip() for name in test_names.strip().split('\n')]
failures = [] failures = []
for name in test_names: for name in test_names:
print 'TESTING %s:' % name, print('TESTING %s:' % name, end=' ')
succeed, result = test_proxy.run( ['--test', name] ) succeed, result = test_proxy.run( ['--test', name] )
if succeed: if succeed:
print 'OK' print('OK')
else: else:
failures.append( (name, result) ) failures.append( (name, result) )
print 'FAILED' print('FAILED')
failed_count = len(failures) failed_count = len(failures)
pass_count = len(test_names) - failed_count pass_count = len(test_names) - failed_count
if failed_count: if failed_count:
print print()
for name, result in failures: for name, result in failures:
print result print(result)
print '%d/%d tests passed (%d failure(s))' % ( print('%d/%d tests passed (%d failure(s))' % (
pass_count, len(test_names), failed_count) pass_count, len(test_names), failed_count))
return 1 return 1
else: else:
print 'All %d tests passed' % len(test_names) print('All %d tests passed' % len(test_names))
return 0 return 0
def main(): def main():

View File

@@ -1 +1 @@
0.6.0-rc2 1.0.0