Squashed 'src/http/qjson/' content from commit c6d92ba

git-subtree-dir: src/http/qjson
git-subtree-split: c6d92bada76be2c46dcf6f585f03b2fba47f9da3
This commit is contained in:
Keith Bennett 2014-03-22 17:05:45 +00:00
commit 5c71260c12
67 changed files with 13978 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
lib
Makefile
doc/html
# -- kdevelop
.kdev4
*.kdev4

121
CMakeLists.txt Normal file
View File

@ -0,0 +1,121 @@
PROJECT(qjson)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII" )
# Force cmake 2.8.8 in order to have a decent support of Qt5
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8)
CMAKE_POLICY(SET CMP0003 NEW)
# Do not link against qtmain on Windows
cmake_policy(SET CMP0020 OLD)
set(CMAKE_INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
IF("${CMAKE_BUILD_TYPE}" MATCHES "^Rel.*")
ADD_DEFINITIONS("-DQT_NO_DEBUG_OUTPUT")
ENDIF("${CMAKE_BUILD_TYPE}" MATCHES "^Rel.*")
# Ability to disable verbose debug output
IF(QJSON_VERBOSE_DEBUG_OUTPUT)
ADD_DEFINITIONS("-DQJSON_VERBOSE_DEBUG_OUTPUT")
endif(QJSON_VERBOSE_DEBUG_OUTPUT)
# On Windows debug library should have 'd' postfix.
IF (WIN32)
SET(CMAKE_DEBUG_POSTFIX "d")
ENDIF (WIN32)
OPTION(OSX_FRAMEWORK "Build a Mac OS X Framework")
SET(FRAMEWORK_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/Library/Frameworks"
CACHE PATH "Where to place qjson.framework if OSX_FRAMEWORK is selected")
# Don't use absolute path in qjson-targets-*.cmake
# (This will have no effect with CMake < 2.8)
SET(QT_USE_IMPORTED_TARGETS TRUE)
option(QT4_BUILD "Force building with Qt4 even if Qt5 is found")
IF (NOT QT4_BUILD)
FIND_PACKAGE( Qt5Core QUIET )
ENDIF()
IF (Qt5Core_FOUND)
MESSAGE ("Qt5 found")
INCLUDE_DIRECTORIES(${Qt5Core_INCLUDE_DIRS})
ADD_DEFINITIONS(${Qt5Core_DEFINITIONS})
# Tell CMake to run moc when necessary:
set(CMAKE_AUTOMOC ON)
# As moc files are generated in the binary dir, tell CMake
# to always look for includes there:
set(CMAKE_INCLUDE_CURRENT_DIR ON)
ELSE()
MESSAGE ("Qt5 not found, searching for Qt4")
# Find Qt4
FIND_PACKAGE( Qt4 REQUIRED )
# Include the cmake file needed to use qt4
INCLUDE( ${QT_USE_FILE} )
ENDIF()
IF (NOT WIN32)
SET( QT_DONT_USE_QTGUI TRUE )
ENDIF()
#add extra search paths for libraries and includes
SET (LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "Directory where lib will install")
SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The directory the headers are installed in")
SET (CMAKECONFIG_INSTALL_DIR "${LIB_INSTALL_DIR}/cmake/${CMAKE_PROJECT_NAME}" CACHE PATH "Directory where to install QJSONConfig.cmake")
set(QJSON_LIB_MAJOR_VERSION "0")
set(QJSON_LIB_MINOR_VERSION "8")
set(QJSON_LIB_PATCH_VERSION "1")
set(QJSON_LIB_VERSION_STRING "${QJSON_LIB_MAJOR_VERSION}.${QJSON_LIB_MINOR_VERSION}.${QJSON_LIB_PATCH_VERSION}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" )
# pkg-config
IF (NOT WIN32)
CONFIGURE_FILE (${CMAKE_CURRENT_SOURCE_DIR}/QJson.pc.in
${CMAKE_CURRENT_BINARY_DIR}/QJson.pc
@ONLY)
INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/QJson.pc
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
ENDIF (NOT WIN32)
# Subdirs
ADD_SUBDIRECTORY(src)
IF (KDE4_BUILD_TESTS OR QJSON_BUILD_TESTS)
enable_testing()
ADD_SUBDIRECTORY(tests)
ENDIF (KDE4_BUILD_TESTS OR QJSON_BUILD_TESTS)
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
INSTALL(EXPORT qjson-export DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE QJSONTargets.cmake)
# figure out the relative path from the installed Config.cmake file to the install prefix (which may be at
# runtime different from the chosen CMAKE_INSTALL_PREFIX if under Windows the package was installed anywhere)
# This relative path will be configured into the QJSONConfig.cmake
file(RELATIVE_PATH relInstallDir ${CMAKE_INSTALL_PREFIX}/${CMAKECONFIG_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX} )
# cmake-modules
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/QJSONConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/QJSONConfig.cmake
@ONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/QJSONConfigVersion.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/QJSONConfigVersion.cmake
@ONLY)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/QJSONConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/QJSONConfigVersion.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}")
ADD_CUSTOM_TARGET(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

504
COPYING.lib Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

103
ChangeLog Normal file
View File

@ -0,0 +1,103 @@
Mon Jan 28 23:01:40 CET 2013 Flavio Castelli <flavio@castelli.name>
* Fix compilation on BlackBerry 10.
Tue Nov 27 11:04:12 CET 2012 Flavio Castelli <flavio@castelli.name>
* Relase 0.8.1:
- ensure API and ABI compatibility with 0.7.1
Thu Nov 22 21:20:11 CET 2012 Flavio Castelli <flavio@castelli.name>
* Fix unsafe pointer usage in Serializer::serialize()
----------------------------------------------------------------------
Wed Nov 21 22:01:51 CET 2012 Flavio Castelli <flavio@castelli.name>
* Version 0.8.0 released
Tue Nov 20 11:19:49 CET 2012 Flavio Castelli <flavio@castelli.name>
* Serializer: handle QVariantHash
Tue Oct 30 15:50:10 CET 2012 Flavio Castelli <flavio@castelli.name>
* Improve error handling inside of Serializer
* Serializer: handle quint16.
Tue Jan 31 10:15:06 CET 2012 Flavio Castelli <flavio@castelli.name>
* Make possible to build qjson as an OS X framework.
Fri Nov 04 16:50:56 CET 2011 Flavio Castelli <flavio@castelli.name>
* Make possible to set double precision during serialization.
Wed Aug 24 17:58:56 CEST 2011 Flavio Castelli <flavio@castelli.name>
* Buildsystem adjustments, fix issues mentioned here:
- http://lists.kde.org/?l=kde-buildsystem&m=130947194605100&w=3
- http://lists.kde.org/?l=kde-buildsystem&m=128835747626464&w=3
The biggest difference now is that FindQJSON.cmake is not provided
anymore. Instead, QJSONConfig.cmake and QJSONConfigVersion.cmake are
installed and can be used in find_package(QJSON) calls. Applications
using QJson can write their own FindQJSON.cmake files if they need to.
Fri Apr 23:04:29 CEST 2011 Flavio Castelli <flavio@castelli.name>
* Fixed QVariant de-serialization. QVariant properties were ignored
during QVariant -> QObject conversion.
Sun Dec 18:59:28 CET 2010 Flavio Castelli <flavio@castelli.name>
* It's now possible to indent the output produced by the Serializer.
Mon Sep 06 18:53:02 CEST 2010 Flavio Castelli <flavio@castelli.name>
* 50% performance improvement when parsing numbers.
Sun Jul 04 15:41:08 CEST 2010 Flavio Castelli <flavio@castelli.name>
* fix make install when not installing as root
* provide "make uninstall"
Tue Jun 15 13:16:57 CEST 2010 Flavio Castelli <flavio@castelli.name>
* Allow top level values
----------------------------------------------------------------------
Sat Mar 13 23:57:00 CEST 2009 - flavio@castelli.name
* Merged the symbian branch into master,
----------------------------------------------------------------------
Sun Oct 11 19:18:00 CEST 2009 - flavio@castelli.name
* Updated to 0.6.3: fixed a bug affecting ulonglong numbers serialization.
-------------------------------------------------------------------
Wed Sep 15 19:21:00 CEST 2009 - flavio@castelli.name
* Updated to 0.6.2: fixed a bug affecting ulonglong numbers parsing.
-------------------------------------------------------------------
Wed Sep 09 09:55:00 CEST 2009 - flavio@castelli.name
* Updated to 0.6.1: relevant bugs fixed.
* Moved the SerializerRunnable class inside QJson namespace.
* Fixed a bug in cmdline_tester.
-------------------------------------------------------------------
Mon Jul 20 15:24:32 CEST 2009 - prusnak@suse.cz
* Updated to 0.6.0 (KDE SVN rev 999750).
-------------------------------------------------------------------
Mon Apr 07 00:00:00 UTC 2009 - flavio@castelli.name
* Released 0.5.1 - added unicode support.
-------------------------------------------------------------------
Mon Apr 03 00:00:00 UTC 2009 - flavio@castelli.name
* First release.

6
QJSONConfig.cmake.in Normal file
View File

@ -0,0 +1,6 @@
GET_FILENAME_COMPONENT(myDir ${CMAKE_CURRENT_LIST_FILE} PATH)
SET(QJSON_LIBRARIES qjson)
SET(QJSON_INCLUDE_DIR "@INCLUDE_INSTALL_DIR@")
include(${myDir}/QJSONTargets.cmake)

View File

@ -0,0 +1,9 @@
SET(PACKAGE_VERSION "@QJSON_LIB_VERSION_STRING@")
IF (PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
SET(PACKAGE_VERSION_EXACT TRUE)
ENDIF (PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
IF (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)
SET(PACKAGE_VERSION_COMPATIBLE TRUE)
ELSE (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)
SET(PACKAGE_VERSION_UNSUITABLE TRUE)
ENDIF (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)

11
QJson.pc.in Normal file
View File

@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=@LIB_INSTALL_DIR@
includedir=@INCLUDE_INSTALL_DIR@
Name: QJson
Description: QJson is a qt-based library that maps JSON data to QVariant objects
Version: @QJSON_LIB_MAJOR_VERSION@.@QJSON_LIB_MINOR_VERSION@.@QJSON_LIB_PATCH_VERSION@
Requires: QtCore
Libs: -L${libdir} -lqjson
Cflags: -I${includedir}

89
README.license Normal file
View File

@ -0,0 +1,89 @@
Qjson version xxxx, Date
The following files are licensed under LGPL V2.1:
------------------------------------------------
src/json_parser.yy
src/json_scanner.cpp
src/json_scanner.h
src/parser.cpp
src/parser.h
src/parser_p.h
src/parserrunnable.cpp
src/parserrunnable.h
src/qjson_debug.h
src/qjson_export.h
src/qobjecthelper.cpp
src/serializer.cpp
src/qobjecthelper.h
src/serializer.h
src/serializerrunnable.cpp
src/serializerrunnable.h
tests/cmdline_tester/cmdline_tester.cpp
tests/cmdline_tester/cmdlineparser.cpp
tests/cmdline_tester/cmdlineparser.h
tests/parser/testparser.cpp
tests/qobjecthelper/person.h
tests/qobjecthelper/testqobjecthelper.cpp
tests/serializer/testserializer.cpp
The following files are licensed under GPL V2 with Bison Exception:
--------------------------------------------------------------------
/src/json_parser.cc
/src/stack.hh
/src/location.hh
/src/position.hh
/src/json_parser.hh
Copyrights:
----------
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Copyright (C) 2009 Flavio Castelli <flavio@castelli.name> 2009 Frank Osterfeld <osterfeld@kde.org>
Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
Copyright (C) 2009 Till Adam <adam@kde.org>
Copyright (C) 2009 Michael Leupold <lemma@confuego.org>
Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
Copyright (C) 2009 Frank Osterfeld <osterfeld@kde.org>
Copyright (C) 2009 Pino Toscano <pino@kde.org>
Copyright (C) 2010 Flavio Castelli <flavio@castelli.name>
GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999:
-------------------------------------------------------------
Checkout COPYING.lib
GPL V2 with Bison Exception:
----------------------------
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison.

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# QJson
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represents integer, real number, string, an ordered sequence of value, and a collection of name/value pairs.
QJson is a qt-based library that maps JSON data to QVariant objects.
JSON arrays will be mapped to QVariantList instances, while JSON's objects will be mapped to QVariantMap.
# Install
QJson requires:
- Qt 4.0 or greater
- cmake 2.6 or greater
Some possible cmake options:
- `-DCMAKE_BUILD_TYPE=DEBUG`: enables some debug output (other than making
easier to debug the code)
- `-DQJSON_BUILD_TESTS=yes` or `-DKDE4_BUILD_TESTS=yes`: builds the unit tests
- `-DCMAKE_INSTALL_PREFIX=${HOME}/testinstall`: install qjson in a custom directory
- `-DCMAKE_INCLUDE_PATH=${HOME}/testinstall/include`: include a custom include directory
- `-DCMAKE_LIBRARY_PATH=${HOME}/testinstall/lib`: include a custom library directory
- `-DLIB_DESTINATION=lib64`: if you have a 64 bit system with separate
libraries for 64 bit libraries
- `-DQJSON_VERBOSE_DEBUG_OUTPUT:BOOL=ON`: more debugging statements are
generated by the parser. It's useful only if you are trying to fix
the bison grammar.
For Unix/Linux/Mac:
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=_preferred_path_ ..
make
make install
/sbin/ldconfig #if necessary
# License
This library is licensed under the Lesser GNU General Public License version 2.1.
See the COPYING.lib file for more information.
# Resources
* [Website](http://qjson.sourceforge.net/)
* [Mailing List](https://lists.sourceforge.net/mailman/listinfo/qjson-devel)
* Project Lead/Maintainer (2008-current): [Flavio Castelli](mailto:flavio@castelli.name).

17
cmake_uninstall.cmake.in Normal file
View File

@ -0,0 +1,17 @@
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
STRING(REGEX REPLACE "\n" ";" files "${files}")
FOREACH(file ${files})
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
EXEC_PROGRAM(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
IF(NOT "${rm_retval}" STREQUAL 0)
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
ENDIF(NOT "${rm_retval}" STREQUAL 0)
ENDFOREACH(file)

1851
doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

32
doc/footer.html Normal file
View File

@ -0,0 +1,32 @@
<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:qjson-devel@lists.sourceforge.net">QJson Developers</a>
</td>
</tr>
</table>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-3214988-2");
pageTracker._trackPageview();
</script>
</body>
</html>

13
doc/header.html Normal file
View File

@ -0,0 +1,13 @@
<html>
<head>
<title>
QJson - a Qt based library for mapping JSON data to QVariant objects
</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head>
<body bgcolor="#ffffff">
<a href="http://qjson.sourceforge.net">QJson home page</a>
<hr>

87
doc/qjson.dox Normal file
View File

@ -0,0 +1,87 @@
/**
\mainpage
\section _intro Introduction
<a HREF="http://www.json.org/">JSON (JavaScript Object Notation)</a>
is a lightweight data-interchange format.
It can represents integer, real number, string, an ordered sequence of value, and
a collection of name/value pairs.
QJson is a qt-based library that maps JSON data to QVariant objects.
JSON arrays will be mapped to QVariantList instances, while JSON's objects will
be mapped to QVariantMap.
\section _usage Usage
Converting JSON's data to QVariant instance is really simple:
\code
// create a JSonDriver instance
QJson::Parser parser;
bool ok;
// json is a QString containing the data to convert
QVariant result = parser.parse (json, &ok);
\endcode
Suppose you're going to convert this JSON data:
\verbatim
{
"encoding" : "UTF-8",
"plug-ins" : [
"python",
"c++",
"ruby"
],
"indent" : { "length" : 3, "use_space" : true }
}
\endverbatim
The following code would convert the JSON data and parse it:
\code
QJson::Parser parser;
bool ok;
QVariantMap result = parser.parse (json, &ok).toMap();
if (!ok) {
qFatal("An error occured during parsing");
exit (1);
}
qDebug() << "encoding:" << result["encoding"].toString();
qDebug() << "plugins:";
foreach (QVariant plugin, result["plug-ins"].toList()) {
qDebug() << "\t-" << plugin.toString();
}
QVariantMap nestedMap = result["indent"].toMap();
qDebug() << "length:" << nestedMap["length"].toInt();
qDebug() << "use_space:" << nestedMap["use_space"].toBool();
\endcode
The output would be:
\verbatim
encoding: "UTF-8"
plugins:
- "python"
- "c++"
- "ruby"
length: 3
use_space: true
\endverbatim
The QJson::QObjectHelper class permits to serialize QObject instances into JSON. QJson::QObjectHelper also allows to
initialize a QObject using the values stored inside of a JSON object.
\section _build Build instructions
QJson build system is based on cmake. Download QJson sources, extract them, move inside the sources directory and then:
\code
mkdir build
cd build
cmake ..
make
sudo make install
\endcode
\author Flavio Castelli <flavio@castelli.name>
*/

1
include/QJson/Parser Normal file
View File

@ -0,0 +1 @@
#include "../../src/parser.h"

View File

@ -0,0 +1 @@
#include "../../src/qobjecthelper.h"

1
include/QJson/Serializer Normal file
View File

@ -0,0 +1 @@
#include "../../src/serializer.h"

3
src/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
moc_*
*.o
Makefile

61
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,61 @@
# add_custom_command (OUTPUT ${qjson_SOURCE_DIR}/lib/json_parser.cc
# PRE_BUILD
# COMMAND bison -t -o json_parser.cc -d json_parser.yy
# DEPENDS json_parser.yy
# WORKING_DIRECTORY ${qjson_SOURCE_DIR}/lib/
# )
# To regenerate json_scanner.cc use:
# flex json_scanner.yy
set(qjson_MOC_HDRS
parserrunnable.h
serializerrunnable.h
)
IF (NOT Qt5Core_FOUND)
qt4_wrap_cpp(qjson_MOC_SRCS ${qjson_MOC_HDRS})
ENDIF()
set (qjson_SRCS parser.cpp qobjecthelper.cpp json_scanner.cpp json_parser.cc parserrunnable.cpp serializer.cpp serializerrunnable.cpp)
set (qjson_HEADERS parser.h parserrunnable.h qobjecthelper.h serializer.h serializerrunnable.h qjson_export.h)
# Required to use the intree copy of FlexLexer.h
INCLUDE_DIRECTORIES(.)
add_library (qjson SHARED ${qjson_SRCS} ${qjson_MOC_SRCS} ${qjson_HEADERS})
IF (Qt5Core_FOUND)
target_link_libraries( qjson ${Qt5Core_LIBRARIES})
ELSE()
target_link_libraries( qjson ${QT_LIBRARIES})
ENDIF()
if(NOT android)
set_target_properties(qjson PROPERTIES
VERSION ${QJSON_LIB_MAJOR_VERSION}.${QJSON_LIB_MINOR_VERSION}.${QJSON_LIB_PATCH_VERSION}
SOVERSION ${QJSON_LIB_MAJOR_VERSION}
)
endif()
set_target_properties(qjson PROPERTIES
DEFINE_SYMBOL QJSON_MAKEDLL
PUBLIC_HEADER "${qjson_HEADERS}"
FRAMEWORK ${OSX_FRAMEWORK}
)
INSTALL(TARGETS qjson EXPORT qjson-export
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qjson
)
if(MSVC)
get_target_property(LOCATION qjson LOCATION_DEBUG)
string(REGEX REPLACE "\\.[^.]*$" ".pdb" LOCATION "${LOCATION}")
install(FILES ${LOCATION} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin CONFIGURATIONS Debug)
get_target_property(LOCATION qjson LOCATION_RELWITHDEBINFO)
string(REGEX REPLACE "\\.[^.]*$" ".pdb" LOCATION "${LOCATION}")
install(FILES ${LOCATION} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin CONFIGURATIONS RelWithDebInfo)
endif(MSVC)

206
src/FlexLexer.h Normal file
View File

@ -0,0 +1,206 @@
// -*-C++-*-
// FlexLexer.h -- define interfaces for lexical analyzer classes generated
// by flex
// Copyright (c) 1993 The Regents of the University of California.
// All rights reserved.
//
// This code is derived from software contributed to Berkeley by
// Kent Williams and Tom Epperly.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the University nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
// This file defines FlexLexer, an abstract class which specifies the
// external interface provided to flex C++ lexer objects, and yyFlexLexer,
// which defines a particular lexer class.
//
// If you want to create multiple lexer classes, you use the -P flag
// to rename each yyFlexLexer to some other xxFlexLexer. You then
// include <FlexLexer.h> in your other sources once per lexer class:
//
// #undef yyFlexLexer
// #define yyFlexLexer xxFlexLexer
// #include <FlexLexer.h>
//
// #undef yyFlexLexer
// #define yyFlexLexer zzFlexLexer
// #include <FlexLexer.h>
// ...
#ifndef __FLEX_LEXER_H
// Never included before - need to define base class.
#define __FLEX_LEXER_H
#include <iostream>
# ifndef FLEX_STD
# define FLEX_STD std::
# endif
extern "C++" {
struct yy_buffer_state;
typedef int yy_state_type;
class FlexLexer {
public:
virtual ~FlexLexer() { }
const char* YYText() const { return yytext; }
int YYLeng() const { return yyleng; }
virtual void
yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
virtual struct yy_buffer_state*
yy_create_buffer( FLEX_STD istream* s, int size ) = 0;
virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
virtual void yyrestart( FLEX_STD istream* s ) = 0;
virtual int yylex() = 0;
// Call yylex with new input/output sources.
int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
{
switch_streams( new_in, new_out );
return yylex();
}
// Switch to new input/output streams. A nil stream pointer
// indicates "keep the current one".
virtual void switch_streams( FLEX_STD istream* new_in = 0,
FLEX_STD ostream* new_out = 0 ) = 0;
int lineno() const { return yylineno; }
int debug() const { return yy_flex_debug; }
void set_debug( int flag ) { yy_flex_debug = flag; }
protected:
char* yytext;
int yyleng;
int yylineno; // only maintained if you use %option yylineno
int yy_flex_debug; // only has effect with -d or "%option debug"
};
}
#endif // FLEXLEXER_H
#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
// Either this is the first time through (yyFlexLexerOnce not defined),
// or this is a repeated include to define a different flavor of
// yyFlexLexer, as discussed in the flex manual.
#define yyFlexLexerOnce
extern "C++" {
class yyFlexLexer : public FlexLexer {
public:
// arg_yyin and arg_yyout default to the cin and cout, but we
// only make that assignment when initializing in yylex().
yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 );
virtual ~yyFlexLexer();
void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size );
void yy_delete_buffer( struct yy_buffer_state* b );
void yyrestart( FLEX_STD istream* s );
void yypush_buffer_state( struct yy_buffer_state* new_buffer );
void yypop_buffer_state();
virtual int yylex();
virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 );
virtual int yywrap();
protected:
virtual int LexerInput( char* buf, int max_size );
virtual void LexerOutput( const char* buf, int size );
virtual void LexerError( const char* msg );
void yyunput( int c, char* buf_ptr );
int yyinput();
void yy_load_buffer_state();
void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s );
void yy_flush_buffer( struct yy_buffer_state* b );
int yy_start_stack_ptr;
int yy_start_stack_depth;
int* yy_start_stack;
void yy_push_state( int new_state );
void yy_pop_state();
int yy_top_state();
yy_state_type yy_get_previous_state();
yy_state_type yy_try_NUL_trans( yy_state_type current_state );
int yy_get_next_buffer();
FLEX_STD istream* yyin; // input source for default LexerInput
FLEX_STD ostream* yyout; // output sink for default LexerOutput
// yy_hold_char holds the character lost when yytext is formed.
char yy_hold_char;
// Number of characters read into yy_ch_buf.
int yy_n_chars;
// Points to current character in buffer.
char* yy_c_buf_p;
int yy_init; // whether we need to initialize
int yy_start; // start state number
// Flag which is used to allow yywrap()'s to do buffer switches
// instead of setting up a fresh yyin. A bit of a hack ...
int yy_did_buffer_switch_on_eof;
size_t yy_buffer_stack_top; /**< index of top of stack. */
size_t yy_buffer_stack_max; /**< capacity of stack. */
struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */
void yyensure_buffer_stack(void);
// The following are not always needed, but may be depending
// on use of certain flex features (like REJECT or yymore()).
yy_state_type yy_last_accepting_state;
char* yy_last_accepting_cpos;
yy_state_type* yy_state_buf;
yy_state_type* yy_state_ptr;
char* yy_full_match;
int* yy_full_state;
int yy_full_lp;
int yy_lp;
int yy_looking_for_trail_begin;
int yy_more_flag;
int yy_more_len;
int yy_more_offset;
int yy_prev_more_offset;
};
}
#endif // yyFlexLexer || ! yyFlexLexerOnce

1103
src/json_parser.cc Normal file

File diff suppressed because it is too large Load Diff

300
src/json_parser.hh Normal file
View File

@ -0,0 +1,300 @@
/* A Bison parser, made by GNU Bison 2.7. */
/* Skeleton interface for Bison LALR(1) parsers in C++
Copyright (C) 2002-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/**
** \file json_parser.hh
** Define the yy::parser class.
*/
/* C++ LALR(1) parser skeleton written by Akim Demaille. */
#ifndef YY_YY_JSON_PARSER_HH_INCLUDED
# define YY_YY_JSON_PARSER_HH_INCLUDED
/* "%code requires" blocks. */
/* Line 33 of lalr1.cc */
#line 26 "json_parser.yy"
#include "parser_p.h"
#include "json_scanner.h"
#include "qjson_debug.h"
#include <QtCore/QByteArray>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <limits>
class JSonScanner;
namespace QJson {
class Parser;
}
#define YYERROR_VERBOSE 1
Q_DECLARE_METATYPE(QVector<QVariant>*)
Q_DECLARE_METATYPE(QVariantMap*)
/* Line 33 of lalr1.cc */
#line 72 "json_parser.hh"
#include <string>
#include <iostream>
#include "stack.hh"
#include "location.hh"
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 1
#endif
namespace yy {
/* Line 33 of lalr1.cc */
#line 88 "json_parser.hh"
/// A Bison parser.
class json_parser
{
public:
/// Symbol semantic values.
#ifndef YYSTYPE
typedef int semantic_type;
#else
typedef YYSTYPE semantic_type;
#endif
/// Symbol locations.
typedef location location_type;
/// Tokens.
struct token
{
/* Tokens. */
enum yytokentype {
END = 0,
CURLY_BRACKET_OPEN = 1,
CURLY_BRACKET_CLOSE = 2,
SQUARE_BRACKET_OPEN = 3,
SQUARE_BRACKET_CLOSE = 4,
COLON = 5,
COMMA = 6,
NUMBER = 7,
TRUE_VAL = 8,
FALSE_VAL = 9,
NULL_VAL = 10,
STRING = 11,
INVALID = 12
};
};
/// Token type.
typedef token::yytokentype token_type;
/// Build a parser object.
json_parser (QJson::ParserPrivate* driver_yyarg);
virtual ~json_parser ();
/// Parse.
/// \returns 0 iff parsing succeeded.
virtual int parse ();
#if YYDEBUG
/// The current debugging stream.
std::ostream& debug_stream () const;
/// Set the current debugging stream.
void set_debug_stream (std::ostream &);
/// Type for debugging levels.
typedef int debug_level_type;
/// The current debugging level.
debug_level_type debug_level () const;
/// Set the current debugging level.
void set_debug_level (debug_level_type l);
#endif
private:
/// Report a syntax error.
/// \param loc where the syntax error is found.
/// \param msg a description of the syntax error.
virtual void error (const location_type& loc, const std::string& msg);
/// Generate an error message.
/// \param state the state where the error occurred.
/// \param tok the lookahead token.
virtual std::string yysyntax_error_ (int yystate, int tok);
#if YYDEBUG
/// \brief Report a symbol value on the debug stream.
/// \param yytype The token type.
/// \param yyvaluep Its semantic value.
/// \param yylocationp Its location.
virtual void yy_symbol_value_print_ (int yytype,
const semantic_type* yyvaluep,
const location_type* yylocationp);
/// \brief Report a symbol on the debug stream.
/// \param yytype The token type.
/// \param yyvaluep Its semantic value.
/// \param yylocationp Its location.
virtual void yy_symbol_print_ (int yytype,
const semantic_type* yyvaluep,
const location_type* yylocationp);
#endif
/// State numbers.
typedef int state_type;
/// State stack type.
typedef stack<state_type> state_stack_type;
/// Semantic value stack type.
typedef stack<semantic_type> semantic_stack_type;
/// location stack type.
typedef stack<location_type> location_stack_type;
/// The state stack.
state_stack_type yystate_stack_;
/// The semantic value stack.
semantic_stack_type yysemantic_stack_;
/// The location stack.
location_stack_type yylocation_stack_;
/// Whether the given \c yypact_ value indicates a defaulted state.
/// \param yyvalue the value to check
static bool yy_pact_value_is_default_ (int yyvalue);
/// Whether the given \c yytable_ value indicates a syntax error.
/// \param yyvalue the value to check
static bool yy_table_value_is_error_ (int yyvalue);
/// Internal symbol numbers.
typedef unsigned char token_number_type;
/* Tables. */
/// For a state, the index in \a yytable_ of its portion.
static const signed char yypact_[];
static const signed char yypact_ninf_;
/// For a state, default reduction number.
/// Unless\a yytable_ specifies something else to do.
/// Zero means the default is an error.
static const unsigned char yydefact_[];
static const signed char yypgoto_[];
static const signed char yydefgoto_[];
/// What to do in a state.
/// \a yytable_[yypact_[s]]: what to do in state \a s.
/// - if positive, shift that token.
/// - if negative, reduce the rule which number is the opposite.
/// - if zero, do what YYDEFACT says.
static const unsigned char yytable_[];
static const signed char yytable_ninf_;
static const signed char yycheck_[];
/// For a state, its accessing symbol.
static const unsigned char yystos_[];
/// For a rule, its LHS.
static const unsigned char yyr1_[];
/// For a rule, its RHS length.
static const unsigned char yyr2_[];
/// Convert the symbol name \a n to a form suitable for a diagnostic.
static std::string yytnamerr_ (const char *n);
/// For a symbol, its name in clear.
static const char* const yytname_[];
#if YYDEBUG
/// A type to store symbol numbers and -1.
typedef signed char rhs_number_type;
/// A `-1'-separated list of the rules' RHS.
static const rhs_number_type yyrhs_[];
/// For each rule, the index of the first RHS symbol in \a yyrhs_.
static const unsigned char yyprhs_[];
/// For each rule, its source line number.
static const unsigned char yyrline_[];
/// For each scanner token number, its symbol number.
static const unsigned short int yytoken_number_[];
/// Report on the debug stream that the rule \a r is going to be reduced.
virtual void yy_reduce_print_ (int r);
/// Print the state stack on the debug stream.
virtual void yystack_print_ ();
/* Debugging. */
int yydebug_;
std::ostream* yycdebug_;
#endif
/// Convert a scanner token number \a t to a symbol number.
token_number_type yytranslate_ (int t);
/// \brief Reclaim the memory associated to a symbol.
/// \param yymsg Why this token is reclaimed.
/// If null, do not display the symbol, just free it.
/// \param yytype The symbol type.
/// \param yyvaluep Its semantic value.
/// \param yylocationp Its location.
inline void yydestruct_ (const char* yymsg,
int yytype,
semantic_type* yyvaluep,
location_type* yylocationp);
/// Pop \a n symbols the three stacks.
inline void yypop_ (unsigned int n = 1);
/* Constants. */
static const int yyeof_;
/* LAST_ -- Last index in TABLE_. */
static const int yylast_;
static const int yynnts_;
static const int yyempty_;
static const int yyfinal_;
static const int yyterror_;
static const int yyerrcode_;
static const int yyntokens_;
static const unsigned int yyuser_token_number_max_;
static const token_number_type yyundef_token_;
/* User arguments. */
QJson::ParserPrivate* driver;
};
} // yy
/* Line 33 of lalr1.cc */
#line 297 "json_parser.hh"
#endif /* !YY_YY_JSON_PARSER_HH_INCLUDED */

162
src/json_parser.yy Normal file
View File

@ -0,0 +1,162 @@
/* This file is part of QJSon
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
%skeleton "lalr1.cc"
%defines
%define "parser_class_name" "json_parser"
%code requires{
#include "parser_p.h"
#include "json_scanner.h"
#include "qjson_debug.h"
#include <QtCore/QByteArray>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <limits>
class JSonScanner;
namespace QJson {
class Parser;
}
#define YYERROR_VERBOSE 1
Q_DECLARE_METATYPE(QVector<QVariant>*)
Q_DECLARE_METATYPE(QVariantMap*)
}
%parse-param { QJson::ParserPrivate* driver }
%lex-param { QJson::ParserPrivate* driver }
%locations
%debug
%error-verbose
%token END 0 "end of file"
%token CURLY_BRACKET_OPEN 1 "{"
%token CURLY_BRACKET_CLOSE 2 "}"
%token SQUARE_BRACKET_OPEN 3 "["
%token SQUARE_BRACKET_CLOSE 4 "]"
%token COLON 5 ":"
%token COMMA 6 ","
%token NUMBER 7 "number"
%token TRUE_VAL 8 "true"
%token FALSE_VAL 9 "false"
%token NULL_VAL 10 "null"
%token STRING 11 "string"
%token INVALID 12 "invalid"
// define the initial token
%start start
%%
// grammar rules
start: data {
driver->m_result = $1;
qjsonDebug() << "json_parser - parsing finished";
};
data: value { $$ = $1; }
| error
{
qCritical()<< "json_parser - syntax error found, "
<< "forcing abort, Line" << @$.begin.line << "Column" << @$.begin.column;
YYABORT;
}
| END;
object: CURLY_BRACKET_OPEN CURLY_BRACKET_CLOSE {
$$ = QVariant(QVariantMap());
}
| CURLY_BRACKET_OPEN members CURLY_BRACKET_CLOSE {
QVariantMap* map = $2.value<QVariantMap*>();
$$ = QVariant(*map);
delete map;
};
members: STRING COLON value {
QVariantMap* pair = new QVariantMap();
pair->insert($1.toString(), $3);
$$.setValue<QVariantMap* >(pair);
}
| members COMMA STRING COLON value {
$$.value<QVariantMap*>()->insert($3.toString(), $5);
};
array: SQUARE_BRACKET_OPEN SQUARE_BRACKET_CLOSE {
$$ = QVariant(QVariantList());
}
| SQUARE_BRACKET_OPEN values SQUARE_BRACKET_CLOSE {
QVector<QVariant>* list = $2.value<QVector<QVariant>* >();
$$ = QVariant(list->toList());
delete list;
};
values: value {
QVector<QVariant>* list = new QVector<QVariant>(1);
list->replace(0, $1);
$$.setValue(list);
}
| values COMMA value {
$$.value<QVector<QVariant>* >()->append($3);
};
value: STRING
| NUMBER
| TRUE_VAL
| FALSE_VAL
| NULL_VAL
| object
| array;
%%
int yy::yylex(YYSTYPE *yylval, yy::location *yylloc, QJson::ParserPrivate* driver)
{
JSonScanner* scanner = driver->m_scanner;
yylval->clear();
int ret = scanner->yylex(yylval, yylloc);
qjsonDebug() << "json_parser::yylex - calling scanner yylval==|"
<< yylval->toByteArray() << "|, ret==|" << QString::number(ret) << "|";
return ret;
}
void yy::json_parser::error (const yy::location& yyloc, const std::string& error)
{
/*qjsonDebug() << yyloc.begin.line;
qjsonDebug() << yyloc.begin.column;
qjsonDebug() << yyloc.end.line;
qjsonDebug() << yyloc.end.column;*/
qjsonDebug() << "json_parser::error [line" << yyloc.end.line << "] -" << error.c_str() ;
driver->setError(QString::fromLatin1(error.c_str()), yyloc.end.line);
}

4513
src/json_scanner.cc Normal file

File diff suppressed because it is too large Load Diff

82
src/json_scanner.cpp Normal file
View File

@ -0,0 +1,82 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "json_scanner.cc"
#include "qjson_debug.h"
#include "json_scanner.h"
#include "json_parser.hh"
#include <ctype.h>
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
#include <cassert>
JSonScanner::JSonScanner(QIODevice* io)
: m_allowSpecialNumbers(false),
m_io (io),
m_criticalError(false),
m_C_locale(QLocale::C)
{
}
JSonScanner::~JSonScanner()
{
}
void JSonScanner::allowSpecialNumbers(bool allow) {
m_allowSpecialNumbers = allow;
}
int JSonScanner::yylex(YYSTYPE* yylval, yy::location *yylloc) {
m_yylval = yylval;
m_yylloc = yylloc;
m_yylloc->step();
int result = yylex();
if (m_criticalError) {
return -1;
}
return result;
}
int JSonScanner::LexerInput(char* buf, int max_size) {
if (!m_io->isOpen()) {
qCritical() << "JSonScanner::yylex - io device is not open";
m_criticalError = true;
return 0;
}
int readBytes = m_io->read(buf, max_size);
if(readBytes < 0) {
qCritical() << "JSonScanner::yylex - error while reading from io device";
m_criticalError = true;
return 0;
}
return readBytes;
}

66
src/json_scanner.h Normal file
View File

@ -0,0 +1,66 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _JSON_SCANNER
#define _JSON_SCANNER
#include <QtCore/QIODevice>
#include <QtCore/QVariant>
#include <QtCore/QLocale>
#define YYSTYPE QVariant
// Only include FlexLexer.h if it hasn't been already included
#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif
#include "parser_p.h"
namespace yy {
class location;
int yylex(YYSTYPE *yylval, yy::location *yylloc, QJson::ParserPrivate* driver);
}
class JSonScanner : public yyFlexLexer
{
public:
explicit JSonScanner(QIODevice* io);
~JSonScanner();
void allowSpecialNumbers(bool allow);
int yylex(YYSTYPE* yylval, yy::location *yylloc);
int yylex();
int LexerInput(char* buf, int max_size);
protected:
bool m_allowSpecialNumbers;
QIODevice* m_io;
YYSTYPE* m_yylval;
yy::location* m_yylloc;
bool m_criticalError;
QString m_currentString;
QLocale m_C_locale;
};
#endif

254
src/json_scanner.yy Normal file
View File

@ -0,0 +1,254 @@
/* This file is part of QJson
*
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110yy::json_parser::token::INVALID301, USA.
*/
/* Flex output settings */
%option 8bit c++ full warn
%option noyywrap nounistd
%option noinput nounput noyy_push_state noyy_pop_state noyy_top_state noyy_scan_buffer noyy_scan_bytes noyy_scan_string noyyget_extra noyyset_extra noyyget_leng noyyget_text noyyget_lineno noyyset_lineno noyyget_in noyyset_in noyyget_out noyyset_out noyyget_lval noyyset_lval noyyget_lloc noyyset_lloc noyyget_debug noyyset_debug
%option yyclass="JSonScanner"
%option outfile="json_scanner.cc"
%{
#include "json_scanner.h"
#include "json_parser.hh"
#if defined(_WIN32) && !defined(__MINGW32__)
#define strtoll _strtoi64
#define strtoull _strtoui64
#endif
#define YY_USER_INIT if(m_allowSpecialNumbers) { \
BEGIN(ALLOW_SPECIAL_NUMBERS); \
}
%}
/* Exclusive subscanners for strings and escaped hex sequences */
%x QUOTMARK_OPEN HEX_OPEN
/* Extra-JSON rules active iff m_allowSpecialNumbers is true */
%s ALLOW_SPECIAL_NUMBERS
%%
/* Whitespace */
[\v\f\t ]+ {
m_yylloc->columns(yyleng);
}
[\r\n]+ {
m_yylloc->lines(yyleng);
}
/* Special values */
true {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(true);
return yy::json_parser::token::TRUE_VAL;
}
false {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(false);
return yy::json_parser::token::FALSE_VAL;
}
null {
m_yylloc->columns(yyleng);
*m_yylval = QVariant();
return yy::json_parser::token::NULL_VAL;
}
/* Numbers */
[0-9] |
[1-9][0-9]+ {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(strtoull(yytext, NULL, 10));
if (errno == ERANGE) {
qCritical() << "Number is out of range: " << yytext;
return yy::json_parser::token::INVALID;
}
return yy::json_parser::token::NUMBER;
}
-[0-9] |
-[1-9][0-9]+ {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(strtoll(yytext, NULL, 10));
if (errno == ERANGE) {
qCritical() << "Number is out of range: " << yytext;
return yy::json_parser::token::INVALID;
}
return yy::json_parser::token::NUMBER;
}
-?(([0-9])|([1-9][0-9]+))(\.[0-9]+)?([Ee][+\-]?[0-9]+)? {
m_yylloc->columns(yyleng);
bool ok;
*m_yylval = QVariant(m_C_locale.toDouble(QLatin1String(yytext),&ok));
if (!ok) {
qCritical() << "Number is out of range: " << yytext;
return yy::json_parser::token::INVALID;
}
return yy::json_parser::token::NUMBER;
}
/* Strings */
\" {
m_yylloc->columns(yyleng);
BEGIN(QUOTMARK_OPEN);
}
<QUOTMARK_OPEN>{
\\\" {
m_currentString.append(QLatin1String("\""));
}
\\\\ {
m_currentString.append(QLatin1String("\\"));
}
\\\/ {
m_currentString.append(QLatin1String("/"));
}
\\b {
m_currentString.append(QLatin1String("\b"));
}
\\f {
m_currentString.append(QLatin1String("\f"));
}
\\n {
m_currentString.append(QLatin1String("\n"));
}
\\r {
m_currentString.append(QLatin1String("\r"));
}
\\t {
m_currentString.append(QLatin1String("\t"));
}
\\u {
BEGIN(HEX_OPEN);
}
[^\"\\]+ {
m_currentString.append(QString::fromUtf8(yytext));
}
\\ {
// ignore
}
\" {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(m_currentString);
m_currentString.clear();
BEGIN(INITIAL);
return yy::json_parser::token::STRING;
}
}
<HEX_OPEN>{
[0-9A-Fa-f]{4} {
QString hexDigits = QString::fromUtf8(yytext, yyleng);
bool ok;
ushort hexDigit1 = hexDigits.left(2).toShort(&ok, 16);
ushort hexDigit2 = hexDigits.right(2).toShort(&ok, 16);
m_currentString.append(QChar(hexDigit2, hexDigit1));
BEGIN(QUOTMARK_OPEN);
}
.|\n {
qCritical() << "Invalid hex string";
m_yylloc->columns(yyleng);
*m_yylval = QVariant(QLatin1String(""));
BEGIN(QUOTMARK_OPEN);
return yy::json_parser::token::INVALID;
}
}
/* "Compound type" related tokens */
: {
m_yylloc->columns(yyleng);
return yy::json_parser::token::COLON;
}
, {
m_yylloc->columns(yyleng);
return yy::json_parser::token::COMMA;
}
\[ {
m_yylloc->columns(yyleng);
return yy::json_parser::token::SQUARE_BRACKET_OPEN;
}
\] {
m_yylloc->columns(yyleng);
return yy::json_parser::token::SQUARE_BRACKET_CLOSE;
}
\{ {
m_yylloc->columns(yyleng);
return yy::json_parser::token::CURLY_BRACKET_OPEN;
}
\} {
m_yylloc->columns(yyleng);
return yy::json_parser::token::CURLY_BRACKET_CLOSE;
}
/* Extra-JSON numbers */
<ALLOW_SPECIAL_NUMBERS>{
(?i:nan) {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(std::numeric_limits<double>::quiet_NaN());
return yy::json_parser::token::NUMBER;
}
[Ii]nfinity {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(std::numeric_limits<double>::infinity());
return yy::json_parser::token::NUMBER;
}
-[Ii]nfinity {
m_yylloc->columns(yyleng);
*m_yylval = QVariant(-std::numeric_limits<double>::infinity());
return yy::json_parser::token::NUMBER;
}
}
/* If all else fails */
. {
m_yylloc->columns(yyleng);
return yy::json_parser::token::INVALID;
}
<<EOF>> return yy::json_parser::token::END;

181
src/location.hh Normal file
View File

@ -0,0 +1,181 @@
/* A Bison parser, made by GNU Bison 2.7. */
/* Locations for Bison parsers in C++
Copyright (C) 2002-2007, 2009-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/**
** \file location.hh
** Define the yy::location class.
*/
#ifndef YY_YY_LOCATION_HH_INCLUDED
# define YY_YY_LOCATION_HH_INCLUDED
# include "position.hh"
namespace yy {
/* Line 166 of location.cc */
#line 47 "location.hh"
/// Abstract a location.
class location
{
public:
/// Construct a location from \a b to \a e.
location (const position& b, const position& e)
: begin (b)
, end (e)
{
}
/// Construct a 0-width location in \a p.
explicit location (const position& p = position ())
: begin (p)
, end (p)
{
}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (std::string* f,
unsigned int l = 1u,
unsigned int c = 1u)
: begin (f, l, c)
, end (f, l, c)
{
}
/// Initialization.
void initialize (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
begin.initialize (f, l, c);
end = begin;
}
/** \name Line and Column related manipulators
** \{ */
public:
/// Reset initial location to final location.
void step ()
{
begin = end;
}
/// Extend the current location to the COUNT next columns.
void columns (unsigned int count = 1)
{
end += count;
}
/// Extend the current location to the COUNT next lines.
void lines (unsigned int count = 1)
{
end.lines (count);
}
/** \} */
public:
/// Beginning of the located region.
position begin;
/// End of the located region.
position end;
};
/// Join two location objects to create a location.
inline const location operator+ (const location& begin, const location& end)
{
location res = begin;
res.end = end.end;
return res;
}
/// Add two location objects.
inline const location operator+ (const location& begin, unsigned int width)
{
location res = begin;
res.columns (width);
return res;
}
/// Add and assign a location.
inline location& operator+= (location& res, unsigned int width)
{
res.columns (width);
return res;
}
/// Compare two location objects.
inline bool
operator== (const location& loc1, const location& loc2)
{
return loc1.begin == loc2.begin && loc1.end == loc2.end;
}
/// Compare two location objects.
inline bool
operator!= (const location& loc1, const location& loc2)
{
return !(loc1 == loc2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param loc a reference to the location to redirect
**
** Avoid duplicate information.
*/
template <typename YYChar>
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
{
position last = loc.end - 1;
ostr << loc.begin;
if (last.filename
&& (!loc.begin.filename
|| *loc.begin.filename != *last.filename))
ostr << '-' << last;
else if (loc.begin.line != last.line)
ostr << '-' << last.line << '.' << last.column;
else if (loc.begin.column != last.column)
ostr << '-' << last.column;
return ostr;
}
} // yy
/* Line 296 of location.cc */
#line 180 "location.hh"
#endif /* !YY_YY_LOCATION_HH_INCLUDED */

141
src/parser.cpp Normal file
View File

@ -0,0 +1,141 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "parser.h"
#include "parser_p.h"
#include "json_parser.hh"
#include "json_scanner.h"
#include <QtCore/QBuffer>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QDebug>
using namespace QJson;
ParserPrivate::ParserPrivate() :
m_scanner(0)
{
m_specialNumbersAllowed = false;
reset();
}
ParserPrivate::~ParserPrivate()
{
if (m_scanner)
delete m_scanner;
}
void ParserPrivate::setError(QString errorMsg, int errorLine) {
m_error = true;
m_errorMsg = errorMsg;
m_errorLine = errorLine;
}
void ParserPrivate::reset()
{
m_error = false;
m_errorLine = 0;
m_errorMsg.clear();
if (m_scanner) {
delete m_scanner;
m_scanner = 0;
}
}
Parser::Parser() :
d(new ParserPrivate)
{
}
Parser::~Parser()
{
delete d;
}
QVariant Parser::parse (QIODevice* io, bool* ok)
{
d->reset();
if (!io->isOpen()) {
if (!io->open(QIODevice::ReadOnly)) {
if (ok != 0)
*ok = false;
qCritical ("Error opening device");
return QVariant();
}
}
if (!io->isReadable()) {
if (ok != 0)
*ok = false;
qCritical ("Device is not readable");
io->close();
return QVariant();
}
if (io->atEnd()) {
if (ok != 0)
*ok = false;
d->setError(QLatin1String("No data"), 0);
io->close();
return QVariant();
}
d->m_scanner = new JSonScanner (io);
d->m_scanner->allowSpecialNumbers(d->m_specialNumbersAllowed);
yy::json_parser parser(d);
parser.parse();
delete d->m_scanner;
d->m_scanner = 0;
if (ok != 0)
*ok = !d->m_error;
io->close();
return d->m_result;
}
QVariant Parser::parse(const QByteArray& jsonString, bool* ok) {
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
buffer.write(jsonString);
buffer.seek(0);
return parse (&buffer, ok);
}
QString Parser::errorString() const
{
return d->m_errorMsg;
}
int Parser::errorLine() const
{
return d->m_errorLine;
}
void QJson::Parser::allowSpecialNumbers(bool allowSpecialNumbers) {
d->m_specialNumbersAllowed = allowSpecialNumbers;
}
bool Parser::specialNumbersAllowed() const {
return d->m_specialNumbersAllowed;
}

99
src/parser.h Normal file
View File

@ -0,0 +1,99 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef QJSON_PARSER_H
#define QJSON_PARSER_H
#include "qjson_export.h"
QT_BEGIN_NAMESPACE
class QIODevice;
class QVariant;
QT_END_NAMESPACE
/**
* Namespace used by QJson
*/
namespace QJson {
class ParserPrivate;
/**
* @brief Main class used to convert JSON data to QVariant objects
*/
class QJSON_EXPORT Parser
{
public:
Parser();
~Parser();
/**
* Read JSON string from the I/O Device and converts it to a QVariant object
* @param io Input output device
* @param ok if a conversion error occurs, *ok is set to false; otherwise *ok is set to true.
* @returns a QVariant object generated from the JSON string
*/
QVariant parse(QIODevice* io, bool* ok = 0);
/**
* This is a method provided for convenience.
* @param jsonData data containing the JSON object representation
* @param ok if a conversion error occurs, *ok is set to false; otherwise *ok is set to true.
* @returns a QVariant object generated from the JSON string
* @sa errorString
* @sa errorLine
*/
QVariant parse(const QByteArray& jsonData, bool* ok = 0);
/**
* This method returns the error message
* @returns a QString object containing the error message of the last parse operation
* @sa errorLine
*/
QString errorString() const;
/**
* This method returns line number where the error occurred
* @returns the line number where the error occurred
* @sa errorString
*/
int errorLine() const;
/**
* Sets whether special numbers (Infinity, -Infinity, NaN) are allowed as an extension to
* the standard
* @param allowSpecialNumbers new value of whether special numbers are allowed
* @sa specialNumbersAllowed
*/
void allowSpecialNumbers(bool allowSpecialNumbers);
/**
* @returns whether special numbers (Infinity, -Infinity, NaN) are allowed
* @sa allowSpecialNumbers
*/
bool specialNumbersAllowed() const;
private:
Q_DISABLE_COPY(Parser)
ParserPrivate* const d;
};
}
#endif // QJSON_PARSER_H

57
src/parser_p.h Normal file
View File

@ -0,0 +1,57 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
* Copyright (C) 2009 Michael Leupold <lemma@confuego.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef QJSON_PARSER_P_H
#define QJSON_PARSER_P_H
#include "parser.h"
#include <QtCore/QString>
#include <QtCore/QVariant>
class JSonScanner;
namespace yy {
class json_parser;
}
namespace QJson {
class ParserPrivate
{
public:
ParserPrivate();
~ParserPrivate();
void reset();
void setError(QString errorMsg, int line);
JSonScanner* m_scanner;
bool m_error;
int m_errorLine;
QString m_errorMsg;
QVariant m_result;
bool m_specialNumbersAllowed;
};
}
#endif // QJSON_PARSER_H

68
src/parserrunnable.cpp Normal file
View File

@ -0,0 +1,68 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "parserrunnable.h"
#include "parser.h"
#include <QtCore/QDebug>
#include <QtCore/QVariant>
using namespace QJson;
class QJson::ParserRunnable::Private
{
public:
QByteArray m_data;
};
ParserRunnable::ParserRunnable(QObject* parent)
: QObject(parent),
QRunnable(),
d(new Private)
{
qRegisterMetaType<QVariant>("QVariant");
}
ParserRunnable::~ParserRunnable()
{
delete d;
}
void ParserRunnable::setData( const QByteArray& data ) {
d->m_data = data;
}
void ParserRunnable::run()
{
qDebug() << Q_FUNC_INFO;
bool ok;
Parser parser;
QVariant result = parser.parse (d->m_data, &ok);
if (ok) {
qDebug() << "successfully converted json item to QVariant object";
emit parsingFinished(result, true, QString());
} else {
const QString errorText = tr("An error occurred while parsing json: %1").arg(parser.errorString());
qCritical() << errorText;
emit parsingFinished(QVariant(), false, errorText);
}
}

64
src/parserrunnable.h Normal file
View File

@ -0,0 +1,64 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef PARSERRUNNABLE_H
#define PARSERRUNNABLE_H
#include "qjson_export.h"
#include <QtCore/QObject>
#include <QtCore/QRunnable>
QT_BEGIN_NAMESPACE
class QVariant;
QT_END_NAMESPACE
namespace QJson {
/**
* @brief Convenience class for converting JSON data to QVariant objects using a dedicated thread
*/
class QJSON_EXPORT ParserRunnable : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit ParserRunnable(QObject* parent = 0);
~ParserRunnable();
void setData( const QByteArray& data );
void run();
Q_SIGNALS:
/**
* This signal is emitted when the parsing process has been completed
* @param json contains the result of the parsing
* @param ok if a parsing error occurs ok is set to false, otherwise it's set to true.
* @param error_msg contains a string explaining the failure reason
**/
void parsingFinished(const QVariant& json, bool ok, const QString& error_msg);
private:
Q_DISABLE_COPY(ParserRunnable)
class Private;
Private* const d;
};
}
#endif // PARSERRUNNABLE_H

172
src/position.hh Normal file
View File

@ -0,0 +1,172 @@
/* A Bison parser, made by GNU Bison 2.7. */
/* Positions for Bison parsers in C++
Copyright (C) 2002-2007, 2009-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/**
** \file position.hh
** Define the yy::position class.
*/
#ifndef YY_YY_POSITION_HH_INCLUDED
# define YY_YY_POSITION_HH_INCLUDED
# include <algorithm> // std::max
# include <iostream>
# include <string>
# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULL nullptr
# else
# define YY_NULL 0
# endif
# endif
namespace yy {
/* Line 36 of location.cc */
#line 57 "position.hh"
/// Abstract a position.
class position
{
public:
/// Construct a position.
explicit position (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
: filename (f)
, line (l)
, column (c)
{
}
/// Initialization.
void initialize (std::string* fn = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
filename = fn;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines (int count = 1)
{
column = 1u;
line += count;
}
/// (column related) Advance to the COUNT next columns.
void columns (int count = 1)
{
column = std::max (1u, column + count);
}
/** \} */
/// File name to which this position refers.
std::string* filename;
/// Current line number.
unsigned int line;
/// Current column number.
unsigned int column;
};
/// Add and assign a position.
inline position&
operator+= (position& res, const int width)
{
res.columns (width);
return res;
}
/// Add two position objects.
inline const position
operator+ (const position& begin, const int width)
{
position res = begin;
return res += width;
}
/// Add and assign a position.
inline position&
operator-= (position& res, const int width)
{
return res += -width;
}
/// Add two position objects.
inline const position
operator- (const position& begin, const int width)
{
return begin + -width;
}
/// Compare two position objects.
inline bool
operator== (const position& pos1, const position& pos2)
{
return (pos1.line == pos2.line
&& pos1.column == pos2.column
&& (pos1.filename == pos2.filename
|| (pos1.filename && pos2.filename
&& *pos1.filename == *pos2.filename)));
}
/// Compare two position objects.
inline bool
operator!= (const position& pos1, const position& pos2)
{
return !(pos1 == pos2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param pos a reference to the position to redirect
*/
template <typename YYChar>
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const position& pos)
{
if (pos.filename)
ostr << *pos.filename << ':';
return ostr << pos.line << '.' << pos.column;
}
} // yy
/* Line 148 of location.cc */
#line 172 "position.hh"
#endif /* !YY_YY_POSITION_HH_INCLUDED */

34
src/qjson_debug.h Normal file
View File

@ -0,0 +1,34 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Michael Leupold <lemma@confuego.org>
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef QJSON_DEBUG_H
#define QJSON_DEBUG_H
#include <QtCore/QDebug>
// define qjsonDebug()
#ifdef QJSON_VERBOSE_DEBUG_OUTPUT
inline QDebug qjsonDebug() { return QDebug(QtDebugMsg); }
#else
#define qjsonDebug() if(false) QDebug(QtDebugMsg)
#endif
#endif

35
src/qjson_export.h Normal file
View File

@ -0,0 +1,35 @@
/* This file is part of the KDE project
Copyright (C) 2009 Pino Toscano <pino@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef QJSON_EXPORT_H
#define QJSON_EXPORT_H
#include <QtCore/qglobal.h>
#ifndef QJSON_EXPORT
# if defined(QJSON_MAKEDLL)
/* We are building this library */
# define QJSON_EXPORT Q_DECL_EXPORT
# else
/* We are using this library */
# define QJSON_EXPORT Q_DECL_IMPORT
# endif
#endif
#endif

85
src/qobjecthelper.cpp Normal file
View File

@ -0,0 +1,85 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Till Adam <adam@kde.org>
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "qobjecthelper.h"
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
#include <QtCore/QObject>
using namespace QJson;
class QObjectHelper::QObjectHelperPrivate {
};
QObjectHelper::QObjectHelper()
: d (new QObjectHelperPrivate)
{
}
QObjectHelper::~QObjectHelper()
{
delete d;
}
QVariantMap QObjectHelper::qobject2qvariant( const QObject* object,
const QStringList& ignoredProperties)
{
QVariantMap result;
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i=0; i<count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
if (ignoredProperties.contains(QLatin1String(name)) || (!metaproperty.isReadable()))
continue;
QVariant value = object->property(name);
result[QLatin1String(name)] = value;
}
return result;
}
void QObjectHelper::qvariant2qobject(const QVariantMap& variant, QObject* object)
{
const QMetaObject *metaobject = object->metaObject();
QVariantMap::const_iterator iter;
for (iter = variant.constBegin(); iter != variant.constEnd(); ++iter) {
int pIdx = metaobject->indexOfProperty( iter.key().toLatin1() );
if ( pIdx < 0 ) {
continue;
}
QMetaProperty metaproperty = metaobject->property( pIdx );
QVariant::Type type = metaproperty.type();
QVariant v( iter.value() );
if ( v.canConvert( type ) ) {
v.convert( type );
metaproperty.write( object, v );
} else if (QString(QLatin1String("QVariant")).compare(QLatin1String(metaproperty.typeName())) == 0) {
metaproperty.write( object, v );
}
}
}

147
src/qobjecthelper.h Normal file
View File

@ -0,0 +1,147 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef QOBJECTHELPER_H
#define QOBJECTHELPER_H
#include "qjson_export.h"
#include <QtCore/QLatin1String>
#include <QtCore/QStringList>
#include <QtCore/QVariantMap>
QT_BEGIN_NAMESPACE
class QObject;
QT_END_NAMESPACE
namespace QJson {
/**
* @brief Class used to convert QObject into QVariant and vivce-versa.
* During these operations only the class attributes defined as properties will
* be considered.
* Properties marked as 'non-stored' will be ignored.
*
* Suppose the declaration of the Person class looks like this:
* \code
* class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int phoneNumber READ phoneNumber WRITE setPhoneNumber)
Q_PROPERTY(Gender gender READ gender WRITE setGender)
Q_PROPERTY(QDate dob READ dob WRITE setDob)
Q_ENUMS(Gender)
public:
Person(QObject* parent = 0);
~Person();
QString name() const;
void setName(const QString& name);
int phoneNumber() const;
void setPhoneNumber(const int phoneNumber);
enum Gender {Male, Female};
void setGender(Gender gender);
Gender gender() const;
QDate dob() const;
void setDob(const QDate& dob);
private:
QString m_name;
int m_phoneNumber;
Gender m_gender;
QDate m_dob;
};
\endcode
The following code will serialize an instance of Person to JSON :
\code
Person person;
person.setName("Flavio");
person.setPhoneNumber(123456);
person.setGender(Person::Male);
person.setDob(QDate(1982, 7, 12));
QVariantMap variant = QObjectHelper::qobject2qvariant(&person);
Serializer serializer;
qDebug() << serializer.serialize( variant);
\endcode
The generated output will be:
\code
{ "dob" : "1982-07-12", "gender" : 0, "name" : "Flavio", "phoneNumber" : 123456 }
\endcode
It's also possible to initialize a QObject using the values stored inside of
a QVariantMap.
Suppose you have the following JSON data stored into a QString:
\code
{ "dob" : "1982-07-12", "gender" : 0, "name" : "Flavio", "phoneNumber" : 123456 }
\endcode
The following code will initialize an already allocated instance of Person
using the JSON values:
\code
Parser parser;
QVariant variant = parser.parse(json);
Person person;
QObjectHelper::qvariant2qobject(variant.toMap(), &person);
\endcode
\sa Parser
\sa Serializer
*/
class QJSON_EXPORT QObjectHelper {
public:
QObjectHelper();
~QObjectHelper();
/**
* This method converts a QObject instance into a QVariantMap.
*
* @param object The QObject instance to be converted.
* @param ignoredProperties Properties that won't be converted.
*/
static QVariantMap qobject2qvariant( const QObject* object,
const QStringList& ignoredProperties = QStringList(QString(QLatin1String("objectName"))));
/**
* This method converts a QVariantMap instance into a QObject
*
* @param variant Attributes to assign to the object.
* @param object The QObject instance to update.
*/
static void qvariant2qobject(const QVariantMap& variant, QObject* object);
private:
Q_DISABLE_COPY(QObjectHelper)
class QObjectHelperPrivate;
QObjectHelperPrivate* const d;
};
}
#endif // QOBJECTHELPER_H

444
src/serializer.cpp Normal file
View File

@ -0,0 +1,444 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Till Adam <adam@kde.org>
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "serializer.h"
#include <QtCore/QDataStream>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <cmath>
#ifdef Q_OS_SOLARIS
# ifndef isinf
# include <ieeefp.h>
# define isinf(x) (!finite((x)) && (x)==(x))
# endif
#endif
#ifdef _MSC_VER // using MSVC compiler
#include <float.h>
#endif
using namespace QJson;
class Serializer::SerializerPrivate {
public:
SerializerPrivate() :
specialNumbersAllowed(false),
indentMode(QJson::IndentNone),
doublePrecision(6) {
errorMessage.clear();
}
QString errorMessage;
bool specialNumbersAllowed;
IndentMode indentMode;
int doublePrecision;
QByteArray buildIndent(int spaces);
QByteArray serialize( const QVariant &v, bool *ok, int indentLevel = 0);
QString sanitizeString( QString str );
QByteArray join( const QList<QByteArray>& list, const QByteArray& sep );
};
QByteArray Serializer::SerializerPrivate::join( const QList<QByteArray>& list, const QByteArray& sep ) {
QByteArray res;
Q_FOREACH( const QByteArray& i, list ) {
if ( !res.isEmpty() )
res += sep;
res += i;
}
return res;
}
QByteArray Serializer::SerializerPrivate::serialize( const QVariant &v, bool *ok, int indentLevel)
{
QByteArray str;
if ( ! v.isValid() ) { // invalid or null?
str = "null";
} else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){ // an array or a stringlist?
const QVariantList list = v.toList();
QList<QByteArray> values;
Q_FOREACH( const QVariant& var, list )
{
QByteArray serializedValue;
serializedValue = serialize( var, ok, indentLevel+1);
if ( !*ok ) {
break;
}
switch(indentMode) {
case QJson::IndentFull :
case QJson::IndentMedium :
case QJson::IndentMinimum :
values << serializedValue;
break;
case QJson::IndentCompact :
case QJson::IndentNone :
default:
values << serializedValue.trimmed();
break;
}
}
if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull ) {
QByteArray indent = buildIndent(indentLevel);
str = indent + "[\n" + join( values, ",\n" ) + "\n" + indent + "]";
}
else if (indentMode == QJson::IndentMinimum) {
QByteArray indent = buildIndent(indentLevel);
str = indent + "[\n" + join( values, ",\n" ) + "\n" + indent + "]";
}
else if (indentMode == QJson::IndentCompact) {
str = "[" + join( values, "," ) + "]";
}
else {
str = "[ " + join( values, ", " ) + " ]";
}
} else if ( v.type() == QVariant::Map ) { // variant is a map?
const QVariantMap vmap = v.toMap();
QMapIterator<QString, QVariant> it( vmap );
if (indentMode == QJson::IndentMinimum) {
QByteArray indent = buildIndent(indentLevel);
str = indent + "{ ";
}
else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel);
QByteArray nextindent = buildIndent(indentLevel + 1);
str = indent + "{\n" + nextindent;
}
else if (indentMode == QJson::IndentCompact) {
str = "{";
}
else {
str = "{ ";
}
QList<QByteArray> pairs;
while ( it.hasNext() ) {
it.next();
indentLevel++;
QByteArray serializedValue = serialize( it.value(), ok, indentLevel);
indentLevel--;
if ( !*ok ) {
break;
}
QByteArray key = sanitizeString( it.key() ).toUtf8();
QByteArray value = serializedValue.trimmed();
if (indentMode == QJson::IndentCompact) {
pairs << key + ":" + value;
} else {
pairs << key + " : " + value;
}
}
if (indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel + 1);
str += join( pairs, ",\n" + indent);
}
else if (indentMode == QJson::IndentCompact) {
str += join( pairs, "," );
}
else {
str += join( pairs, ", " );
}
if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel);
str += "\n" + indent + "}";
}
else if (indentMode == QJson::IndentCompact) {
str += "}";
}
else {
str += " }";
}
} else if ( v.type() == QVariant::Hash ) { // variant is a hash?
const QVariantHash vhash = v.toHash();
QHashIterator<QString, QVariant> it( vhash );
if (indentMode == QJson::IndentMinimum) {
QByteArray indent = buildIndent(indentLevel);
str = indent + "{ ";
}
else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel);
QByteArray nextindent = buildIndent(indentLevel + 1);
str = indent + "{\n" + nextindent;
}
else if (indentMode == QJson::IndentCompact) {
str = "{";
}
else {
str = "{ ";
}
QList<QByteArray> pairs;
while ( it.hasNext() ) {
it.next();
QByteArray serializedValue = serialize( it.value(), ok, indentLevel + 1);
if ( !*ok ) {
break;
}
QByteArray key = sanitizeString( it.key() ).toUtf8();
QByteArray value = serializedValue.trimmed();
if (indentMode == QJson::IndentCompact) {
pairs << key + ":" + value;
} else {
pairs << key + " : " + value;
}
}
if (indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel + 1);
str += join( pairs, ",\n" + indent);
}
else if (indentMode == QJson::IndentCompact) {
str += join( pairs, "," );
}
else {
str += join( pairs, ", " );
}
if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
QByteArray indent = buildIndent(indentLevel);
str += "\n" + indent + "}";
}
else if (indentMode == QJson::IndentCompact) {
str += "}";
}
else {
str += " }";
}
} else {
// Add indent, we may need to remove it later for some layouts
switch(indentMode) {
case QJson::IndentFull :
case QJson::IndentMedium :
case QJson::IndentMinimum :
str += buildIndent(indentLevel);
break;
case QJson::IndentCompact :
case QJson::IndentNone :
default:
break;
}
if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) { // a string or a byte array?
str = sanitizeString( v.toString() ).toUtf8();
} else if (( v.type() == QVariant::Double) || ((QMetaType::Type)v.type() == QMetaType::Float)) { // a double or a float?
const double value = v.toDouble();
#if defined _WIN32 && !defined(Q_OS_SYMBIAN)
const bool special = _isnan(value) || !_finite(value);
#elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
const bool special = isnan(value) || isinf(value);
#else
const bool special = std::isnan(value) || std::isinf(value);
#endif
if (special) {
if (specialNumbersAllowed) {
#if defined _WIN32 && !defined(Q_OS_SYMBIAN)
if (_isnan(value)) {
#elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
if (isnan(value)) {
#else
if (std::isnan(value)) {
#endif
str += "NaN";
} else {
if (value<0) {
str += '-';
}
str += "Infinity";
}
} else {
errorMessage += QLatin1String("Attempt to write NaN or infinity, which is not supported by json\n");
*ok = false;
}
} else {
str = QByteArray::number( value , 'g', doublePrecision);
if( ! str.contains( "." ) && ! str.contains( "e" ) ) {
str += ".0";
}
}
} else if ( v.type() == QVariant::Bool ) { // boolean value?
str += ( v.toBool() ? "true" : "false" );
} else if ( v.type() == QVariant::ULongLong ) { // large unsigned number?
str += QByteArray::number( v.value<qulonglong>() );
} else if ( v.type() == QVariant::UInt ) { // unsigned int number?
str += QByteArray::number( v.value<quint32>() );
} else if ( v.canConvert<qlonglong>() ) { // any signed number?
str += QByteArray::number( v.value<qlonglong>() );
} else if ( v.canConvert<int>() ) { // unsigned short number?
str += QByteArray::number( v.value<int>() );
} else if ( v.canConvert<QString>() ){ // can value be converted to string?
// this will catch QDate, QDateTime, QUrl, ...
str += sanitizeString( v.toString() ).toUtf8();
//TODO: catch other values like QImage, QRect, ...
} else {
*ok = false;
errorMessage += QLatin1String("Cannot serialize ");
errorMessage += v.toString();
errorMessage += QLatin1String(" because type ");
errorMessage += QLatin1String(v.typeName());
errorMessage += QLatin1String(" is not supported by QJson\n");
}
}
if ( *ok )
{
return str;
}
else
return QByteArray();
}
QByteArray Serializer::SerializerPrivate::buildIndent(int spaces)
{
QByteArray indent;
if (spaces < 0) {
spaces = 0;
}
for (int i = 0; i < spaces; i++ ) {
indent += " ";
}
return indent;
}
QString Serializer::SerializerPrivate::sanitizeString( QString str )
{
str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) );
// escape unicode chars
QString result;
const ushort* unicode = str.utf16();
unsigned int i = 0;
while ( unicode[ i ] ) {
if ( unicode[ i ] < 128 ) {
result.append( QChar( unicode[ i ] ) );
}
else {
QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4,
QLatin1Char('0') );
result.append( QLatin1String ("\\u") ).append( hexCode );
}
++i;
}
str = result;
str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) );
str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) );
str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) );
str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) );
str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) );
str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) );
return QString( QLatin1String( "\"%1\"" ) ).arg( str );
}
Serializer::Serializer()
: d( new SerializerPrivate )
{
}
Serializer::~Serializer() {
delete d;
}
void Serializer::serialize( const QVariant& v, QIODevice* io, bool* ok)
{
Q_ASSERT( io );
*ok = true;
if (!io->isOpen()) {
if (!io->open(QIODevice::WriteOnly)) {
d->errorMessage = QLatin1String("Error opening device");
*ok = false;
return;
}
}
if (!io->isWritable()) {
d->errorMessage = QLatin1String("Device is not readable");
io->close();
*ok = false;
return;
}
const QByteArray str = serialize( v, ok);
if (*ok && (io->write(str) != str.count())) {
*ok = false;
d->errorMessage = QLatin1String("Something went wrong while writing to IO device");
}
}
QByteArray Serializer::serialize( const QVariant &v)
{
bool ok;
return serialize(v, &ok);
}
QByteArray Serializer::serialize( const QVariant &v, bool *ok)
{
bool _ok = true;
d->errorMessage.clear();
if (ok) {
*ok = true;
} else {
ok = &_ok;
}
return d->serialize(v, ok);
}
void QJson::Serializer::allowSpecialNumbers(bool allow) {
d->specialNumbersAllowed = allow;
}
bool QJson::Serializer::specialNumbersAllowed() const {
return d->specialNumbersAllowed;
}
void QJson::Serializer::setIndentMode(IndentMode mode) {
d->indentMode = mode;
}
void QJson::Serializer::setDoublePrecision(int precision) {
d->doublePrecision = precision;
}
IndentMode QJson::Serializer::indentMode() const {
return d->indentMode;
}
QString QJson::Serializer::errorMessage() const {
return d->errorMessage;
}

230
src/serializer.h Normal file
View File

@ -0,0 +1,230 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Till Adam <adam@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef QJSON_SERIALIZER_H
#define QJSON_SERIALIZER_H
#include "qjson_export.h"
QT_BEGIN_NAMESPACE
class QIODevice;
class QString;
class QVariant;
QT_END_NAMESPACE
namespace QJson {
/**
@brief How the indentation should work.
\verbatim
none (default) :
{ "foo" : 0, "foo1" : 1, "foo2" : [ { "bar" : 1, "foo" : 0, "foobar" : 0 }, { "bar" : 1, "foo" : 1, "foobar" : 1 } ], "foo3" : [ 1, 2, 3, 4, 5, 6 ] }
compact :
{"foo":0,"foo1":1,"foo2":[{"bar":1,"foo":0,"foobar":0},{"bar":1,"foo":1,"foobar":1}],"foo3":[1,2,3,4,5,6]}
minimum :
{ "foo" : 0, "foo1" : 1, "foo2" : [
{ "bar" : 1, "foo" : 0, "foobar" : 0 },
{ "bar" : 1, "foo" : 1, "foobar" : 1 }
], "foo3" : [
1,
2,
3,
4,
5,
6
] }
medium :
{
"foo" : 0, "foo1" : 1, "foo2" : [
{
"bar" : 1, "foo" : 0, "foobar" : 0
},
{
"bar" : 1, "foo" : 1, "foobar" : 1
}
], "foo3" : [
1,
2,
3,
4,
5,
6
]
}
full :
{
"foo" : 0,
"foo1" : 1,
"foo2" : [
{
"bar" : 1,
"foo" : 0,
"foobar" : 0
},
{
"bar" : 1,
"foo" : 1,
"foobar" : 1
}
],
"foo3" : [
1,
2,
3,
4,
5,
6
]
}
\endverbatim
*/
enum IndentMode {
IndentNone,
IndentCompact,
IndentMinimum,
IndentMedium,
IndentFull
};
/**
* @brief Main class used to convert QVariant objects to JSON data.
*
* QVariant objects are converted to a string containing the JSON data.
*
*
* Usage:
*
* \code
* QVariantList people;
*
* QVariantMap bob;
* bob.insert("Name", "Bob");
* bob.insert("Phonenumber", 123);
*
* QVariantMap alice;
* alice.insert("Name", "Alice");
* alice.insert("Phonenumber", 321);
*
* people << bob << alice;
*
* QJson::Serializer serializer;
* bool ok;
* QByteArray json = serializer.serialize(people, &ok);
*
* if (ok) {
* qDebug() << json;
* } else {
* qCritical() << "Something went wrong:" << serializer.errorMessage();
* }
* \endcode
*
* The output will be:
*
* \code
* "[ { "Name" : "Bob", "Phonenumber" : 123 },
* { "Name" : "Alice", "Phonenumber" : 321 } ]"
* \endcode
*
* It's possible to tune the indentation level of the resulting string. \sa setIndentMode
*/
class QJSON_EXPORT Serializer {
public:
Serializer();
~Serializer();
/**
* This method generates a textual JSON representation and outputs it to the
* passed in I/O Device.
* @param variant The JSON document in its in-memory representation as generated by the
* parser.
* @param out Input output device
* @param ok if a conversion error occurs, *ok is set to false; otherwise *ok is set to true
*/
void serialize( const QVariant& variant, QIODevice* out, bool* ok);
/**
* This is a method provided for convenience. It turns the passed in in-memory
* representation of the JSON document into a textual one, which is returned.
* If the returned string is empty, the document was empty. If it was null, there
* was a parsing error.
*
* @param variant The JSON document in its in-memory representation as generated by the
* parser.
*
* \deprecated This method is going to be removed with the next major release of QJson.
*/
QByteArray serialize( const QVariant& variant);
/**
* This is a method provided for convenience. It turns the passed in in-memory
* representation of the JSON document into a textual one, which is returned.
* If the returned string is empty, the document was empty. If it was null, there
* was a parsing error.
*
* @param variant The JSON document in its in-memory representation as generated by the
* parser.
* @param ok if a conversion error occurs, *ok is set to false; otherwise *ok is set to true
*/
QByteArray serialize( const QVariant& variant, bool *ok);
/**
* Allow or disallow writing of NaN and/or Infinity (as an extension to QJson)
*/
void allowSpecialNumbers(bool allow);
/**
* Is Nan and/or Infinity allowed?
*/
bool specialNumbersAllowed() const;
/**
* set output indentation mode as defined in QJson::IndentMode
*/
void setIndentMode(IndentMode mode = QJson::IndentNone);
/**
* set double precision used while converting Double
* \sa QByteArray::number
*/
void setDoublePrecision(int precision);
/**
* Returns one of the indentation modes defined in QJson::IndentMode
*/
IndentMode indentMode() const;
/**
* Returns the error message
*/
QString errorMessage() const;
private:
Q_DISABLE_COPY(Serializer)
class SerializerPrivate;
SerializerPrivate* const d;
};
}
#endif // QJSON_SERIALIZER_H

View File

@ -0,0 +1,62 @@
#include "serializerrunnable.h"
/* This file is part of qjson
*
* Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
* 2009 Frank Osterfeld <osterfeld@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "parserrunnable.h"
#include "serializer.h"
#include <QtCore/QDebug>
#include <QtCore/QVariant>
using namespace QJson;
class SerializerRunnable::Private
{
public:
QVariant json;
};
SerializerRunnable::SerializerRunnable(QObject* parent)
: QObject(parent),
QRunnable(),
d(new Private)
{
qRegisterMetaType<QVariant>("QVariant");
}
SerializerRunnable::~SerializerRunnable()
{
delete d;
}
void SerializerRunnable::setJsonObject( const QVariant& json )
{
d->json = json;
}
void SerializerRunnable::run()
{
Serializer serializer;
bool ok;
const QByteArray serialized = serializer.serialize( d->json, &ok);
emit parsingFinished( serialized, ok, serializer.errorMessage() );
}

71
src/serializerrunnable.h Normal file
View File

@ -0,0 +1,71 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Frank Osterfeld <osterfeld@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef SERIALIZERRUNNABLE_H
#define SERIALIZERRUNNABLE_H
#include "qjson_export.h"
#include <QtCore/QObject>
#include <QtCore/QRunnable>
QT_BEGIN_NAMESPACE
class QByteArray;
class QString;
class QVariant;
QT_END_NAMESPACE
namespace QJson {
/**
* @brief Convenience class for converting JSON data to QVariant objects using a dedicated thread
*/
class QJSON_EXPORT SerializerRunnable : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit SerializerRunnable(QObject* parent = 0);
~SerializerRunnable();
/**
* Sets the json object to serialize.
*
* @param json QVariant containing the json representation to be serialized
*/
void setJsonObject( const QVariant& json );
/* reimp */ void run();
Q_SIGNALS:
/**
* This signal is emitted when the serialization process has been completed
* @param serialized contains the result of the serialization
* @param ok if a serialization error occurs ok is set to false, otherwise it's set to true.
* @param error_msg contains a string explaining the failure reason
**/
void parsingFinished(const QByteArray& serialized, bool ok, const QString& error_msg);
private:
Q_DISABLE_COPY(SerializerRunnable)
class Private;
Private* const d;
};
}
#endif // SERIALIZERRUNNABLE_H

133
src/stack.hh Normal file
View File

@ -0,0 +1,133 @@
/* A Bison parser, made by GNU Bison 2.7. */
/* Stack handling for Bison parsers in C++
Copyright (C) 2002-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/**
** \file stack.hh
** Define the yy::stack class.
*/
#ifndef YY_YY_STACK_HH_INCLUDED
# define YY_YY_STACK_HH_INCLUDED
# include <deque>
namespace yy {
/* Line 34 of stack.hh */
#line 47 "stack.hh"
template <class T, class S = std::deque<T> >
class stack
{
public:
// Hide our reversed order.
typedef typename S::reverse_iterator iterator;
typedef typename S::const_reverse_iterator const_iterator;
stack () : seq_ ()
{
}
stack (unsigned int n) : seq_ (n)
{
}
inline
T&
operator [] (unsigned int i)
{
return seq_[i];
}
inline
const T&
operator [] (unsigned int i) const
{
return seq_[i];
}
inline
void
push (const T& t)
{
seq_.push_front (t);
}
inline
void
pop (unsigned int n = 1)
{
for (; n; --n)
seq_.pop_front ();
}
inline
unsigned int
height () const
{
return seq_.size ();
}
inline const_iterator begin () const { return seq_.rbegin (); }
inline const_iterator end () const { return seq_.rend (); }
private:
S seq_;
};
/// Present a slice of the top of a stack.
template <class T, class S = stack<T> >
class slice
{
public:
slice (const S& stack, unsigned int range)
: stack_ (stack)
, range_ (range)
{
}
inline
const T&
operator [] (unsigned int i) const
{
return stack_[range_ - i];
}
private:
const S& stack_;
unsigned int range_;
};
} // yy
/* Line 116 of stack.hh */
#line 132 "stack.hh"
#endif /* !YY_YY_STACK_HH_INCLUDED */

1
tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
Makefile

15
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
IF (Qt5Core_FOUND)
FIND_PACKAGE( Qt5Test REQUIRED )
INCLUDE_DIRECTORIES(${Qt5Test_INCLUDE_DIRS})
ADD_DEFINITIONS(${Qt5Test_DEFINITIONS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Test_EXECUTABLE_COMPILE_FLAGS}")
SET (TEST_LIBRARIES ${Qt5Test_LIBRARIES})
ENDIF()
ADD_SUBDIRECTORY(cmdline_tester)
ADD_SUBDIRECTORY(parser)
ADD_SUBDIRECTORY(scanner)
ADD_SUBDIRECTORY(qobjecthelper)
ADD_SUBDIRECTORY(serializer)

View File

@ -0,0 +1,38 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
parsingbenchmark
qlocalevsstrtod_l
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
ADD_EXECUTABLE(
${test}
${test}.cpp
)
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@ -0,0 +1,55 @@
/* This file is part of QJson
*
* Copyright (C) 2014 Sune Vuorela <sune@ange.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QtTest/QTest>
#include <QFile>
class ParsingBenchmark: public QObject {
Q_OBJECT
private Q_SLOTS:
void benchmark();
};
void ParsingBenchmark::benchmark() {
QString path = QFINDTESTDATA("largefile.json");
QVERIFY(QFile::exists(path));
QFile f(path);
QVERIFY(f.open(QIODevice::ReadOnly));
QByteArray data = f.readAll();
QVariant result;
QJson::Parser parser;
QBENCHMARK {
result = parser.parse(data);
}
Q_UNUSED(result);
}
QTEST_MAIN(ParsingBenchmark)
#include "parsingbenchmark.moc"

View File

@ -0,0 +1,70 @@
/* This file is part of QJson
*
* Copyright (C) 2014 Sune Vuorela <sune@ange.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QObject>
#include <QtTest>
#include <locale.h>
class QLocaleVsStrtod_l : public QObject {
Q_OBJECT
private Q_SLOTS:
void benchmark();
void benchmark_data();
};
void QLocaleVsStrtod_l::benchmark() {
QFETCH(bool, useQLocale);
QList<char*> l;
l << strdup("0.123") << strdup("0.947834") << strdup("8.8373") << strdup("884.82921");
double result;
if(useQLocale) {
QLocale c(QLocale::C);
QBENCHMARK {
Q_FOREACH(const char* str, l) {
result = c.toDouble(QString(str));
}
}
} else {
locale_t c = newlocale(LC_NUMERIC_MASK, "C", NULL);
QBENCHMARK {
Q_FOREACH(const char* str, l) {
result = strtod_l(str, NULL, c);
}
}
}
Q_FOREACH(char* str, l) {
free(str);
}
}
void QLocaleVsStrtod_l::benchmark_data() {
QTest::addColumn<bool>("useQLocale");
QTest::newRow("using QLocale") << true;
QTest::newRow("using strtod_l") << false;
}
QTEST_MAIN(QLocaleVsStrtod_l);
#include "qlocalevsstrtod_l.moc"

4
tests/cmdline_tester/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
Makefile
*.o
*.moc
cmdline_tester

View File

@ -0,0 +1,35 @@
##### Probably don't want to edit below this line #####
IF (WIN32 AND Qt5Core_FOUND)
FIND_PACKAGE( Qt5Widgets REQUIRED )
INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDE_DIRS})
ADD_DEFINITIONS(${Qt5Widgets_DEFINITIONS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
ENDIF()
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
ADD_EXECUTABLE(
cmdline_tester
cmdline_tester.cpp
cmdlineparser.cpp
)
TARGET_LINK_LIBRARIES(
cmdline_tester
${QT_LIBRARIES}
${Qt5Widgets_LIBRARIES}
qjson
)

View File

@ -0,0 +1,99 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtCore/QTextCodec>
#include <QtCore/QTime>
#include <QJson/Parser>
#include <QJson/Serializer>
#include "cmdlineparser.h"
using namespace QJson;
int main(int argc, char *argv[]) {
QCoreApplication app (argc, argv);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForCStrings(codec);
#endif
QTime time;
int duration;
CmdLineParser cmd (app.arguments());
CmdLineParser::Result res = cmd.parse();
if (res == CmdLineParser::Help)
return 0;
else if (res == CmdLineParser::Error)
return -1;
QString filename = cmd.file();
if (!QFile::exists ( filename )) {
qCritical ("The file you specified doesn't exist!");
exit (1);
}
Parser parser;
bool ok;
QFile file (filename);
time.start();
QVariant data = parser.parse (&file, &ok);
duration = time.elapsed();
if (!ok) {
qCritical("%s:%i - Error: %s", filename.toLatin1().data(), parser.errorLine(), qPrintable(parser.errorString()));
exit (1);
}
else {
qDebug() << "Parsing of" << filename << "took" << duration << "ms";
if (!cmd.quiet())
qDebug() << data;
}
if (cmd.serialize()) {
// serializer tests
qDebug() << "Serializing... ";
QJson::Serializer serializer;
serializer.setIndentMode(cmd.indentationMode());
time.start();
QByteArray b = serializer.serialize(data, &ok);
if (!ok) {
qCritical() << "Serialization failed:" << serializer.errorMessage();
exit(1);
} else {
duration = time.elapsed();
qDebug() << "Serialization took:" << duration << "ms";
if (!cmd.quiet())
qDebug() << b;
}
}
qDebug() << "JOB DONE, BYE";
return 0;
}

View File

@ -0,0 +1,170 @@
/* This file is part of qjson
*
* Copyright (C) 2010 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <QtCore/QStringBuilder>
#ifdef Q_OS_WIN
//using Qt5
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/QMessageBox>
#else
//using Qt4
#include <QtGui/QMessageBox>
#endif
#endif
#include "cmdlineparser.h"
using namespace QJson;
const QString CmdLineParser::m_helpMessage = QLatin1String(
"Usage: cmdline_tester [options] file\n\n"
"This program converts the json data read from 'file' to a QVariant object.\n"
"--quiet Do not print output generated by parser and serializer.\n"
"--serialize Parses the QVariant object back to json.\n"
"--indent Sets the indentation level used by the 'serialize' option.\n"
" Allowed values:\n"
" - none [default]\n"
" - compact\n"
" - minimum\n"
" - medium\n"
" - full\n"
"--help Displays this help.\n"
);
CmdLineParser::CmdLineParser(const QStringList &arguments)
: m_pos(0),
m_indentationMode(IndentNone),
m_serialize(false),
m_quiet(false)
{
for (int i = 1; i < arguments.count(); ++i) {
const QString &arg = arguments.at(i);
m_arguments.append(arg);
}
}
CmdLineParser::Result CmdLineParser::parse()
{
bool showHelp = false;
while (m_error.isEmpty() && hasMoreArgs()) {
const QString &arg = nextArg();
if (arg.toLower() == QLatin1String("--indent"))
handleSetIndentationMode();
else if (arg.toLower() == QLatin1String("--help"))
showHelp = true;
else if (arg.toLower() == QLatin1String("--serialize"))
m_serialize = true;
else if (arg.toLower() == QLatin1String("--quiet"))
m_quiet = true;
else if (!arg.startsWith(QLatin1String("--")))
m_file = arg;
else
m_error = QString(QLatin1String("Unknown option: %1")).arg(arg);
}
if (m_file.isEmpty()) {
m_error = QLatin1String("You have to specify the file containing the json data.");
}
if (!m_error.isEmpty()) {
showMessage(m_error + QLatin1String("\n\n\n") + m_helpMessage, true);
return Error;
} else if (showHelp) {
showMessage(m_helpMessage, false);
return Help;
}
return Ok;
}
bool CmdLineParser::hasMoreArgs() const
{
return m_pos < m_arguments.count();
}
const QString &CmdLineParser::nextArg()
{
Q_ASSERT(hasMoreArgs());
return m_arguments.at(m_pos++);
}
void CmdLineParser::handleSetIndentationMode()
{
if (hasMoreArgs()) {
const QString &indentationMode = nextArg();
if (indentationMode.compare(QLatin1String("none"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentNone;
else if (indentationMode.compare(QLatin1String("compact"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentCompact;
else if (indentationMode.compare(QLatin1String("minimum"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentMinimum;
else if (indentationMode.compare(QLatin1String("medium"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentMedium;
else if (indentationMode.compare(QLatin1String("full"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentFull;
else
m_error = QString(QLatin1String("Unknown indentation mode '%1'.")).
arg(indentationMode);
} else {
m_error = QLatin1String("Missing indentation level.");
}
}
void CmdLineParser::showMessage(const QString &msg, bool error)
{
#ifdef Q_OS_WIN
QString message = QLatin1String("<pre>") % msg % QLatin1String("</pre>");
if (error)
QMessageBox::critical(0, QLatin1String("Error"), message);
else
QMessageBox::information(0, QLatin1String("Notice"), message);
#else
fprintf(error ? stderr : stdout, "%s\n", qPrintable(msg));
#endif
}
void CmdLineParser::setIndentationMode(const IndentMode &mode)
{
m_indentationMode = mode;
}
IndentMode CmdLineParser::indentationMode() const
{
return m_indentationMode;
}
QString CmdLineParser::file() const
{
return m_file;
}
bool CmdLineParser::serialize()
{
return m_serialize;
}
bool CmdLineParser::quiet()
{
return m_quiet;
}

View File

@ -0,0 +1,64 @@
/* This file is part of qjson
*
* Copyright (C) 2010 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef CMDLINEPARSER_H
#define CMDLINEPARSER_H
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QJson/Serializer>
namespace QJson {
class CmdLineParser
{
public:
enum Result {Ok, Help, Error};
CmdLineParser(const QStringList &arguments);
Result parse();
void setIndentationMode(const IndentMode &mode);
IndentMode indentationMode() const;
QString helpFile() const;
QString file() const;
bool serialize();
bool quiet();
void showMessage(const QString &msg, bool error);
private:
bool hasMoreArgs() const;
const QString &nextArg();
void handleSetIndentationMode();
QStringList m_arguments;
int m_pos;
IndentMode m_indentationMode;
QString m_file;
bool m_serialize;
bool m_quiet;
static const QString m_helpMessage;
QString m_error;
};
}
#endif

View File

@ -0,0 +1,22 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

4
tests/parser/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
Makefile
*.o
*.moc
parser

View File

@ -0,0 +1,46 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testparser
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

456
tests/parser/testparser.cpp Normal file
View File

@ -0,0 +1,456 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <cmath>
#include <QtCore/QVariant>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QLocale>
class TestParser: public QObject
{
Q_OBJECT
private slots:
void parseNonAsciiString();
void parseSimpleObject();
void parseEmptyObject();
void parseEmptyValue();
void parseUrl();
void parseMultipleObject();
void parseSimpleArray();
void parseInvalidObject();
void parseInvalidObject_data();
void parseMultipleArray();
void reuseSameParser();
void testTrueFalseNullValues();
void testEscapeChars();
void testNumbers();
void testNumbers_data();
void testDoubleParsingWithDifferentLocale();
void testTopLevelValues();
void testTopLevelValues_data();
void testReadWrite();
void testReadWrite_data();
};
Q_DECLARE_METATYPE(QVariant)
Q_DECLARE_METATYPE(QVariant::Type)
using namespace QJson;
void TestParser::parseSimpleObject() {
QByteArray json = "{\"foo\":\"bar\"}";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
QVariant expected(map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseEmptyObject() {
QByteArray json = "{}";
QVariantMap map;
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseEmptyValue() {
QByteArray json = "{\"value\": \"\"}";
QVariantMap map;
map.insert (QLatin1String("value"), QString(QLatin1String("")));
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QVERIFY (result.toMap().value(QLatin1String("value")).type() == QVariant::String);
QString value = result.toMap().value(QLatin1String("value")).toString();
QVERIFY (value.isEmpty());
}
void TestParser::parseInvalidObject() {
QFETCH(QByteArray, json);
Parser parser;
bool ok;
parser.parse (json, &ok);
QVERIFY (!ok);
QVERIFY(!parser.errorString().isEmpty());
}
void TestParser::parseInvalidObject_data() {
QTest::addColumn<QByteArray>("json");
QTest::newRow("unclosed object") << QByteArray("{\"foo\":\"bar\"");
QTest::newRow("infinum (disallow") << QByteArray("Infinum");
QTest::newRow("Nan (disallow") << QByteArray("NaN");
QTest::newRow("no data") << QByteArray("");
}
void TestParser::parseNonAsciiString() {
QByteArray json = "{\"artist\":\"Queensr\\u00ffche\"}";
QVariantMap map;
QChar unicode_char (0x00ff);
QString unicode_string;
unicode_string.setUnicode(&unicode_char, 1);
unicode_string = QLatin1String("Queensr") + unicode_string + QLatin1String("che");
map.insert (QLatin1String("artist"), unicode_string);
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseMultipleObject() {
//put also some extra spaces inside the json string
QByteArray json = "{ \"foo\":\"bar\",\n\"number\" : 51.3 , \"array\":[\"item1\", 123]}";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
map.insert (QLatin1String("number"), 51.3);
QVariantList list;
list.append (QLatin1String("item1"));
list.append (QLatin1String("123"));
map.insert (QLatin1String("array"), list);
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QVERIFY (result.toMap().value(QLatin1String("number")).canConvert<float>());
QVERIFY (result.toMap().value(QLatin1String("array")).canConvert<QVariantList>());
}
void TestParser::parseUrl(){
//"http:\/\/www.last.fm\/venue\/8926427"
QByteArray json = "[\"http:\\/\\/www.last.fm\\/venue\\/8926427\"]";
QVariantList list;
list.append (QVariant(QLatin1String("http://www.last.fm/venue/8926427")));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseSimpleArray() {
QByteArray json = "[\"foo\",\"bar\"]";
QVariantList list;
list.append (QLatin1String("foo"));
list.append (QLatin1String("bar"));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseMultipleArray() {
//put also some extra spaces inside the json string
QByteArray json = "[ {\"foo\":\"bar\"},\n\"number\",51.3 , [\"item1\", 123]]";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
QVariantList array;
array.append (QLatin1String("item1"));
array.append (123);
QVariantList list;
list.append (map);
list.append (QLatin1String("number"));
list.append (QLatin1String("51.3"));
list.append ((QVariant) array);
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::testTrueFalseNullValues() {
QByteArray json = "[true,false, null, {\"foo\" : true}]";
QVariantList list;
list.append (QVariant(true));
list.append (QVariant(false));
list.append (QVariant());
QVariantMap map;
map.insert (QLatin1String("foo"), true);
list.append (map);
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QCOMPARE (result.toList().at(0).toBool(), true);
QCOMPARE (result.toList().at(1).toBool(), false);
QVERIFY (result.toList().at(2).isNull());
}
void TestParser::testEscapeChars() {
QByteArray json = "[\"\\b \\f \\n \\r \\t \", \" \\\\ \\/ \\\\\", \"http:\\/\\/foo.com\"]";
QVariantList list;
list.append (QLatin1String("\b \f \n \r \t "));
list.append (QLatin1String(" \\ / \\"));
list.append (QLatin1String("http://foo.com"));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result.toList().size(), expected.toList().size() );
QCOMPARE(result, expected);
}
void TestParser::testNumbers() {
QFETCH(QByteArray, input);
QFETCH(QVariant, expected);
QFETCH(QVariant::Type, type);
Parser parser;
bool ok;
QVariant result = parser.parse ('[' + input + ']', &ok);
QVERIFY (ok);
QVariant value = result.toList().at(0);
QCOMPARE(value, expected);
QCOMPARE( value.type(), type);
}
void TestParser::testNumbers_data() {
QTest::addColumn<QByteArray>( "input" );
QTest::addColumn<QVariant>( "expected" );
QTest::addColumn<QVariant::Type>( "type" );
QByteArray input;
QVariant output;
// simple ulonglong
input = QByteArray("1");
output = QVariant(QVariant::ULongLong);
output.setValue(1);
QTest::newRow("simple ulonglong") << input << output << QVariant::ULongLong;
// big number
input = QByteArray("12345678901234567890");
output = QVariant(QVariant::ULongLong);
output.setValue(12345678901234567890ull);
QTest::newRow("big number") << input << output << QVariant::ULongLong;
// simple double
input = QByteArray("2.004");
output = QVariant(QVariant::Double);
output.setValue(2.004);
QTest::newRow("simple double") << input << output << QVariant::Double;
// negative int
input = QByteArray("-100");
output = QVariant(QVariant::LongLong);
output.setValue(-100);
QTest::newRow("negative int") << input << output << QVariant::LongLong;
// negative double
input = QByteArray("-3.4");
output = QVariant(QVariant::Double);
output.setValue(-3.4);
QTest::newRow("negative double") << input << output << QVariant::Double;
}
void TestParser::testTopLevelValues() {
QFETCH(QByteArray, input);
QFETCH(QVariant, expected);
QFETCH(QVariant::Type, type);
Parser parser;
bool ok;
QVariant result = parser.parse (input, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QCOMPARE(result.type(), type);
}
void TestParser::testTopLevelValues_data() {
QTest::addColumn<QByteArray>( "input" );
QTest::addColumn<QVariant>( "expected" );
QTest::addColumn<QVariant::Type>( "type" );
QByteArray input;
QVariant output;
// string
input = QByteArray("\"foo bar\"");
output = QVariant(QLatin1String("foo bar"));
QTest::newRow("string") << input << output << QVariant::String;
// number
input = QByteArray("2.4");
output = QVariant(QVariant::Double);
output.setValue(2.4);
QTest::newRow("simple double") << input << output << QVariant::Double;
// boolean
input = QByteArray("true");
output = QVariant(QVariant::Bool);
output.setValue(true);
QTest::newRow("bool") << input << output << QVariant::Bool;
// null
input = QByteArray("null");
output = QVariant();
QTest::newRow("null") << input << output << QVariant::Invalid;
// array
input = QByteArray("[1,2,3]");
QVariantList list;
list << QVariant(1) << QVariant(2) << QVariant(3);
output = QVariant(QVariant::List);
output.setValue(list);
QTest::newRow("array") << input << output << QVariant::List;
// object
input = QByteArray("{\"foo\" : \"bar\"}");
QVariantMap map;
map.insert(QLatin1String("foo"), QLatin1String("bar"));
output = QVariant(QVariant::Map);
output.setValue(map);
QTest::newRow("object") << input << output << QVariant::Map;
}
void TestParser::testDoubleParsingWithDifferentLocale() {
QLocale oldLocale;
QLocale itLocale(QLatin1String("it_IT.utf8"));
QCOMPARE(itLocale.name(), QLatin1String("it_IT") );
// the Italian locale uses ',' as digit separator.
QLocale::setDefault(itLocale);
Parser parser;
bool ok;
QVariant result = parser.parse ("12.3", &ok);
QVERIFY (ok);
QCOMPARE(result.toDouble(), 12.3);
QLocale::setDefault(oldLocale);
}
void TestParser::testReadWrite()
{
QFETCH( QVariant, variant );
Serializer serializer;
bool ok;
QByteArray json = serializer.serialize(variant, &ok);
QVERIFY(ok);
Parser parser;
QVariant result = parser.parse( json, &ok );
QVERIFY(ok);
QCOMPARE( result, variant );
}
void TestParser::testReadWrite_data()
{
QTest::addColumn<QVariant>( "variant" );
// array tests
QTest::newRow( "empty array" ) << QVariant(QVariantList());
// basic array
QVariantList list;
list << QString(QLatin1String("hello"));
list << 12;
QTest::newRow( "basic array" ) << QVariant(list);
// simple map
QVariantMap map;
map[QString(QLatin1String("Name"))] = 32;
QTest::newRow( "complicated array" ) << QVariant(map);
}
void TestParser::reuseSameParser()
{
Parser parser;
bool ok;
parser.parse ("12.3", &ok);
QVERIFY (ok);
parser.parse ("wrong entry", &ok);
QVERIFY (!ok);
parser.parse ("12.3", &ok);
QVERIFY (ok);
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestParser)
#include "moc_testparser.cxx"
#else
QTEST_GUILESS_MAIN(TestParser)
#include "testparser.moc"
#endif

5
tests/qobjecthelper/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
Makefile
*.o
*.moc
moc_*
qobjecthelper

View File

@ -0,0 +1,55 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET (qjson_test_support_SRCS person.cpp)
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(qjson_test_support_MOC_SRCS person.h)
ENDIF()
ADD_LIBRARY (qjson_test_support STATIC ${qjson_test_support_SRCS}
${qjson_test_support_MOC_SRCS})
SET( UNIT_TESTS
testqobjecthelper
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson
qjson_test_support
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@ -0,0 +1,75 @@
#include "person.h"
Person::Person(QObject* parent)
: QObject(parent),
m_name(),
m_phoneNumber(0),
m_gender(Female),
m_luckyNumber(0)
{
}
Person::~Person()
{
}
QString Person::name() const
{
return m_name;
}
void Person::setName(const QString& name)
{
m_name = name;
}
int Person::phoneNumber() const
{
return m_phoneNumber;
}
void Person::setPhoneNumber(const int phoneNumber)
{
m_phoneNumber = phoneNumber;
}
void Person::setGender(Gender gender)
{
m_gender = gender;
}
Person::Gender Person::gender() const
{
return m_gender;
}
QDate Person::dob() const
{
return m_dob;
}
void Person::setDob(const QDate& dob)
{
m_dob = dob;
}
QVariant Person::customField() const
{
return m_customField;
}
void Person::setCustomField(const QVariant& customField)
{
m_customField = customField;
}
const quint16 Person::luckyNumber() const
{
return m_luckyNumber;
}
void Person::setLuckyNumber(const quint16 luckyNumber)
{
m_luckyNumber = luckyNumber;
}

View File

@ -0,0 +1,73 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Till Adam <adam@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef PERSON_H
#define PERSON_H
#include <QtCore/QDate>
#include <QtCore/QtGlobal>
#include <QtCore/QObject>
#include <QtCore/QVariant>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int phoneNumber READ phoneNumber WRITE setPhoneNumber)
Q_PROPERTY(Gender gender READ gender WRITE setGender)
Q_PROPERTY(QDate dob READ dob WRITE setDob)
Q_PROPERTY(QVariant customField READ customField WRITE setCustomField)
Q_PROPERTY(quint16 luckyNumber READ luckyNumber WRITE setLuckyNumber)
Q_ENUMS(Gender)
public:
Person(QObject* parent = 0);
~Person();
QString name() const;
void setName(const QString& name);
int phoneNumber() const;
void setPhoneNumber(const int phoneNumber);
enum Gender {Male, Female};
void setGender(Gender gender);
Gender gender() const;
QDate dob() const;
void setDob(const QDate& dob);
QVariant customField() const;
void setCustomField(const QVariant& customField);
const quint16 luckyNumber() const;
void setLuckyNumber(const quint16 luckyNumber);
private:
QString m_name;
int m_phoneNumber;
Gender m_gender;
QDate m_dob;
QVariant m_customField;
quint16 m_luckyNumber;
};
#endif

View File

@ -0,0 +1,126 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <limits>
#include <QtCore/QVariant>
#include <QtCore/QVariantList>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QJson/QObjectHelper>
#include "person.h"
class TestQObjectHelper: public QObject
{
Q_OBJECT
private slots:
void testQObject2QVariant();
void testQVariant2QObject();
};
using namespace QJson;
void TestQObjectHelper::testQObject2QVariant()
{
QString name = QLatin1String("Flavio Castelli");
int phoneNumber = 123456;
Person::Gender gender = Person::Male;
QDate dob (1982, 7, 12);
QVariantList nicknames;
nicknames << QLatin1String("nickname1") << QLatin1String("nickname2");
quint16 luckyNumber = 123;
Person person;
person.setName(name);
person.setPhoneNumber(phoneNumber);
person.setGender(gender);
person.setDob(dob);
person.setCustomField(nicknames);
person.setLuckyNumber(luckyNumber);
QVariantMap expected;
expected[QLatin1String("name")] = QVariant(name);
expected[QLatin1String("phoneNumber")] = QVariant(phoneNumber);
expected[QLatin1String("gender")] = QVariant(gender);
expected[QLatin1String("dob")] = QVariant(dob);
expected[QLatin1String("customField")] = nicknames;
expected[QLatin1String("luckyNumber")] = luckyNumber;
QVariantMap result = QObjectHelper::qobject2qvariant(&person);
QCOMPARE(result, expected);
}
void TestQObjectHelper::testQVariant2QObject()
{
bool ok;
QString name = QLatin1String("Flavio Castelli");
int phoneNumber = 123456;
Person::Gender gender = Person::Male;
QDate dob (1982, 7, 12);
QVariantList nicknames;
nicknames << QLatin1String("nickname1") << QLatin1String("nickname2");
quint16 luckyNumber = 123;
Person expected_person;
expected_person.setName(name);
expected_person.setPhoneNumber(phoneNumber);
expected_person.setGender(gender);
expected_person.setDob(dob);
expected_person.setCustomField(nicknames);
expected_person.setLuckyNumber(luckyNumber);
QVariantMap variant = QObjectHelper::qobject2qvariant(&expected_person);
Serializer serializer;
QByteArray json = serializer.serialize(variant, &ok);
qDebug() << "json is" << json;
QVERIFY(ok);
Parser parser;
QVariant parsedVariant = parser.parse(json,&ok);
QVERIFY(ok);
qDebug() << parsedVariant;
QVERIFY(parsedVariant.canConvert(QVariant::Map));
Person person;
QCOMPARE(Person::Female, person.gender());
QObjectHelper::qvariant2qobject(parsedVariant.toMap(), &person);
QCOMPARE(person.name(), name);
QCOMPARE(person.phoneNumber(), phoneNumber);
QCOMPARE(person.gender(), gender);
QCOMPARE(person.dob(), dob);
QCOMPARE(person.customField(), QVariant(nicknames));
QCOMPARE(person.luckyNumber(), luckyNumber);
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestQObjectHelper)
#include "moc_testqobjecthelper.cxx"
#else
QTEST_GUILESS_MAIN(TestQObjectHelper)
#include "testqobjecthelper.moc"
#endif

View File

@ -0,0 +1,47 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../src
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testscanner
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@ -0,0 +1,256 @@
/* This file is part of QJson
*
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <cmath>
#include <QtCore/QVariant>
#include <QtCore/QVariant>
#include <QtTest/QtTest>
#include "json_scanner.h"
#include "json_parser.hh"
#include "location.hh"
#define TOKEN(type) (int)yy::json_parser::token::type
class TestScanner: public QObject
{
Q_OBJECT
private slots:
void scanClosedDevice();
void scanTokens();
void scanTokens_data();
void scanSpecialNumbers();
void scanSpecialNumbers_data();
};
Q_DECLARE_METATYPE(QVariant)
Q_DECLARE_METATYPE(QVariant::Type)
using namespace QJson;
void TestScanner::scanClosedDevice() {
QBuffer buffer;
int expectedResult = -1;
JSonScanner scanner(&buffer);
QVariant yylval;
yy::location location;
int result = scanner.yylex(&yylval, &location);
QCOMPARE(result, expectedResult);
}
void TestScanner::scanTokens() {
QFETCH(QByteArray, input);
QFETCH(bool, allowSpecialNumbers);
QFETCH(bool, skipFirstToken);
QFETCH(int, expectedResult);
QFETCH(QVariant, expectedYylval);
QFETCH(int, expectedLocationBeginLine);
QFETCH(int, expectedLocationBeginColumn);
QFETCH(int, expectedLocationEndLine);
QFETCH(int, expectedLocationEndColumn);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
buffer.write(input);
buffer.seek(0);
JSonScanner scanner(&buffer);
scanner.allowSpecialNumbers(allowSpecialNumbers);
QVariant yylval;
yy::position position(YY_NULL, 1, 0);
yy::location location(position, position);
int result = scanner.yylex(&yylval, &location);
if (skipFirstToken) {
result = scanner.yylex(&yylval, &location);
}
QCOMPARE(result, expectedResult);
QCOMPARE(yylval, expectedYylval);
QCOMPARE(location.begin.line, (uint)expectedLocationBeginLine);
QCOMPARE(location.begin.column, (uint)expectedLocationBeginColumn);
QCOMPARE(location.end.line, (uint)expectedLocationEndLine);
QCOMPARE(location.end.column, (uint)expectedLocationEndColumn);
}
void TestScanner::scanTokens_data() {
QTest::addColumn<QByteArray>("input");
QTest::addColumn<bool>("allowSpecialNumbers");
QTest::addColumn<bool>("skipFirstToken");
QTest::addColumn<int>("expectedResult");
QTest::addColumn<QVariant>("expectedYylval");
QTest::addColumn<int>("expectedLocationBeginLine");
QTest::addColumn<int>("expectedLocationBeginColumn");
QTest::addColumn<int>("expectedLocationEndLine");
QTest::addColumn<int>("expectedLocationEndColumn");
QTest::newRow("empty string") << QByteArray("") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 0;
QTest::newRow("carriage return") << QByteArray("\r") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 2 << 1;
QTest::newRow("new line") << QByteArray("\n") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 2 << 1;
QTest::newRow("formfeed") << QByteArray("\f") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("vertical tab") << QByteArray("\v") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("space") << QByteArray(" ") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("tab") << QByteArray("\t") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("all spaces") << QByteArray("\r\n\f\v \t") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 3 << 5;
QTest::newRow("true") << QByteArray("true") << true << false << TOKEN(TRUE_VAL) << QVariant(true) << 1 << 0 << 1 << 4;
QTest::newRow("false") << QByteArray("false") << true << false << TOKEN(FALSE_VAL) << QVariant(false) << 1 << 0 << 1 << 5;
QTest::newRow("null") << QByteArray("null") << true << false << TOKEN(NULL_VAL) << QVariant() << 1 << 0 << 1 << 4;
QTest::newRow("alphabetic string") << QByteArray("\"abcde\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("abcde")) << 1 << 0 << 1 << 2;
QTest::newRow("ecaped string") << QByteArray("\"abcde\\b\\f\\n\\r\\t\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("abcde\b\f\n\r\t")) << 1 << 0 << 1 << 2;
QTest::newRow("invalid ecaped string") << QByteArray("\"\\x\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("x")) << 1 << 0 << 1 << 2;
QTest::newRow("escaped unicode sequence") << QByteArray("\"\\u005A\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("Z")) << 1 << 0 << 1 << 2;
QTest::newRow("invalid unicode sequence") << QByteArray("\"\\u005Z\"") << true << false << TOKEN(INVALID) << QVariant(QLatin1String("")) << 1 << 0 << 1 << 2;
QTest::newRow("empty string") << QByteArray("\"") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("single digit") << QByteArray("0") << true << false << TOKEN(NUMBER) << QVariant(0u) << 1 << 0 << 1 << 1;
QTest::newRow("multiple digits") << QByteArray("123456789") << true << false << TOKEN(NUMBER) << QVariant(123456789u) << 1 << 0 << 1 << 9;
QTest::newRow("negative single digit") << QByteArray("-0") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 2;
QTest::newRow("negative multiple digits") << QByteArray("-123456789") << true << false << TOKEN(NUMBER) << QVariant(-123456789) << 1 << 0 << 1 << 10;
QTest::newRow("fractional single digit") << QByteArray("0.1") << true << false << TOKEN(NUMBER) << QVariant(0.1) << 1 << 0 << 1 << 3;
QTest::newRow("fractional multiple digits") << QByteArray("123456789.12") << true << false << TOKEN(NUMBER) << QVariant(123456789.12) << 1 << 0 << 1 << 12;
QTest::newRow("fractional negative single digit") << QByteArray("-0.3") << true << false << TOKEN(NUMBER) << QVariant(-0.3) << 1 << 0 << 1 << 4;
QTest::newRow("fractional negative multiple digits") << QByteArray("-123456789.23") << true << false << TOKEN(NUMBER) << QVariant(-123456789.23) << 1 << 0 << 1 << 13;
QTest::newRow("exponential single digit") << QByteArray("10e2") << true << false << TOKEN(NUMBER) << QVariant(1000) << 1 << 0 << 1 << 4;
QTest::newRow("exponential multiple digits") << QByteArray("10e23") << true << false << TOKEN(NUMBER) << QVariant(10e23) << 1 << 0 << 1 << 5;
QTest::newRow("exponential zero") << QByteArray("0e23") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 4;
QTest::newRow("exponential fractional") << QByteArray("0.12354e23") << true << false << TOKEN(NUMBER) << QVariant(0.12354e23) << 1 << 0 << 1 << 10;
QTest::newRow("exponential fractional multiple digits") << QByteArray("120.12354e23") << true << false << TOKEN(NUMBER) << QVariant(120.12354e23) << 1 << 0 << 1 << 12;
QTest::newRow("uppercase exponential") << QByteArray("120.12354E23") << true << false << TOKEN(NUMBER) << QVariant(120.12354E23) << 1 << 0 << 1 << 12;
QTest::newRow("negative exponential single digit") << QByteArray("-10e2") << true << false << TOKEN(NUMBER) << QVariant(-1000) << 1 << 0 << 1 << 5;
QTest::newRow("negative exponential multiple digits") << QByteArray("-10e23") << true << false << TOKEN(NUMBER) << QVariant(-10e23) << 1 << 0 << 1 << 6;
QTest::newRow("negative exponential zero") << QByteArray("-0e23") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 5;
QTest::newRow("negative exponential fractional") << QByteArray("-0.12354e23") << true << false << TOKEN(NUMBER) << QVariant(-0.12354e23) << 1 << 0 << 1 << 11;
QTest::newRow("negative exponential fractional multiple digits") << QByteArray("-120.12354e23") << true << false << TOKEN(NUMBER) << QVariant(-120.12354e23) << 1 << 0 << 1 << 13;
QTest::newRow("negative exponent") << QByteArray("10e-2") << true << false << TOKEN(NUMBER) << QVariant(10e-2) << 1 << 0 << 1 << 5;
QTest::newRow("positive exponent with plus") << QByteArray("10e+2") << true << false << TOKEN(NUMBER) << QVariant(1000) << 1 << 0 << 1 << 5;
QTest::newRow("invalid multiple digits") << QByteArray("001") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 1;
QTest::newRow("invalid negative multiple digits") << QByteArray("-001") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 2;
QTest::newRow("invalid fractional") << QByteArray("12.") << true << true << TOKEN(INVALID) << QVariant(12) << 1 << 2 << 1 << 3;
QTest::newRow("invalid exponential 1") << QByteArray("-5e+") << true << true << TOKEN(INVALID) << QVariant(-5) << 1 << 2 << 1 << 3;
QTest::newRow("invalid exponential 2") << QByteArray("2e") << true << true << TOKEN(INVALID) << QVariant(2) << 1 << 1 << 1 << 2;
QTest::newRow("invalid exponential 3") << QByteArray("3e+") << true << true << TOKEN(INVALID) << QVariant(3) << 1 << 1 << 1 << 2;
QTest::newRow("invalid exponential 4") << QByteArray("4.3E") << true << true << TOKEN(INVALID) << QVariant(4.3) << 1 << 3 << 1 << 4;
QTest::newRow("invalid exponential 5") << QByteArray("5.4E-") << true << true << TOKEN(INVALID) << QVariant(5.4) << 1 << 3 << 1 << 4;
QTest::newRow("colon") << QByteArray(":") << true << false << TOKEN(COLON) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("comma") << QByteArray(",") << true << false << TOKEN(COMMA) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("square bracket open") << QByteArray("[") << true << false << TOKEN(SQUARE_BRACKET_OPEN) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("square bracket close") << QByteArray("]") << true << false << TOKEN(SQUARE_BRACKET_CLOSE) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("curly bracket open") << QByteArray("{") << true << false << TOKEN(CURLY_BRACKET_OPEN) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("curly bracket close") << QByteArray("}") << true << false << TOKEN(CURLY_BRACKET_CLOSE) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("too large unsinged number") << QByteArray("18446744073709551616") << false << false << TOKEN(INVALID) << QVariant(ULLONG_MAX) << 1 << 0 << 1 << 20;
QTest::newRow("too large signed number") << QByteArray("-9223372036854775808") << false << false << TOKEN(INVALID) << QVariant(LLONG_MIN) << 1 << 0 << 1 << 20;
QTest::newRow("too large exponential") << QByteArray("1.7976931348623157e309") << false << false << TOKEN(INVALID) << QVariant(0) << 1 << 0 << 1 << 22;
QTest::newRow("not allowed nan") << QByteArray("nan") << false << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("not allowed infinity") << QByteArray("Infinity") << false << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("unknown") << QByteArray("*") << true << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
}
void TestScanner::scanSpecialNumbers() {
QFETCH(QByteArray, input);
QFETCH(bool, isInfinity);
QFETCH(bool, isNegative);
QFETCH(bool, isNan);
QFETCH(int, expectedLocationBeginLine);
QFETCH(int, expectedLocationBeginColumn);
QFETCH(int, expectedLocationEndLine);
QFETCH(int, expectedLocationEndColumn);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
buffer.write(input);
buffer.seek(0);
JSonScanner scanner(&buffer);
scanner.allowSpecialNumbers(true);
QVariant yylval;
yy::position position(YY_NULL, 1, 0);
yy::location location(position, position);
int result = scanner.yylex(&yylval, &location);
QCOMPARE(result, TOKEN(NUMBER));
QVERIFY(yylval.type() == QVariant::Double);
double doubleResult = yylval.toDouble();
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY)
QCOMPARE(bool(isinf(doubleResult)), isInfinity);
#else
// skip this test for MSVC, because there is no "isinf" function.
#ifndef Q_CC_MSVC
QCOMPARE(bool(std::isinf(doubleResult)), isInfinity);
#endif
#endif
QCOMPARE(doubleResult<0, isNegative);
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY)
QCOMPARE(bool(isnan(doubleResult)), isNan);
#else
// skip this test for MSVC, because there is no "isinf" function.
#ifndef Q_CC_MSVC
QCOMPARE(bool(std::isnan(doubleResult)), isNan);
#endif
#endif
QCOMPARE(location.begin.line, (uint)expectedLocationBeginLine);
QCOMPARE(location.begin.column, (uint)expectedLocationBeginColumn);
QCOMPARE(location.end.line, (uint)expectedLocationEndLine);
QCOMPARE(location.end.column, (uint)expectedLocationEndColumn);
}
void TestScanner::scanSpecialNumbers_data() {
QTest::addColumn<QByteArray>("input");
QTest::addColumn<bool>("isInfinity");
QTest::addColumn<bool>("isNegative");
QTest::addColumn<bool>("isNan");
QTest::addColumn<int>("expectedLocationBeginLine");
QTest::addColumn<int>("expectedLocationBeginColumn");
QTest::addColumn<int>("expectedLocationEndLine");
QTest::addColumn<int>("expectedLocationEndColumn");
QTest::newRow("nan") << QByteArray("nan") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("NAN") << QByteArray("NAN") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("NaN") << QByteArray("NaN") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("infinity") << QByteArray("infinity") << true << false << false << 1 << 0 << 1 << 8;
QTest::newRow("Infinity") << QByteArray("infinity") << true << false << false << 1 << 0 << 1 << 8;
QTest::newRow("-infinity") << QByteArray("-infinity") << true << true << false << 1 << 0 << 1 << 9;
QTest::newRow("-Infinity") << QByteArray("-Infinity") << true << true << false << 1 << 0 << 1 << 9;
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestScanner)
#include "moc_testscanner.cxx"
#else
QTEST_GUILESS_MAIN(TestScanner)
#include "testscanner.moc"
#endif

4
tests/serializer/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
Makefile
*.o
*.moc
serializer

View File

@ -0,0 +1,46 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testserializer
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@ -0,0 +1,542 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <limits>
#include <QtCore/QVariant>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
class TestSerializer: public QObject
{
Q_OBJECT
private slots:
void testReadWriteEmptyDocument();
void testReadWrite();
void testReadWrite_data();
void testValueNull();
void testValueString();
void testValueString_data();
void testValueStringList();
void testValueStringList_data();
void testValueHashMap();
void testValueInteger();
void testValueInteger_data();
void testValueDouble();
void testValueDouble_data();
void testSetDoublePrecision();
void testValueFloat();
void testValueFloat_data();
void testValueBoolean();
void testValueBoolean_data();
void testSpecialNumbers();
void testSpecialNumbers_data();
void testIndentation();
void testIndentation_data();
void testSerializetoQIODevice();
void testSerializeWithoutOkParam();
private:
void valueTest( const QVariant& value, const QString& expectedRegExp, bool errorExpected = false );
void valueTest( const QObject* object, const QString& expectedRegExp );
};
Q_DECLARE_METATYPE(QVariant)
using namespace QJson;
void TestSerializer::testReadWriteEmptyDocument()
{
QByteArray json = "";
Parser parser;
bool ok;
QVariant result = parser.parse( json, &ok );
QVERIFY(!ok);
QVERIFY( ! result.isValid() );
Serializer serializer;
const QByteArray serialized = serializer.serialize( result, &ok);
QVERIFY( ok );
QByteArray expected = "null";
QCOMPARE(expected, serialized);
}
void TestSerializer::testReadWrite()
{
QFETCH( QByteArray, json );
Parser parser;
bool ok;
QVariant result = parser.parse( json, &ok );
QVERIFY(ok);
Serializer serializer;
const QByteArray serialized = serializer.serialize( result, &ok);
QVERIFY(ok);
QVariant writtenThenRead = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( result, writtenThenRead );
}
void TestSerializer::testReadWrite_data()
{
QTest::addColumn<QByteArray>( "json" );
// array tests
QTest::newRow( "empty array" ) << QByteArray("[]");
QTest::newRow( "basic array" ) << QByteArray("[\"person\",\"bar\"]");
QTest::newRow( "single int array" ) << QByteArray("[6]");
QTest::newRow( "int array" ) << QByteArray("[6,5,6,7]");
const QByteArray json = "[1,2.4, -100, -3.4, -5e+0, 2e0,3e+0,4.3E0,5.4E-0]";
QTest::newRow( QByteArray("array of various numbers") ) << json;
// document tests
QTest::newRow( "empty object" ) << QByteArray("{}");
QTest::newRow( "basic document" ) << QByteArray("{\"person\":\"bar\"}");
QTest::newRow( "object with ints" ) << QByteArray("{\"person\":6}");
const QByteArray json2 = "{ \"person\":\"bar\",\n\"number\" : 51.3 , \"array\":[\"item1\", 123]}";
QTest::newRow( "complicated document" ) << json2;
// more complex cases
const QByteArray json3 = "[ {\"person\":\"bar\"},\n\"number\",51.3 , [\"item1\", 123]]";
QTest::newRow( "complicated array" ) << json3;
}
void TestSerializer::testIndentation()
{
QFETCH( QByteArray, json );
QFETCH( QByteArray, expected_compact );
QFETCH( QByteArray, expected_min );
QFETCH( QByteArray, expected_med );
QFETCH( QByteArray, expected_full );
// parse
Parser parser;
bool ok;
QVariant parsed = parser.parse( json, &ok );
QVERIFY(ok);
Serializer serializer;
QVariant reparsed;
QByteArray serialized;
// serialize with indent compact and reparse
serializer.setIndentMode(QJson::IndentCompact);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_compact);
reparsed = parser.parse( serialized, &ok);
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent minimum and reparse
serializer.setIndentMode(QJson::IndentMinimum);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_min);
reparsed = parser.parse( serialized, &ok);
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent medium and reparse
serializer.setIndentMode(QJson::IndentMedium);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_med);
reparsed = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent full and reparse
serializer.setIndentMode(QJson::IndentFull);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_full);
reparsed = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
}
void TestSerializer::testIndentation_data()
{
QTest::addColumn<QByteArray>( "json" );
QTest::addColumn<QByteArray>( "expected_compact" );
QTest::addColumn<QByteArray>( "expected_min" );
QTest::addColumn<QByteArray>( "expected_med" );
QTest::addColumn<QByteArray>( "expected_full" );
const QByteArray json = " { \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [ { \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0 }, { \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1 } ], \"foo3\" : [ 1, 2, 3, 4, 5, 6 ] }";
const QByteArray ex_compact = "{\"foo\":0,\"foo1\":1,\"foo2\":[{\"bar\":1,\"foo\":0,\"foobar\":0},{\"bar\":1,\"foo\":1,\"foobar\":1}],\"foo3\":[1,2,3,4,5,6]}";
const QByteArray ex_min = "{ \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [\n { \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0 },\n { \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1 }\n ], \"foo3\" : [\n 1,\n 2,\n 3,\n 4,\n 5,\n 6\n ] }";
const QByteArray ex_med = "{\n \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [\n {\n \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0\n },\n {\n \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1\n }\n ], \"foo3\" : [\n 1,\n 2,\n 3,\n 4,\n 5,\n 6\n ]\n}";
const QByteArray ex_full = "{\n \"foo\" : 0,\n \"foo1\" : 1,\n \"foo2\" : [\n {\n \"bar\" : 1,\n \"foo\" : 0,\n \"foobar\" : 0\n },\n {\n \"bar\" : 1,\n \"foo\" : 1,\n \"foobar\" : 1\n }\n ],\n \"foo3\" : [\n 1,\n 2,\n 3,\n 4,\n 5,\n 6\n ]\n}";
QTest::newRow( "test indents" ) << json << ex_compact << ex_min << ex_med << ex_full;
}
void TestSerializer::valueTest( const QVariant& value, const QString& expectedRegExp, bool errorExpected )
{
Serializer serializer;
bool ok;
const QByteArray serialized = serializer.serialize( value, &ok);
QCOMPARE(ok, !errorExpected);
QCOMPARE(serialized.isNull(), errorExpected);
const QString serializedUnicode = QString::fromUtf8( serialized );
if (!errorExpected) {
QRegExp expected( expectedRegExp );
QVERIFY( expected.isValid() );
QVERIFY2( expected.exactMatch( serializedUnicode ),
qPrintable( QString( QLatin1String( "Expected regexp \"%1\" but got \"%2\"." ) )
.arg( expectedRegExp ).arg( serializedUnicode ) ) );
} else {
QVERIFY(!serializer.errorMessage().isEmpty());
}
}
void TestSerializer::valueTest( const QObject* object, const QString& expectedRegExp )
{
Serializer serializer;
bool ok;
const QByteArray serialized = serializer.serialize( object, &ok);
QVERIFY(ok);
const QString serializedUnicode = QString::fromUtf8( serialized );
QRegExp expected( expectedRegExp );
QVERIFY( expected.isValid() );
QVERIFY2( expected.exactMatch( serializedUnicode ),
qPrintable( QString( QLatin1String( "Expected regexp \"%1\" but got \"%2\"." ) )
.arg( expectedRegExp ).arg( serializedUnicode ) ) );
}
void TestSerializer::testValueNull()
{
valueTest( QVariant(), QLatin1String( "\\s*null\\s*" ) );
QVariantMap map;
map[QLatin1String("value")] = QVariant();
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:\\s*null\\s*\\}\\s*" ) );
}
void TestSerializer::testValueString()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueString_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "null string" ) << QVariant( QString() ) << QString( QLatin1String( "\\s*\"\"\\s*" ) );
QTest::newRow( "empty string" ) << QVariant( QString( QLatin1String( "" ) ) ) << QString( QLatin1String( "\\s*\"\"\\s*" ) );
QTest::newRow( "Simple String" ) << QVariant( QString( QLatin1String( "simpleString" ) ) ) << QString( QLatin1String( "\\s*\"simpleString\"\\s*" ) );
QTest::newRow( "string with tab" ) << QVariant( QString( QLatin1String( "string\tstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\tstring\"\\s*" ) );
QTest::newRow( "string with newline" ) << QVariant( QString( QLatin1String( "string\nstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\nstring\"\\s*" ) );
QTest::newRow( "string with bell" ) << QVariant( QString( QLatin1String( "string\bstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\bstring\"\\s*" ) );
QTest::newRow( "string with return" ) << QVariant( QString( QLatin1String( "string\rstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\rstring\"\\s*" ) );
QTest::newRow( "string with double quote" ) << QVariant( QString( QLatin1String( "string\"string" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\\"string\"\\s*" ) );
QTest::newRow( "string with backslash" ) << QVariant( QString( QLatin1String( "string\\string" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\\\\\string\"\\s*" ) );
QString testStringWithUnicode = QString( QLatin1String( "string" ) ) + QChar( 0x2665 ) + QLatin1String( "string" );
QString testEscapedString = QString( QLatin1String( "string" ) ) + QLatin1String("\\\\u2665") + QLatin1String( "string" );
QTest::newRow( "string with unicode" ) << QVariant( testStringWithUnicode ) << QLatin1String( "\\s*\"" ) + testEscapedString + QLatin1String( "\"\\s*" );
}
void TestSerializer::testValueStringList()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueStringList_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QStringList stringlist;
QString expected;
// simple QStringList
stringlist << QLatin1String("hello") << QLatin1String("world");
expected = QLatin1String( "\\s*\\[\\s*\"hello\"\\s*,\\s*\"world\"\\s*\\]\\s*" );
QTest::newRow( "simple QStringList" ) << QVariant( stringlist) << expected;
}
void TestSerializer::testValueInteger()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueInteger_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "int 0" ) << QVariant( static_cast<int>( 0 ) ) << QString( QLatin1String( "\\s*0\\s*" ) );
QTest::newRow( "uint 0" ) << QVariant( static_cast<uint>( 0 ) ) << QString( QLatin1String( "\\s*0\\s*" ) );
QTest::newRow( "int -1" ) << QVariant( static_cast<int>( -1 ) ) << QString( QLatin1String( "\\s*-1\\s*" ) );
QTest::newRow( "int 2133149800" ) << QVariant( static_cast<int>(2133149800) ) << QString( QLatin1String( "\\s*2133149800\\s*" ) );
QTest::newRow( "uint 4133149800" ) << QVariant( static_cast<uint>(4133149800u) ) << QString( QLatin1String( "\\s*4133149800\\s*" ) );
QTest::newRow( "uint64 932838457459459" ) << QVariant( Q_UINT64_C(932838457459459) ) << QString( QLatin1String( "\\s*932838457459459\\s*" ) );
QTest::newRow( "max unsigned long long" ) << QVariant( std::numeric_limits<unsigned long long>::max() ) << QString( QLatin1String( "\\s*%1\\s*" ) ).arg(std::numeric_limits<unsigned long long>::max());
}
void TestSerializer::testValueDouble()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
QFETCH( bool, errorExpected );
valueTest( value, expected, errorExpected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ), errorExpected );
}
void TestSerializer::testValueDouble_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::addColumn<bool>( "errorExpected" );
QTest::newRow( "double 0" ) << QVariant( 0.0 ) << QString( QLatin1String( "\\s*0.0\\s*" ) ) << false;
QTest::newRow( "double -1" ) << QVariant( -1.0 ) << QString( QLatin1String( "\\s*-1.0\\s*" ) ) << false;
QTest::newRow( "double 1.5E-20" ) << QVariant( 1.5e-20 ) << QString( QLatin1String( "\\s*1.5[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double -1.5E-20" ) << QVariant( -1.5e-20 ) << QString( QLatin1String( "\\s*-1.5[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double 2.0E-20" ) << QVariant( 2.0e-20 ) << QString( QLatin1String( "\\s*2(?:.0)?[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double infinity" ) << QVariant( std::numeric_limits< double >::infinity() ) << QString( ) << true;
QTest::newRow( "double -infinity" ) << QVariant( -std::numeric_limits< double >::infinity() ) << QString( ) << true;
QTest::newRow( "double NaN" ) << QVariant( std::numeric_limits< double >::quiet_NaN() ) << QString( ) << true;
}
void TestSerializer::testSetDoublePrecision()
{
bool ok;
Serializer serializer;
QByteArray actual;
QString expected, actualUnicode;
double num = 0.12345678;
// Set 1 as double precision
serializer.setDoublePrecision(1);
expected = QString(QLatin1String("0.1"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 2 as double precision
serializer.setDoublePrecision(2);
expected = QString(QLatin1String("0.12"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 4 as double precision
serializer.setDoublePrecision(4);
expected = QString(QLatin1String("0.1235"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 14 as double precision
serializer.setDoublePrecision(14);
expected = QString(QLatin1String("0.12345678"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
}
void TestSerializer::testValueFloat()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
QFETCH( bool, errorExpected );
valueTest( value, expected, errorExpected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ), errorExpected );
}
void TestSerializer::testValueFloat_data()
{
QVariant v;
float value;
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::addColumn<bool>( "errorExpected" );
value = 0;
v.setValue(value);
QTest::newRow( "float 0" ) << v << QString( QLatin1String( "\\s*0.0\\s*" ) ) << false;
value = -1;
v.setValue(value);
QTest::newRow( "float -1" ) << v << QString( QLatin1String( "\\s*-1.0\\s*" ) ) << false;
value = 1.12f;
v.setValue(value);
QTest::newRow( "float 1.12" ) << v << QString( QLatin1String( "\\s*1.12\\s*" ) ) << false;
}
void TestSerializer::testValueBoolean()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueBoolean_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "bool false" ) << QVariant( false ) << QString( QLatin1String( "\\s*false\\s*" ) );
QTest::newRow( "bool true" ) << QVariant( true ) << QString( QLatin1String( "\\s*true\\s*" ) );
}
void TestSerializer::testSpecialNumbers() {
bool ok;
QFETCH( QVariant, value );
QFETCH( QString, expected );
Serializer specialSerializer;
QVERIFY(!specialSerializer.specialNumbersAllowed());
specialSerializer.allowSpecialNumbers(true);
QVERIFY(specialSerializer.specialNumbersAllowed());
QByteArray serialized = specialSerializer.serialize(value, &ok);
QVERIFY(ok);
QCOMPARE(QString::fromLocal8Bit(serialized), expected);
}
void TestSerializer::testSpecialNumbers_data() {
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "Infinity" ) << QVariant( std::numeric_limits< double >::infinity() ) << QString::fromLocal8Bit("Infinity");
QTest::newRow( "-Infinity" ) << QVariant( -std::numeric_limits< double >::infinity() ) << QString::fromLocal8Bit("-Infinity");
QTest::newRow( "Infinity" ) << QVariant( std::numeric_limits< double >::quiet_NaN() ) << QString::fromLocal8Bit("NaN");
}
void TestSerializer::testSerializetoQIODevice() {
QBuffer buffer;
QVariantList variant;
variant << QVariant(QLatin1String("Hello"));
variant << QVariant(QLatin1String("world!"));
Serializer serializer;
bool ok;
serializer.serialize(variant, &buffer, &ok);
QCOMPARE(QString(QLatin1String(buffer.data())),
QString(QLatin1String("[ \"Hello\", \"world!\" ]")));
QVERIFY(ok);
}
void TestSerializer::testSerializeWithoutOkParam() {
QBuffer buffer;
QVariantList variant;
variant << QVariant(QLatin1String("Hello"));
variant << QVariant(QLatin1String("world!"));
Serializer serializer;
const QByteArray serialized = serializer.serialize(variant);
const QByteArray expected = "[ \"Hello\", \"world!\" ]";
QCOMPARE(expected, serialized);
// test a serialization which produces an error
QVariant brokenVariant ( std::numeric_limits< double >::quiet_NaN() );
QVERIFY(serializer.serialize(brokenVariant).isEmpty());
}
void TestSerializer::testValueHashMap()
{
Serializer serializer;
bool ok;
QVariantHash hash;
hash[QLatin1String("one")] = 1;
hash[QLatin1String("three")] = 3;
hash[QLatin1String("seven")] = 7;
QByteArray json = serializer.serialize(hash, &ok);
QVERIFY(ok);
Parser parser;
QVariant var = parser.parse(json, &ok);
QVERIFY(ok);
QVariantMap vmap = var.toMap();
QHashIterator<QString, QVariant> hIt( hash );
while ( hIt.hasNext() ) {
hIt.next();
QString key = hIt.key();
QVariant value = hIt.value();
QMap<QString, QVariant>::const_iterator mIt = vmap.constFind(key);
QVERIFY(mIt != vmap.constEnd());
QCOMPARE(mIt.value(), value);
}
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestSerializer)
#include "moc_testserializer.cxx"
#else
QTEST_GUILESS_MAIN(TestSerializer)
#include "testserializer.moc"
#endif