reimplement QJsonDocument via Jansson

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2021-02-11 01:36:04 +02:00
parent 62371e5749
commit 31f76bdcd1
43 changed files with 2185 additions and 8884 deletions

View file

@ -215,6 +215,15 @@ set_package_properties(ZSTD PROPERTIES
TYPE REQUIRED
)
# v2.0+ required for json_loads() with three arguments
find_package(Jansson 2.0)
set_package_properties(Jansson PROPERTIES
PURPOSE "Required for JSON support"
DESCRIPTION "C library for encoding, decoding and manipulating JSON data"
URL "https://github.com/akheron/jansson"
TYPE REQUIRED
)
# v0.9.8+ required for SHA-224...SHA-512 support
find_package(OpenSSL 0.9.8)
set_package_properties(OpenSSL PROPERTIES
@ -742,7 +751,6 @@ katie_generate_obsolete(QItemEditorCreatorBase QtGui qitemeditorfactory.h)
katie_generate_obsolete(QItemEditorCreator QtGui qitemeditorfactory.h)
katie_generate_obsolete(QItemSelection QtGui qitemselectionmodel.h)
katie_generate_obsolete(QItemSelectionRange QtGui qitemselectionmodel.h)
katie_generate_obsolete(QJsonParseError QtCore qjsondocument.h)
katie_generate_obsolete(QKeyEvent QtGui qevent.h)
katie_generate_obsolete(QLatin1Char QtCore qchar.h)
katie_generate_obsolete(QLatin1String QtCore qstring.h)

View file

@ -12,7 +12,7 @@ build_script:
sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev libc6-dev libpng-dev \
libjpeg-dev libtiff-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev \
libicu-dev unixodbc-dev libpq-dev libmariadbclient-dev libmariadbd-dev liblz4-dev \
libsqlite3-dev xorg-dev dbus-x11
libsqlite3-dev xorg-dev dbus-x11 libjansson-dev
cmake . -Wno-dev -DKATIE_TESTS=ON -DKATIE_BENCHMARKS=ON -DKATIE_UTILS=ON -DKATIE_PCH=ON -DCMAKE_UNITY_BUILD=ON

View file

@ -0,0 +1,32 @@
# - Try to find Jansson
# Once done this will define
#
# JANSSON_FOUND - system has Jansson
# JANSSON_INCLUDES - the Jansson include directory
# JANSSON_LIBRARIES - the libraries needed to use Jansson
#
# Copyright (C) 2021, Ivailo Monev, <xakepa10@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
include(FindPkgConfig)
include(FindPackageHandleStandardArgs)
pkg_check_modules(PC_JANSSON QUIET jansson)
find_path(JANSSON_INCLUDES
NAMES jansson.h
HINTS $ENV{JANSSONDIR}/include ${PC_JANSSON_INCLUDEDIR}
)
find_library(JANSSON_LIBRARIES
NAMES jansson
HINTS $ENV{JANSSONDIR}/lib ${PC_JANSSON_LIBDIR}
)
find_package_handle_standard_args(Jansson
VERSION_VAR PC_JANSSON_VERSION
REQUIRED_VARS JANSSON_LIBRARIES JANSSON_INCLUDES
)
mark_as_advanced(JANSSON_INCLUDES JANSSON_LIBRARIES)

View file

@ -10,8 +10,8 @@ pkgdesc='C++ toolkit derived from the Qt 4.8 framework'
arch=('i486' 'i686' 'pentium4' 'x86_64' 'arm')
url='https://github.com/fluxer/katie'
license=('LGPL' 'BSD')
depends=('libsm' 'libxcursor' 'libxinerama' 'icu' 'libcups' 'libxrandr' 'sqlite' 'fontconfig'
'xdg-utils')
depends=('libsm' 'libxcursor' 'libxinerama' 'icu' 'libcups' 'libxrandr' 'sqlite'
'fontconfig' 'xdg-utils' 'jansson')
makedepends=('cmake' 'git' 'postgresql' 'mariadb-libs' 'unixodbc' 'unifdef')
optdepends=('postgresql-libs: PostgreSQL driver'
'mariadb-libs: MariaDB driver'

View file

@ -6,11 +6,12 @@ Vcs-Git: git://github.com/fluxer/katie.git
Vcs-browser: https://github.com/fluxer/katie
Standards-Version: 4.10.0
Build-Depends: debhelper (>= 9~), libssl-dev, zlib1g-dev, libzstd-dev,
libc6-dev, libpng-dev, libjpeg-dev, libtiff5-dev, libcups2-dev,
libfreetype6-dev, libfontconfig1-dev, libpcre3-dev, libdbus-1-dev,
unixodbc-dev, libicu-dev, libsqlite3-dev, cmake, git, xserver-xorg-dev,
libxinerama-dev, libxrandr-dev, libxrender-dev, libxcursor-dev, libsm-dev,
libpq-dev, libmariadbclient-dev, libmariadbd-dev, unifdef | dpkg
libc6-dev, libjansson-dev, libpng-dev, libjpeg-dev, libtiff5-dev,
libcups2-dev, libfreetype6-dev, libfontconfig1-dev, libpcre3-dev,
libdbus-1-dev, unixodbc-dev, libicu-dev, libsqlite3-dev, cmake, git,
xserver-xorg-dev, libxinerama-dev, libxrandr-dev, libxrender-dev,
libxcursor-dev, libsm-dev, libpq-dev, libmariadbclient-dev, libmariadbd-dev,
unifdef | dpkg
Package: katie-runtime
Architecture: amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x hurd-i386

View file

@ -7,7 +7,7 @@ Summary: C++ toolkit derived from the Qt 4.8 framework
License: BSD and LGPLv2+
URL: https://github.com/fluxer/katie
BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel zlib-devel libsq3-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel libtiff-devel libjpeg-turbo-devel fontconfig-devel cups-devel libiodbc-devel libpq-devel mariadb-embedded-devel unifdef
BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel jansson-devel zlib-devel libsq3-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel libtiff-devel libjpeg-turbo-devel fontconfig-devel cups-devel libiodbc-devel libpq-devel mariadb-embedded-devel unifdef
Requires: xdg-utils
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig

View file

@ -19,10 +19,12 @@ USES = compiler:c++11-lang pkgconfig cmake ssl xorg sqlite:3 desktop-file-utils
USE_XORG = xinerama xrandr xrender xfixes xcursor xext sm ice
USE_LDCONFIG = yes
RUN_DEPENDS = xdg-open:devel/xdg-utils
LIB_DEPENDS = libzstd.so:archivers/zstd libicuuc.so:devel/icu libicui18n.so:devel/icu \
libpcre.so:devel/pcre libpng.so:graphics/png libjpeg.so:graphics/jpeg-turbo \
libtiff.so:graphics/tiff libfreetype.so:print/freetype2 \
libfontconfig.so:x11-fonts/fontconfig libdbus-1.so:devel/dbus libcups.so:print/cups \
LIB_DEPENDS = libzstd.so:archivers/zstd libicuuc.so:devel/icu \
libicui18n.so:devel/icu libjansson.so:devel/jansson \
libpcre.so:devel/pcre libpng.so:graphics/png \
libjpeg.so:graphics/jpeg-turbo libtiff.so:graphics/tiff \
libfreetype.so:print/freetype2 libfontconfig.so:x11-fonts/fontconfig \
libdbus-1.so:devel/dbus libcups.so:print/cups \
libiodbc.so:databases/libiodbc
CMAKE_ARGS = -DKATIE_TOOLS_SUFFIX="-katie"

View file

@ -71,11 +71,7 @@ include/katie/QtCore/QHashNode
include/katie/QtCore/QIODevice
include/katie/QtCore/QIncompatibleFlag
include/katie/QtCore/QInternal
include/katie/QtCore/QJsonArray
include/katie/QtCore/QJsonDocument
include/katie/QtCore/QJsonObject
include/katie/QtCore/QJsonParseError
include/katie/QtCore/QJsonValue
include/katie/QtCore/QLatin1Char
include/katie/QtCore/QLatin1String
include/katie/QtCore/QLibrary
@ -256,10 +252,7 @@ include/katie/QtCore/qglobal.h
include/katie/QtCore/qhash.h
include/katie/QtCore/qiodevice.h
include/katie/QtCore/qiterator.h
include/katie/QtCore/qjsonarray.h
include/katie/QtCore/qjsondocument.h
include/katie/QtCore/qjsonobject.h
include/katie/QtCore/qjsonvalue.h
include/katie/QtCore/qlibrary.h
include/katie/QtCore/qlibraryinfo.h
include/katie/QtCore/qline.h

View file

@ -26,6 +26,7 @@ DEPENDS = xdg-utils-[0-9]*:../../misc/xdg-utils
.include "../../sysutils/desktop-file-utils/desktopdb.mk"
.include "../../archivers/zstd/buildlink3.mk"
.include "../../textproc/jansson/buildlink3.mk"
.include "../../textproc/icu/buildlink3.mk"
.include "../../devel/pcre/buildlink3.mk"
.include "../../devel/zlib/buildlink3.mk"

View file

@ -74,11 +74,7 @@ include/katie/QtCore/QHashNode
include/katie/QtCore/QIODevice
include/katie/QtCore/QIncompatibleFlag
include/katie/QtCore/QInternal
include/katie/QtCore/QJsonArray
include/katie/QtCore/QJsonDocument
include/katie/QtCore/QJsonObject
include/katie/QtCore/QJsonParseError
include/katie/QtCore/QJsonValue
include/katie/QtCore/QLatin1Char
include/katie/QtCore/QLatin1String
include/katie/QtCore/QLibrary
@ -259,10 +255,7 @@ include/katie/QtCore/qglobal.h
include/katie/QtCore/qhash.h
include/katie/QtCore/qiodevice.h
include/katie/QtCore/qiterator.h
include/katie/QtCore/qjsonarray.h
include/katie/QtCore/qjsondocument.h
include/katie/QtCore/qjsonobject.h
include/katie/QtCore/qjsonvalue.h
include/katie/QtCore/qlibrary.h
include/katie/QtCore/qlibraryinfo.h
include/katie/QtCore/qline.h

View file

@ -21,9 +21,9 @@ COMPILER = base-clang ports-gcc
MODULES = devel/cmake
BUILD_DEPENDS = devel/gettext,-tools
RUN_DEPENDS = devel/desktop-file-utils devel/xdg-utils
LIB_DEPENDS = archivers/zstd textproc/icu4c devel/pcre graphics/png \
graphics/jpeg graphics/tiff x11/dbus print/cups,-libs databases/iodbc \
databases/sqlite3 devel/gettext,-runtime
LIB_DEPENDS = archivers/zstd textproc/icu4c devel/jansson devel/pcre \
graphics/png graphics/jpeg graphics/tiff x11/dbus print/cups,-libs \
databases/iodbc databases/sqlite3 devel/gettext,-runtime
WANTLIB = ${COMPILER_LIBCXX} ICE SM X11 Xcursor Xext Xfixes Xinerama Xrandr \
Xrender fontconfig freetype zstd icui18n icuuc pcre png jpeg tiff \
dbus-1 cups iodbc sqlite3 intl ssl z c crypto m

View file

@ -74,11 +74,7 @@ include/katie/QtCore/QHashNode
include/katie/QtCore/QIODevice
include/katie/QtCore/QIncompatibleFlag
include/katie/QtCore/QInternal
include/katie/QtCore/QJsonArray
include/katie/QtCore/QJsonDocument
include/katie/QtCore/QJsonObject
include/katie/QtCore/QJsonParseError
include/katie/QtCore/QJsonValue
include/katie/QtCore/QLatin1Char
include/katie/QtCore/QLatin1String
include/katie/QtCore/QLibrary
@ -259,10 +255,7 @@ include/katie/QtCore/qglobal.h
include/katie/QtCore/qhash.h
include/katie/QtCore/qiodevice.h
include/katie/QtCore/qiterator.h
include/katie/QtCore/qjsonarray.h
include/katie/QtCore/qjsondocument.h
include/katie/QtCore/qjsonobject.h
include/katie/QtCore/qjsonvalue.h
include/katie/QtCore/qlibrary.h
include/katie/QtCore/qlibraryinfo.h
include/katie/QtCore/qline.h

View file

@ -36,7 +36,6 @@ incmap = {
'QHashNode': 'qhash.h',
'QIncompatibleFlag': 'qglobal.h',
'QInternal': 'qnamespace.h',
'QJsonParseError': 'qjsondocument.h',
'QLatin1Char': 'qchar.h',
'QLatin1String': 'qstring.h',
'QLineF': 'qline.h',

View file

@ -362,11 +362,7 @@ classlist = [
"QItemSelection",
"QItemSelectionModel",
"QItemSelectionRange",
"QJsonArray",
"QJsonDocument",
"QJsonObject",
"QJsonParseError",
"QJsonValue",
"QKeyEvent",
"QKeySequence",
"QLabel",

View file

@ -3,6 +3,7 @@ set(EXTRA_CORE_LIBS
${ZLIB_LIBRARIES}
${ICU_LIBRARIES}
${ZSTD_LIBRARIES}
${JANSSON_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
# libm should be present by default becaue this is C++
m
@ -101,10 +102,7 @@ set(CORE_PUBLIC_HEADERS
QBasicTimer
QThread
QSocketNotifier
QJsonArray
QJsonDocument
QJsonObject
QJsonValue
)
include_directories(
@ -114,6 +112,7 @@ include_directories(
${ZLIB_INCLUDE_DIRS}
${ICU_INCLUDES}
${ZSTD_INCLUDES}
${JANSSON_INCLUDES}
)
set(CORE_HEADERS
@ -188,13 +187,6 @@ set(CORE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/io/qfilesystemengine_p.h
${CMAKE_CURRENT_SOURCE_DIR}/io/qfilesystemmetadata_p.h
${CMAKE_CURRENT_SOURCE_DIR}/io/qfilesystemiterator_p.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonarray.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsondocument.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonobject.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonparser_p.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjson_p.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonvalue.h
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonwriter_p.h
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qabstracteventdispatcher.h
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qabstractitemmodel.h
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qabstractitemmodel_p.h
@ -255,6 +247,7 @@ set(CORE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/tools/qdatetime_p.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qeasingcurve.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qhash.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qjsondocument.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qline.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qlinkedlist.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/qlist.h
@ -339,13 +332,6 @@ set(CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/io/qprocess_unix.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io/qfilesystemiterator_unix.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io/qstandardpaths_unix.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonarray.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjson.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsondocument.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonobject.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonparser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonvalue.cpp
${CMAKE_CURRENT_SOURCE_DIR}/json/qjsonwriter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qabstracteventdispatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qabstractitemmodel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/kernel/qbasictimer.cpp
@ -390,6 +376,7 @@ set(CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/tools/qeasingcurve.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qelapsedtimer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qhash.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qjsondocument.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qline.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qlinkedlist.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/qlist.cpp

View file

@ -23,7 +23,6 @@
#include "qplatformdefs.h"
#include "qsettings.h"
#include "qjsondocument.h"
#include "qjsonobject.h"
#include "qstandardpaths.h"
#include "qmutex.h"
#include "qcoreapplication.h"
@ -63,14 +62,13 @@ static bool json_settings_read(QIODevice &device, QSettings::SettingsMap &map)
return false;
}
QJsonParseError error;
QJsonDocument jsondoc = QJsonDocument::fromJson(data, &error);
QJsonDocument jsondoc = QJsonDocument::fromJson(data);
if (Q_UNLIKELY(jsondoc.isNull())) {
qWarning("json_settings_read: %s", error.errorString().toUtf8().constData());
qWarning("json_settings_read: %s", jsondoc.errorString().toUtf8().constData());
return false;
}
map = jsondoc.object().toVariantMap();
map = jsondoc.toVariant().toMap();
// qDebug() << "json_settings_read" << jsondoc.toJson();
return true;
@ -78,7 +76,7 @@ static bool json_settings_read(QIODevice &device, QSettings::SettingsMap &map)
static bool json_settings_write(QIODevice &device, const QSettings::SettingsMap &map)
{
QJsonDocument jsondoc = QJsonDocument(QJsonObject::fromVariantMap(map));
QJsonDocument jsondoc = QJsonDocument::fromVariant(map);
QByteArray jsondata = jsondoc.toJson();
if (Q_UNLIKELY(jsondoc.isNull() || jsondata.isNull())) {
return false;

View file

@ -1,438 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjson_p.h"
#include "qalgorithms.h"
QT_BEGIN_NAMESPACE
namespace QJsonPrivate {
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
#define Q_TO_LITTLE_ENDIAN(x) (x)
#else
#define Q_TO_LITTLE_ENDIAN(x) ( ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
#endif
static const Base emptyArray = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
static const Base emptyObject = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
void Data::compact()
{
Q_ASSERT(sizeof(Value) == sizeof(offset));
if (!compactionCounter) {
return;
}
Base *base = header->root();
int reserve = 0;
if (base->is_object) {
Object *o = static_cast<Object *>(base);
for (int i = 0; i < (int)o->length; ++i) {
reserve += o->entryAt(i)->usedStorage(o);
}
} else {
Array *a = static_cast<Array *>(base);
for (int i = 0; i < (int)a->length; ++i) {
reserve += (*a)[i].usedStorage(a);
}
}
int size = sizeof(Base) + reserve + base->length * sizeof(offset);
int alloc = sizeof(Header) + size;
Header *h = (Header *) malloc(alloc);
h->tag = QJsonDocument::BinaryFormatTag;
h->version = 1;
Base *b = h->root();
b->size = size;
b->is_object = header->root()->is_object;
b->length = base->length;
b->tableOffset = reserve + sizeof(Array);
int offset = sizeof(Base);
if (b->is_object) {
Object *o = static_cast<Object *>(base);
Object *no = static_cast<Object *>(b);
for (int i = 0; i < (int)o->length; ++i) {
no->table()[i] = offset;
const Entry *e = o->entryAt(i);
Entry *ne = no->entryAt(i);
int s = e->size();
memcpy(ne, e, s);
offset += s;
int dataSize = e->value.usedStorage(o);
if (dataSize) {
memcpy((char *)no + offset, e->value.data(o), dataSize);
ne->value.value = offset;
offset += dataSize;
}
}
} else {
Array *a = static_cast<Array *>(base);
Array *na = static_cast<Array *>(b);
for (int i = 0; i < (int)a->length; ++i) {
const Value &v = (*a)[i];
Value &nv = (*na)[i];
nv = v;
int dataSize = v.usedStorage(a);
if (dataSize) {
memcpy((char *)na + offset, v.data(a), dataSize);
nv.value = offset;
offset += dataSize;
}
}
}
Q_ASSERT(offset == (int)b->tableOffset);
free(header);
header = h;
this->alloc = alloc;
compactionCounter = 0;
}
bool Data::valid() const
{
if (header->tag != QJsonDocument::BinaryFormatTag || header->version != 1u) {
return false;
}
bool res = false;
if (header->root()->is_object) {
res = static_cast<Object *>(header->root())->isValid();
} else {
res = static_cast<Array *>(header->root())->isValid();
}
return res;
}
int Base::reserveSpace(uint dataSize, int posInTable, uint numItems, bool replace)
{
Q_ASSERT(posInTable >= 0 && posInTable <= (int)length);
if (size + dataSize >= Value::MaxSize) {
qWarning("QJson: Document too large to store in data structure %d %d %d", (uint)size, dataSize, Value::MaxSize);
return 0;
}
offset off = tableOffset;
// move table to new position
if (replace) {
memmove((char *)(table()) + dataSize, table(), length * sizeof(offset));
} else {
memmove((char *)(table() + posInTable + numItems) + dataSize, table() + posInTable,
(length - posInTable)*sizeof(offset));
memmove((char *)(table()) + dataSize, table(), posInTable * sizeof(offset));
}
tableOffset += dataSize;
for (int i = 0; i < (int)numItems; ++i) {
table()[posInTable + i] = off;
}
size += dataSize;
if (!replace) {
length += numItems;
size += numItems * sizeof(offset);
}
return off;
}
void Base::removeItems(int pos, int numItems)
{
Q_ASSERT(pos >= 0 && pos <= (int)length);
if (pos + numItems < (int)length) {
memmove(table() + pos, table() + pos + numItems, (length - pos - numItems)*sizeof(offset));
}
length -= numItems;
}
int Object::indexOf(const QString &key, bool *exists)
{
int min = 0;
int n = length;
while (n > 0) {
int half = n >> 1;
int middle = min + half;
if (*entryAt(middle) >= key) {
n = half;
} else {
min = middle + 1;
n -= half + 1;
}
}
if (min < (int)length && *entryAt(min) == key) {
*exists = true;
return min;
}
*exists = false;
return min;
}
bool Object::isValid() const
{
if (tableOffset + length * sizeof(offset) > size) {
return false;
}
for (uint i = 0; i < length; ++i) {
offset entryOffset = table()[i];
if (entryOffset + sizeof(Entry) >= tableOffset) {
return false;
}
Entry *e = entryAt(i);
int s = e->size();
if (table()[i] + s > tableOffset) {
return false;
}
if (!e->value.isValid(this)) {
return false;
}
}
return true;
}
bool Array::isValid() const
{
if (tableOffset + length * sizeof(offset) > size) {
return false;
}
for (uint i = 0; i < length; ++i) {
if (!at(i).isValid(this)) {
return false;
}
}
return true;
}
bool Entry::operator ==(const QString &key) const
{
if (value.latinKey) {
return (shallowLatin1Key() == key);
} else {
return (shallowKey() == key);
}
}
bool Entry::operator ==(const Entry &other) const
{
if (value.latinKey) {
if (other.value.latinKey) {
return shallowLatin1Key() == other.shallowLatin1Key();
}
return shallowLatin1Key() == other.shallowKey();
} else if (other.value.latinKey) {
return shallowKey() == other.shallowLatin1Key();
}
return shallowKey() == other.shallowKey();
}
bool Entry::operator >=(const Entry &other) const
{
if (value.latinKey) {
if (other.value.latinKey) {
return shallowLatin1Key() >= other.shallowLatin1Key();
}
return shallowLatin1Key() >= other.shallowKey();
} else if (other.value.latinKey) {
return shallowKey() >= other.shallowLatin1Key();
}
return shallowKey() >= other.shallowKey();
}
int Value::usedStorage(const Base *b) const
{
int s = 0;
switch (type) {
case QJsonValue::Double:
if (latinOrIntValue) {
break;
}
s = sizeof(double);
break;
case QJsonValue::String: {
char *d = data(b);
if (latinOrIntValue) {
s = sizeof(ushort) + qFromLittleEndian(*(ushort *)d);
} else {
s = sizeof(int) + sizeof(ushort) * qFromLittleEndian(*(int *)d);
}
break;
}
case QJsonValue::Array:
case QJsonValue::Object:
s = base(b)->size;
break;
case QJsonValue::Null:
case QJsonValue::Bool:
default:
break;
}
return alignedSize(s);
}
bool Value::isValid(const Base *b) const
{
int offset = 0;
switch (type) {
case QJsonValue::Double:
if (latinOrIntValue) {
break;
}
// fall through
case QJsonValue::String:
case QJsonValue::Array:
case QJsonValue::Object:
offset = value;
break;
case QJsonValue::Null:
case QJsonValue::Bool:
default:
break;
}
if (!offset) {
return true;
}
if (offset + sizeof(uint) > b->tableOffset) {
return false;
}
int s = usedStorage(b);
if (!s) {
return true;
}
if (s < 0 || offset + s > (int)b->tableOffset) {
return false;
}
if (type == QJsonValue::Array) {
return static_cast<Array *>(base(b))->isValid();
}
if (type == QJsonValue::Object) {
return static_cast<Object *>(base(b))->isValid();
}
return true;
}
/*!
\internal
*/
int Value::requiredStorage(QJsonValue &v, bool *compressed)
{
*compressed = false;
switch (v.t) {
case QJsonValue::Double:
if (QJsonPrivate::compressedNumber(v.dbl) != INT_MAX) {
*compressed = true;
return 0;
}
return sizeof(double);
case QJsonValue::String: {
QString s = v.toString();
*compressed = QJsonPrivate::useCompressed(s);
return QJsonPrivate::qStringSize(s, *compressed);
}
case QJsonValue::Array:
case QJsonValue::Object:
if (v.d && v.d->compactionCounter) {
v.detach();
v.d->compact();
v.base = static_cast<QJsonPrivate::Base *>(v.d->header->root());
}
return v.base ? v.base->size : sizeof(QJsonPrivate::Base);
case QJsonValue::Undefined:
case QJsonValue::Null:
case QJsonValue::Bool:
break;
}
return 0;
}
/*!
\internal
*/
uint Value::valueToStore(const QJsonValue &v, uint offset)
{
switch (v.t) {
case QJsonValue::Undefined:
case QJsonValue::Null:
break;
case QJsonValue::Bool:
return v.b;
case QJsonValue::Double: {
int c = QJsonPrivate::compressedNumber(v.dbl);
if (c != INT_MAX) {
return c;
}
}
// fall through
case QJsonValue::String:
case QJsonValue::Array:
case QJsonValue::Object:
return offset;
}
return 0;
}
/*!
\internal
*/
void Value::copyData(const QJsonValue &v, char *dest, bool compressed)
{
switch (v.t) {
case QJsonValue::Double:
if (!compressed) {
qToLittleEndian(v.dbl, (uchar *)dest);
}
break;
case QJsonValue::String: {
QString str = v.toString();
QJsonPrivate::copyString(dest, str, compressed);
break;
}
case QJsonValue::Array:
case QJsonValue::Object: {
const QJsonPrivate::Base *b = v.base;
if (!b) {
b = (v.t == QJsonValue::Array ? &emptyArray : &emptyObject);
}
memcpy(dest, b, b->size);
break;
}
default:
break;
}
}
} // namespace QJsonPrivate
QT_END_NAMESPACE

View file

@ -1,849 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSON_P_H
#define QJSON_P_H
#include "qjsonobject.h"
#include "qjsonvalue.h"
#include "qjsondocument.h"
#include "qjsonarray.h"
#include "qatomic.h"
#include "qstring.h"
#include "qendian.h"
#include "qnumeric.h"
#include <limits.h>
#include <limits>
QT_BEGIN_NAMESPACE
/*
This defines a binary data structure for Json data. The data structure is optimised for fast reading
and minimum allocations. The whole data structure can be mmap'ed and used directly.
In most cases the binary structure is not as space efficient as a utf8 encoded text representation, but
much faster to access.
The size requirements are:
String:
Latin1 data: 2 bytes header + string.length()
Full Unicode: 4 bytes header + 2*(string.length())
Values: 4 bytes + size of data (size can be 0 for some data)
bool: 0 bytes
double: 8 bytes (0 if integer with less than 27bits)
string: see above
array: size of array
object: size of object
Array: 12 bytes + 4*length + size of Value data
Object: 12 bytes + 8*length + size of Key Strings + size of Value data
For an example such as
{ // object: 12 + 5*8 = 52
"firstName": "John", // key 12, value 8 = 20
"lastName" : "Smith", // key 12, value 8 = 20
"age" : 25, // key 8, value 0 = 8
"address" : // key 12, object below = 140
{ // object: 12 + 4*8
"streetAddress": "21 2nd Street", // key 16, value 16
"city" : "New York", // key 8, value 12
"state" : "NY", // key 8, value 4
"postalCode" : "10021" // key 12, value 8
}, // object total: 128
"phoneNumber": // key: 16, value array below = 172
[ // array: 12 + 2*4 + values below: 156
{ // object 12 + 2*8
"type" : "home", // key 8, value 8
"number": "212 555-1234" // key 8, value 16
}, // object total: 68
{ // object 12 + 2*8
"type" : "fax", // key 8, value 8
"number": "646 555-4567" // key 8, value 16
} // object total: 68
] // array total: 156
} // great total: 412 bytes
The uncompressed text file used roughly 500 bytes, so in this case we end up using about
the same space as the text representation.
Other measurements have shown a slightly bigger binary size than a compact text
representation where all possible whitespace was stripped out.
*/
namespace QJsonPrivate {
class Array;
class Object;
class Value;
class Entry;
template<typename T>
class q_littleendian
{
public:
T val;
q_littleendian &operator =(T i) {
val = qToLittleEndian(i);
return *this;
}
operator T() const {
return qFromLittleEndian(val);
}
bool operator ==(T i) {
return qFromLittleEndian(val) == i;
}
bool operator !=(T i) {
return qFromLittleEndian(val) != i;
}
bool operator ==(q_littleendian<T> i) {
return val == i.val;
}
bool operator !=(q_littleendian<T> i) {
return val != i.val;
}
bool operator <(T i) {
return qFromLittleEndian(val) < i;
}
bool operator >(T i) {
return qFromLittleEndian(val) > i;
}
bool operator <=(T i) {
return qFromLittleEndian(val) <= i;
}
bool operator >=(T i) {
return qFromLittleEndian(val) >= i;
}
q_littleendian &operator +=(T i) {
val = qToLittleEndian(qFromLittleEndian(val) + i);
return *this;
}
};
typedef q_littleendian<short> qle_short;
typedef q_littleendian<unsigned short> qle_ushort;
typedef q_littleendian<int> qle_int;
typedef q_littleendian<unsigned int> qle_uint;
template<int pos, int width>
class qle_bitfield
{
public:
uint val;
enum {
mask = ((1u << width) - 1) << pos
};
void operator =(uint t) {
uint i = qFromLittleEndian(val);
i &= ~mask;
i |= t << pos;
val = qToLittleEndian(i);
}
operator uint() const {
uint t = qFromLittleEndian(val);
t &= mask;
t >>= pos;
return t;
}
bool operator !() const {
return !operator uint();
}
bool operator ==(uint t) {
return uint(*this) == t;
}
bool operator !=(uint t) {
return uint(*this) != t;
}
bool operator <(uint t) {
return uint(*this) < t;
}
bool operator >(uint t) {
return uint(*this) > t;
}
bool operator <=(uint t) {
return uint(*this) <= t;
}
bool operator >=(uint t) {
return uint(*this) >= t;
}
qle_bitfield &operator +=(uint i) {
*this = (uint(*this) + i);
return *this;
}
qle_bitfield &operator -=(uint i) {
*this = (uint(*this) - i);
return *this;
}
};
template<int pos, int width>
class qle_signedbitfield
{
public:
uint val;
enum {
mask = ((1u << width) - 1) << pos
};
void operator =(int t) {
uint i = qFromLittleEndian(val);
i &= ~mask;
i |= t << pos;
val = qToLittleEndian(i);
}
operator int() const {
uint i = qFromLittleEndian(val);
i <<= 32 - width - pos;
int t = (int) i;
t >>= pos;
return t;
}
bool operator !() const {
return !operator int();
}
bool operator ==(int t) {
return int(*this) == t;
}
bool operator !=(int t) {
return int(*this) != t;
}
bool operator <(int t) {
return int(*this) < t;
}
bool operator >(int t) {
return int(*this) > t;
}
bool operator <=(int t) {
return int(*this) <= t;
}
bool operator >=(int t) {
return int(*this) >= t;
}
qle_signedbitfield &operator +=(int i) {
*this = (int(*this) + i);
return *this;
}
qle_signedbitfield &operator -=(int i) {
*this = (int(*this) - i);
return *this;
}
};
typedef qle_uint offset;
// round the size up to the next 4 byte boundary
inline int alignedSize(int size)
{
return (size + 3) & ~3;
}
static inline bool useCompressed(const QString &s)
{
if (s.length() >= 0x8000) {
return false;
}
const ushort *uc = (const ushort *)s.constData();
const ushort *e = uc + s.length();
while (uc < e) {
if (*uc > 0xff) {
return false;
}
++uc;
}
return true;
}
static inline int qStringSize(const QString &string, bool compress)
{
int l = 2 + string.length();
if (!compress) {
l *= 2;
}
return alignedSize(l);
}
// returns INT_MAX if it can't compress it into 28 bits
static inline int compressedNumber(double d)
{
// this relies on details of how ieee floats are represented
const int exponent_off = 52;
const quint64 fraction_mask = 0x000fffffffffffffull;
const quint64 exponent_mask = 0x7ff0000000000000ull;
quint64 val;
memcpy (&val, &d, sizeof(double));
int exp = (int)((val & exponent_mask) >> exponent_off) - 1023;
if (exp < 0 || exp > 25) {
return INT_MAX;
}
quint64 non_int = val & (fraction_mask >> exp);
if (non_int) {
return INT_MAX;
}
bool neg = (val >> 63);
val &= fraction_mask;
val |= ((quint64)1 << 52);
int res = (int)(val >> (52 - exp));
return neg ? -res : res;
}
class Latin1String;
class String
{
public:
String(const char *data) {
d = (Data *)data;
}
struct Data {
qle_int length;
qle_ushort utf16[1];
};
Data *d;
inline String &operator=(const QString &str) {
d->length = str.length();
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
const qle_ushort *uc = (const qle_ushort *)str.unicode();
for (int i = 0; i < str.length(); ++i) {
d->utf16[i] = uc[i];
}
#else
memcpy(d->utf16, str.unicode(), str.length()*sizeof(ushort));
#endif
if (str.length() & 1) {
d->utf16[str.length()] = 0;
}
return *this;
}
inline bool operator ==(const QString &str) const {
int slen = str.length();
int l = d->length;
if (slen != l) {
return false;
}
const ushort *s = (const ushort *)str.constData();
const qle_ushort *a = d->utf16;
const ushort *b = s;
while (l-- && *a == *b) {
a++, b++;
}
return (l == -1);
}
inline bool operator !=(const QString &str) const {
return !operator ==(str);
}
inline bool operator >=(const QString &str) const {
// ###
return toString() >= str;
}
inline bool operator<(const Latin1String &str) const;
inline bool operator>=(const Latin1String &str) const {
return !operator <(str);
}
inline bool operator ==(const Latin1String &str) const;
inline bool operator ==(const String &str) const {
if (d->length != str.d->length) {
return false;
}
return !memcmp(d->utf16, str.d->utf16, d->length * sizeof(ushort));
}
inline bool operator<(const String &other) const;
inline bool operator >=(const String &other) const {
return other < *this;
}
inline QString toString() const {
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
return QString((QChar *)d->utf16, d->length);
#else
int l = d->length;
QString str(l, Qt::Uninitialized);
QChar *ch = str.data();
for (int i = 0; i < l; ++i) {
ch[i] = QChar(d->utf16[i]);
}
return str;
#endif
}
};
class Latin1String
{
public:
Latin1String(const char *data) {
d = (Data *)data;
}
struct Data {
qle_short length;
char latin1[1];
};
Data *d;
inline Latin1String &operator=(const QString &str) {
d->length = str.length();
uchar *l = (uchar *)d->latin1;
const ushort *uc = (const ushort *)str.unicode();
for (int i = 0; i < str.length(); ++i) {
*l++ = uc[i];
}
while ((quintptr)l & 0x3) {
*l++ = 0;
}
return *this;
}
inline bool operator ==(const QString &str) const {
return QLatin1String(d->latin1) == str;
}
inline bool operator !=(const QString &str) const {
return !operator ==(str);
}
inline bool operator >=(const QString &str) const {
// ###
return toString() >= str;
}
inline bool operator ==(const Latin1String &str) const {
return d->length == str.d->length && !strcmp(d->latin1, str.d->latin1);
}
inline bool operator >=(const Latin1String &str) const {
int l = qMin(d->length, str.d->length);
int val = strncmp(d->latin1, str.d->latin1, l);
if (!val) {
val = d->length - str.d->length;
}
return val >= 0;
}
inline bool operator ==(const String &str) const {
return (str == *this);
}
inline bool operator >=(const String &str) const {
return (str < *this);
}
inline QString toString() const {
return QString::fromLatin1(d->latin1, d->length);
}
};
inline bool String::operator ==(const Latin1String &str) const
{
if ((int)d->length != (int)str.d->length) {
return false;
}
const qle_ushort *uc = d->utf16;
const qle_ushort *e = uc + d->length;
const uchar *c = (uchar *)str.d->latin1;
while (uc < e) {
if (*uc != *c) {
return false;
}
++uc;
++c;
}
return true;
}
inline bool String::operator <(const String &other) const
{
int alen = d->length;
int blen = other.d->length;
int l = qMin(alen, blen);
qle_ushort *a = d->utf16;
qle_ushort *b = other.d->utf16;
while (l-- && *a == *b) {
a++, b++;
}
if (l == -1) {
return (alen < blen);
}
return (ushort) * a - (ushort) * b;
}
inline bool String::operator<(const Latin1String &str) const
{
const uchar *c = (uchar *) str.d->latin1;
if (!c || *c == 0) {
return false;
}
const qle_ushort *uc = d->utf16;
const qle_ushort *e = uc + qMin((int)d->length, (int)str.d->length);
while (uc < e) {
if (*uc != *c) {
break;
}
++uc;
++c;
}
return (uc == e ? (int)d->length < (int)str.d->length : (ushort) * uc < *c);
}
static inline void copyString(char *dest, const QString &str, bool compress)
{
if (compress) {
Latin1String string(dest);
string = str;
} else {
String string(dest);
string = str;
}
}
/*
Base is the base class for both Object and Array. Both classe work more or less the same way.
The class starts with a header (defined by the struct below), then followed by data (the data for
values in the Array case and Entry's (see below) for objects.
After the data a table follows (tableOffset points to it) containing Value objects for Arrays, and
offsets from the beginning of the object to Entry's in the case of Object.
Entry's in the Object's table are lexicographically sorted by key in the table(). This allows the usage
of a binary search over the keys in an Object.
*/
class Base
{
public:
qle_uint size;
union {
uint _dummy;
qle_bitfield<0, 1> is_object;
qle_bitfield<1, 31> length;
};
offset tableOffset;
// content follows here
inline bool isObject() const {
return is_object;
}
inline bool isArray() const {
return !isObject();
}
inline offset *table() const {
return (offset *) (((char *) this) + tableOffset);
}
int reserveSpace(uint dataSize, int posInTable, uint numItems, bool replace);
void removeItems(int pos, int numItems);
};
class Object : public Base
{
public:
Entry *entryAt(int i) const {
return reinterpret_cast<Entry *>(((char *)this) + table()[i]);
}
int indexOf(const QString &key, bool *exists);
bool isValid() const;
};
class Array : public Base
{
public:
inline Value at(int i) const;
inline Value &operator [](int i);
bool isValid() const;
};
class Value
{
public:
enum {
MaxSize = (1 << 27) - 1
};
union {
uint _dummy;
qle_bitfield<0, 3> type;
qle_bitfield<3, 1> latinOrIntValue;
qle_bitfield<4, 1> latinKey;
qle_bitfield<5, 27> value;
qle_signedbitfield<5, 27> int_value;
};
inline char *data(const Base *b) const {
return ((char *)b) + value;
}
int usedStorage(const Base *b) const;
bool toBoolean() const;
double toDouble(const Base *b) const;
QString toString(const Base *b) const;
String asString(const Base *b) const;
Latin1String asLatin1String(const Base *b) const;
Base *base(const Base *b) const;
bool isValid(const Base *b) const;
static int requiredStorage(QJsonValue &v, bool *compressed);
static uint valueToStore(const QJsonValue &v, uint offset);
static void copyData(const QJsonValue &v, char *dest, bool compressed);
};
inline Value Array::at(int i) const
{
return *(Value *) (table() + i);
}
inline Value &Array::operator [](int i)
{
return *(Value *) (table() + i);
}
class Entry
{
public:
Value value;
// key
// value data follows key
int size() const {
int s = sizeof(Entry);
if (value.latinKey) {
s += sizeof(ushort) + qFromLittleEndian(*(ushort *) ((const char *)this + sizeof(Entry)));
} else {
s += sizeof(uint) + qFromLittleEndian(*(int *) ((const char *)this + sizeof(Entry)));
}
return alignedSize(s);
}
int usedStorage(Base *b) const {
return size() + value.usedStorage(b);
}
String shallowKey() const {
Q_ASSERT(!value.latinKey);
return String((const char *)this + sizeof(Entry));
}
Latin1String shallowLatin1Key() const {
Q_ASSERT(value.latinKey);
return Latin1String((const char *)this + sizeof(Entry));
}
QString key() const {
if (value.latinKey) {
return shallowLatin1Key().toString();
}
return shallowKey().toString();
}
bool operator ==(const QString &key) const;
inline bool operator !=(const QString &key) const {
return !operator ==(key);
}
inline bool operator >=(const QString &key) const;
bool operator ==(const Entry &other) const;
bool operator >=(const Entry &other) const;
};
inline bool Entry::operator >=(const QString &key) const
{
if (value.latinKey) {
return (shallowLatin1Key() >= key);
} else {
return (shallowKey() >= key);
}
}
inline bool operator <(const QString &key, const Entry &e)
{
return e >= key;
}
class Header
{
public:
qle_uint tag; // 'qbjs'
qle_uint version; // 1
Base *root() {
return (Base *)(this + 1);
}
};
inline bool Value::toBoolean() const
{
Q_ASSERT(type == QJsonValue::Bool);
return value != 0;
}
inline double Value::toDouble(const Base *b) const
{
Q_ASSERT(type == QJsonValue::Double);
if (latinOrIntValue) {
return int_value;
}
quint64 i = qFromLittleEndian<quint64>((const uchar *)b + value);
double d;
memcpy(&d, &i, sizeof(double));
return d;
}
inline String Value::asString(const Base *b) const
{
Q_ASSERT(type == QJsonValue::String && !latinOrIntValue);
return String(data(b));
}
inline Latin1String Value::asLatin1String(const Base *b) const
{
Q_ASSERT(type == QJsonValue::String && latinOrIntValue);
return Latin1String(data(b));
}
inline QString Value::toString(const Base *b) const
{
if (latinOrIntValue) {
return asLatin1String(b).toString();
} else {
return asString(b).toString();
}
}
inline Base *Value::base(const Base *b) const
{
Q_ASSERT(type == QJsonValue::Array || type == QJsonValue::Object);
return reinterpret_cast<Base *>(data(b));
}
class Data
{
public:
enum Validation {
Unchecked,
Validated,
Invalid
};
QAtomicInt ref;
int alloc;
union {
char *rawData;
Header *header;
};
uint compactionCounter;
bool ownsData;
inline Data(char *raw, int a)
: alloc(a), rawData(raw), compactionCounter(0), ownsData(true) {
}
inline Data(int reserved, QJsonValue::Type valueType)
: rawData(0), compactionCounter(0), ownsData(true) {
Q_ASSERT(valueType == QJsonValue::Array || valueType == QJsonValue::Object);
alloc = sizeof(Header) + sizeof(Base) + reserved + sizeof(offset);
header = (Header *)malloc(alloc);
Q_CHECK_PTR(header);
header->tag = QJsonDocument::BinaryFormatTag;
header->version = 1;
Base *b = header->root();
b->size = sizeof(Base);
b->is_object = (valueType == QJsonValue::Object);
b->tableOffset = sizeof(Base);
b->length = 0;
}
inline ~Data() {
if (ownsData) {
free(rawData);
}
}
uint offsetOf(const void *ptr) const {
return (uint)(((char *)ptr - rawData));
}
QJsonObject toObject(Object *o) const {
return QJsonObject(const_cast<Data *>(this), o);
}
QJsonArray toArray(Array *a) const {
return QJsonArray(const_cast<Data *>(this), a);
}
Data *clone(Base *b, int reserve = 0) {
int size = sizeof(Header) + b->size;
if (b == header->root() && ref == 1 && alloc >= size + reserve) {
return this;
}
if (reserve) {
if (reserve < 128) {
reserve = 128;
}
size = qMax(size + reserve, size * 2);
}
char *raw = (char *)malloc(size);
Q_CHECK_PTR(raw);
memcpy(raw + sizeof(Header), b, b->size);
Header *h = (Header *)raw;
h->tag = QJsonDocument::BinaryFormatTag;
h->version = 1;
Data *d = new Data(raw, size);
d->compactionCounter = (b == header->root()) ? compactionCounter : 0;
return d;
}
void compact();
bool valid() const;
private:
Q_DISABLE_COPY(Data)
};
}
QT_END_NAMESPACE
#endif // QJSON_P_H

File diff suppressed because it is too large Load diff

View file

@ -1,340 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONARRAY_H
#define QJSONARRAY_H
#include <QtCore/qjsonvalue.h>
QT_BEGIN_NAMESPACE
class QDebug;
class QStringList;
template <typename T> class QList;
typedef QList<QVariant> QVariantList;
class Q_CORE_EXPORT QJsonArray
{
public:
QJsonArray();
~QJsonArray();
QJsonArray(const QJsonArray &other);
QJsonArray &operator =(const QJsonArray &other);
static QJsonArray fromStringList(const QStringList &list);
static QJsonArray fromVariantList(const QVariantList &list);
QVariantList toVariantList() const;
int size() const;
inline int count() const {
return size();
}
bool isEmpty() const;
QJsonValue at(int i) const;
QJsonValue first() const;
QJsonValue last() const;
void prepend(const QJsonValue &value);
void append(const QJsonValue &value);
void removeAt(int i);
QJsonValue takeAt(int i);
inline void removeFirst() {
removeAt(0);
}
inline void removeLast() {
removeAt(size() - 1);
}
void insert(int i, const QJsonValue &value);
void replace(int i, const QJsonValue &value);
bool contains(const QJsonValue &element) const;
QJsonValueRef operator[](int i);
QJsonValue operator[](int i) const;
bool operator==(const QJsonArray &other) const;
bool operator!=(const QJsonArray &other) const;
class const_iterator;
class iterator
{
public:
QJsonArray *a;
int i;
typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
typedef QJsonValueRefPtr pointer;
typedef QJsonValueRef reference;
inline iterator() : a(0), i(0) { }
explicit inline iterator(QJsonArray *array, int index) : a(array), i(index) { }
inline QJsonValueRef operator*() const {
return QJsonValueRef(a, i);
}
inline QJsonValueRefPtr operator->() const {
return QJsonValueRefPtr(a, i);
}
inline QJsonValueRef operator[](int j) const {
return QJsonValueRef(a, i + j);
}
inline bool operator==(const iterator &o) const {
return i == o.i;
}
inline bool operator!=(const iterator &o) const {
return i != o.i;
}
inline bool operator<(const iterator &other) const {
return i < other.i;
}
inline bool operator<=(const iterator &other) const {
return i <= other.i;
}
inline bool operator>(const iterator &other) const {
return i > other.i;
}
inline bool operator>=(const iterator &other) const {
return i >= other.i;
}
inline bool operator==(const const_iterator &o) const {
return i == o.i;
}
inline bool operator!=(const const_iterator &o) const {
return i != o.i;
}
inline bool operator<(const const_iterator &other) const {
return i < other.i;
}
inline bool operator<=(const const_iterator &other) const {
return i <= other.i;
}
inline bool operator>(const const_iterator &other) const {
return i > other.i;
}
inline bool operator>=(const const_iterator &other) const {
return i >= other.i;
}
inline iterator &operator++() {
++i;
return *this;
}
inline iterator operator++(int) {
iterator n = *this;
++i;
return n;
}
inline iterator &operator--() {
i--;
return *this;
}
inline iterator operator--(int) {
iterator n = *this;
i--;
return n;
}
inline iterator &operator+=(int j) {
i += j;
return *this;
}
inline iterator &operator-=(int j) {
i -= j;
return *this;
}
inline iterator operator+(int j) const {
return iterator(a, i + j);
}
inline iterator operator-(int j) const {
return iterator(a, i - j);
}
inline int operator-(iterator j) const {
return i - j.i;
}
};
friend class iterator;
class const_iterator
{
public:
const QJsonArray *a;
int i;
typedef std::random_access_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef QJsonValue value_type;
typedef QJsonValuePtr pointer;
typedef QJsonValue reference;
inline const_iterator() : a(0), i(0) { }
explicit inline const_iterator(const QJsonArray *array, int index) : a(array), i(index) { }
inline const_iterator(const const_iterator &o) : a(o.a), i(o.i) {}
inline const_iterator(const iterator &o) : a(o.a), i(o.i) {}
inline QJsonValue operator*() const {
return a->at(i);
}
inline QJsonValuePtr operator->() const {
return QJsonValuePtr(a->at(i));
}
inline QJsonValue operator[](int j) const {
return a->at(i + j);
}
inline bool operator==(const const_iterator &o) const {
return i == o.i;
}
inline bool operator!=(const const_iterator &o) const {
return i != o.i;
}
inline bool operator<(const const_iterator &other) const {
return i < other.i;
}
inline bool operator<=(const const_iterator &other) const {
return i <= other.i;
}
inline bool operator>(const const_iterator &other) const {
return i > other.i;
}
inline bool operator>=(const const_iterator &other) const {
return i >= other.i;
}
inline const_iterator &operator++() {
++i;
return *this;
}
inline const_iterator operator++(int) {
const_iterator n = *this;
++i;
return n;
}
inline const_iterator &operator--() {
i--;
return *this;
}
inline const_iterator operator--(int) {
const_iterator n = *this;
i--;
return n;
}
inline const_iterator &operator+=(int j) {
i += j;
return *this;
}
inline const_iterator &operator-=(int j) {
i -= j;
return *this;
}
inline const_iterator operator+(int j) const {
return const_iterator(a, i + j);
}
inline const_iterator operator-(int j) const {
return const_iterator(a, i - j);
}
inline int operator-(const_iterator j) const {
return i - j.i;
}
};
friend class const_iterator;
// stl style
inline iterator begin() {
detach();
return iterator(this, 0);
}
inline const_iterator begin() const {
return const_iterator(this, 0);
}
inline const_iterator constBegin() const {
return const_iterator(this, 0);
}
inline iterator end() {
detach();
return iterator(this, size());
}
inline const_iterator end() const {
return const_iterator(this, size());
}
inline const_iterator constEnd() const {
return const_iterator(this, size());
}
iterator insert(iterator before, const QJsonValue &value) {
insert(before.i, value);
return before;
}
iterator erase(iterator it) {
removeAt(it.i);
return it;
}
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
// stl compatibility
inline void push_back(const QJsonValue &t) {
append(t);
}
inline void push_front(const QJsonValue &t) {
prepend(t);
}
inline void pop_front() {
removeFirst();
}
inline void pop_back() {
removeLast();
}
inline bool empty() const {
return isEmpty();
}
typedef int size_type;
typedef QJsonValue value_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
typedef QJsonValueRef reference;
typedef QJsonValue const_reference;
typedef int difference_type;
private:
friend class QJsonPrivate::Data;
friend class QJsonValue;
friend class QJsonDocument;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
QJsonArray(QJsonPrivate::Data *data, QJsonPrivate::Array *array);
void compact();
void detach(uint reserve = 0);
QJsonPrivate::Data *d;
QJsonPrivate::Array *a;
};
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
QT_END_NAMESPACE
#endif // QJSONARRAY_H

View file

@ -1,503 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjsondocument.h"
#include "qjsonobject.h"
#include "qjsonvalue.h"
#include "qjsonarray.h"
#include "qstringlist.h"
#include "qvariant.h"
#include "qdebug.h"
#include "qjsonwriter_p.h"
#include "qjsonparser_p.h"
#include "qjson_p.h"
QT_BEGIN_NAMESPACE
QJsonDocument::QJsonDocument()
: d(0)
{
}
QJsonDocument::QJsonDocument(const QJsonObject &object)
: d(0)
{
setObject(object);
}
QJsonDocument::QJsonDocument(const QJsonArray &array)
: d(0)
{
setArray(array);
}
QJsonDocument::QJsonDocument(QJsonPrivate::Data *data)
: d(data)
{
Q_ASSERT(d);
d->ref.ref();
}
QJsonDocument::~QJsonDocument()
{
if (d && !d->ref.deref()) {
delete d;
}
}
QJsonDocument::QJsonDocument(const QJsonDocument &other)
{
d = other.d;
if (d) {
d->ref.ref();
}
}
/*!
* Assigns the \a other document to this QJsonDocument.
* Returns a reference to this object.
*/
QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
{
if (d != other.d) {
if (d && !d->ref.deref()) {
delete d;
}
d = other.d;
if (d) {
d->ref.ref();
}
}
return *this;
}
/*! \enum QJsonDocument::DataValidation
This value is used to tell QJsonDocument whether to validate the binary data
when converting to a QJsonDocument using fromBinaryData() or fromRawData().
\value Validate Validate the data before using it. This is the default.
\value BypassValidation Bypasses data validation. Only use if you received the
data from a trusted place and know it's valid, as using of invalid data can crash
the application.
*/
/*!
Creates a QJsonDocument that uses the first \a size bytes from
\a data. It assumes \a data contains a binary encoded JSON document.
The created document does not take ownership of \a data and the caller
has to guarantee that \a data will not be deleted or modified as long as
any QJsonDocument, QJsonObject or QJsonArray still references the data.
\a data has to be aligned to a 4 byte boundary.
\a validation decides whether the data is checked for validity before being used.
By default the data is validated. If the \a data is not valid, the method returns
a null document.
Returns a QJsonDocument representing the data.
\sa rawData(), fromBinaryData(), isNull(), DataValidation
*/
QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation)
{
if (quintptr(data) & 3) {
qWarning() << "QJsonDocument::fromRawData: data has to have 4 byte alignment";
return QJsonDocument();
}
QJsonPrivate::Data *d = new QJsonPrivate::Data((char *)data, size);
d->ownsData = false;
if (validation != BypassValidation && !d->valid()) {
delete d;
return QJsonDocument();
}
return QJsonDocument(d);
}
/*!
Returns the raw binary representation of the data
\a size will contain the size of the returned data.
This method is useful to e.g. stream the JSON document
in it's binary form to a file.
*/
const char *QJsonDocument::rawData(int *size) const
{
if (!d) {
*size = 0;
return 0;
}
*size = d->alloc;
return d->rawData;
}
/*!
Creates a QJsonDocument from \a data.
\a validation decides whether the data is checked for validity before being used.
By default the data is validated. If the \a data is not valid, the method returns
a null document.
\sa toBinaryData(), fromRawData(), isNull(), DataValidation
*/
QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation)
{
if (data.size() < (int)(sizeof(QJsonPrivate::Header) + sizeof(QJsonPrivate::Base))) {
return QJsonDocument();
}
QJsonPrivate::Header h;
memcpy(&h, data.constData(), sizeof(QJsonPrivate::Header));
QJsonPrivate::Base root;
memcpy(&root, data.constData() + sizeof(QJsonPrivate::Header), sizeof(QJsonPrivate::Base));
// do basic checks here, so we don't try to allocate more memory than we can.
if (h.tag != QJsonDocument::BinaryFormatTag || h.version != 1u ||
sizeof(QJsonPrivate::Header) + root.size > (uint)data.size()) {
return QJsonDocument();
}
const uint size = sizeof(QJsonPrivate::Header) + root.size;
char *raw = (char *)malloc(size);
if (!raw) {
return QJsonDocument();
}
memcpy(raw, data.constData(), size);
QJsonPrivate::Data *d = new QJsonPrivate::Data(raw, size);
if (validation != BypassValidation && !d->valid()) {
delete d;
return QJsonDocument();
}
return QJsonDocument(d);
}
/*!
Creates a QJsonDocument from the QVariant \a variant.
If the \a variant contains any other type than a QVariant::Map,
QVariant::List or QVariant::StringList, the returned document
document is invalid.
\sa toVariant()
*/
QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
{
QJsonDocument doc;
if (variant.type() == QVariant::Map) {
doc.setObject(QJsonObject::fromVariantMap(variant.toMap()));
} else if (variant.type() == QVariant::List) {
doc.setArray(QJsonArray::fromVariantList(variant.toList()));
} else if (variant.type() == QVariant::StringList) {
doc.setArray(QJsonArray::fromStringList(variant.toStringList()));
}
return doc;
}
/*!
Returns a QVariant representing the Json document.
The returned variant will be a QVariantList if the document is
a QJsonArray and a QVariantMap if the document is a QJsonObject.
\sa fromVariant(), QJsonValue::toVariant()
*/
QVariant QJsonDocument::toVariant() const
{
if (!d) {
return QVariant();
}
if (d->header->root()->isArray()) {
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root())).toVariantList();
} else {
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root())).toVariantMap();
}
}
QByteArray QJsonDocument::toJson(JsonFormat format) const
{
if (!d) {
return QByteArray();
}
QByteArray json;
if (d->header->root()->isArray()) {
QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(d->header->root()), json, 0, (format == Compact));
} else {
QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(d->header->root()), json, 0,
(format == Compact));
}
return json;
}
/*!
Parses a UTF-8 encoded JSON document and creates a QJsonDocument
from it.
\a json contains the json document to be parsed.
The optional \a error variable can be used to pass in a QJsonParseError data
structure that will contain information about possible errors encountered during
parsing.
\sa toJson(), QJsonParseError
*/
QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error)
{
QJsonPrivate::Parser parser(json.constData(), json.length());
return parser.parse(error);
}
/*!
Returns true if the document doesn't contain any data.
*/
bool QJsonDocument::isEmpty() const
{
if (!d) {
return true;
}
return false;
}
/*!
Returns a binary representation of the document.
The binary representation is also the native format used internally in Qt,
and is very efficient and fast to convert to and from.
The binary format can be stored on disk and interchanged with other applications
or computers. fromBinaryData() can be used to convert it back into a
JSON document.
\sa fromBinaryData()
*/
QByteArray QJsonDocument::toBinaryData() const
{
if (!d || !d->rawData) {
return QByteArray();
}
return QByteArray(d->rawData, d->header->root()->size + sizeof(QJsonPrivate::Header));
}
/*!
Returns true if the document contains an array.
\sa array(), isObject()
*/
bool QJsonDocument::isArray() const
{
if (!d) {
return false;
}
QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
return h->root()->isArray();
}
/*!
Returns true if the document contains an object.
\sa object(), isArray()
*/
bool QJsonDocument::isObject() const
{
if (!d) {
return false;
}
QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
return h->root()->isObject();
}
/*!
Returns the QJsonObject contained in the document.
Returns an empty object if the document contains an
array.
\sa isObject(), array(), setObject()
*/
QJsonObject QJsonDocument::object() const
{
if (d) {
QJsonPrivate::Base *b = d->header->root();
if (b->isObject()) {
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(b));
}
}
return QJsonObject();
}
/*!
Returns the QJsonArray contained in the document.
Returns an empty array if the document contains an
object.
\sa isArray(), object(), setArray()
*/
QJsonArray QJsonDocument::array() const
{
if (d) {
QJsonPrivate::Base *b = d->header->root();
if (b->isArray()) {
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(b));
}
}
return QJsonArray();
}
/*!
Sets \a object as the main object of this document.
\sa setArray(), object()
*/
void QJsonDocument::setObject(const QJsonObject &object)
{
if (d && !d->ref.deref()) {
delete d;
}
d = object.d;
if (!d) {
d = new QJsonPrivate::Data(0, QJsonValue::Object);
} else if (d->compactionCounter || object.o != d->header->root()) {
QJsonObject o(object);
if (d->compactionCounter) {
o.compact();
} else {
o.detach();
}
d = o.d;
d->ref.ref();
return;
}
d->ref.ref();
}
/*!
Sets \a array as the main object of this document.
\sa setObject(), array()
*/
void QJsonDocument::setArray(const QJsonArray &array)
{
if (d && !d->ref.deref()) {
delete d;
}
d = array.d;
if (!d) {
d = new QJsonPrivate::Data(0, QJsonValue::Array);
} else if (d->compactionCounter || array.a != d->header->root()) {
QJsonArray a(array);
if (d->compactionCounter) {
a.compact();
} else {
a.detach();
}
d = a.d;
d->ref.ref();
return;
}
d->ref.ref();
}
/*!
Returns \c true if the \a other document is equal to this document.
*/
bool QJsonDocument::operator==(const QJsonDocument &other) const
{
if (d == other.d) {
return true;
}
if (!d || !other.d) {
return false;
}
if (d->header->root()->isArray() != other.d->header->root()->isArray()) {
return false;
}
if (d->header->root()->isObject())
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root()))
== QJsonObject(other.d, static_cast<QJsonPrivate::Object *>(other.d->header->root()));
else
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root()))
== QJsonArray(other.d, static_cast<QJsonPrivate::Array *>(other.d->header->root()));
}
/*!
\fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
returns \c true if \a other is not equal to this document
*/
/*!
returns true if this document is null.
Null documents are documents created through the default constructor.
Documents created from UTF-8 encoded text or the binary format are
validated during parsing. If validation fails, the returned document
will also be null.
*/
bool QJsonDocument::isNull() const
{
return (d == 0);
}
QDebug operator<<(QDebug dbg, const QJsonDocument &o)
{
if (!o.d) {
dbg << "QJsonDocument()";
return dbg;
}
QByteArray json;
if (o.d->header->root()->isArray()) {
QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(o.d->header->root()), json, 0, true);
} else {
QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(o.d->header->root()), json, 0, true);
}
dbg.nospace() << "QJsonDocument("
<< json.constData() // print as utf-8 string without extra quotation marks
<< ")";
return dbg.space();
}
QT_END_NAMESPACE

View file

@ -1,136 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONDOCUMENT_H
#define QJSONDOCUMENT_H
#include <QtCore/qjsonvalue.h>
QT_BEGIN_NAMESPACE
class QDebug;
namespace QJsonPrivate {
class Parser;
}
struct Q_CORE_EXPORT QJsonParseError {
enum ParseError {
NoError = 0,
UnterminatedObject,
MissingNameSeparator,
UnterminatedArray,
MissingValueSeparator,
IllegalValue,
TerminationByNumber,
IllegalNumber,
IllegalEscapeSequence,
IllegalUTF8String,
UnterminatedString,
MissingObject,
DeepNesting,
DocumentTooLarge
};
QString errorString() const;
int offset;
ParseError error;
};
class Q_CORE_EXPORT QJsonDocument
{
public:
#ifdef Q_LITTLE_ENDIAN
static const uint BinaryFormatTag = ('q') | ('b' << 8) | ('j' << 16) | ('s' << 24);
#else
static const uint BinaryFormatTag = ('q' << 24) | ('b' << 16) | ('j' << 8) | ('s');
#endif
QJsonDocument();
explicit QJsonDocument(const QJsonObject &object);
explicit QJsonDocument(const QJsonArray &array);
~QJsonDocument();
QJsonDocument(const QJsonDocument &other);
QJsonDocument &operator =(const QJsonDocument &other);
enum DataValidation {
Validate,
BypassValidation
};
static QJsonDocument fromRawData(const char *data, int size, DataValidation validation = Validate);
const char *rawData(int *size) const;
static QJsonDocument fromBinaryData(const QByteArray &data, DataValidation validation = Validate);
QByteArray toBinaryData() const;
static QJsonDocument fromVariant(const QVariant &variant);
QVariant toVariant() const;
enum JsonFormat {
Indented,
Compact
};
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = 0);
QByteArray toJson(JsonFormat format = Indented) const;
bool isEmpty() const;
bool isArray() const;
bool isObject() const;
QJsonObject object() const;
QJsonArray array() const;
void setObject(const QJsonObject &object);
void setArray(const QJsonArray &array);
bool operator==(const QJsonDocument &other) const;
bool operator!=(const QJsonDocument &other) const {
return !(*this == other);
}
bool isNull() const;
private:
friend class QJsonValue;
friend class QJsonPrivate::Data;
friend class QJsonPrivate::Parser;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
QJsonDocument(QJsonPrivate::Data *data);
QJsonPrivate::Data *d;
};
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
QT_END_NAMESPACE
#endif // QJSONDOCUMENT_H

File diff suppressed because it is too large Load diff

View file

@ -1,305 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONOBJECT_H
#define QJSONOBJECT_H
#include "qjsonvalue.h"
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qiterator.h>
QT_BEGIN_NAMESPACE
class QDebug;
typedef QMap<QString, QVariant> QVariantMap;
typedef QHash<QString, QVariant> QVariantHash;
class Q_CORE_EXPORT QJsonObject
{
public:
QJsonObject();
~QJsonObject();
QJsonObject(const QJsonObject &other);
QJsonObject &operator =(const QJsonObject &other);
static QJsonObject fromVariantMap(const QVariantMap &map);
QVariantMap toVariantMap() const;
static QJsonObject fromVariantHash(const QVariantHash &map);
QVariantHash toVariantHash() const;
QStringList keys() const;
int size() const;
inline int count() const {
return size();
}
inline int length() const {
return size();
}
bool isEmpty() const;
QJsonValue value(const QString &key) const;
QJsonValue operator[] (const QString &key) const;
QJsonValueRef operator[] (const QString &key);
void remove(const QString &key);
QJsonValue take(const QString &key);
bool contains(const QString &key) const;
bool operator==(const QJsonObject &other) const;
bool operator!=(const QJsonObject &other) const;
class const_iterator;
class iterator
{
friend class const_iterator;
friend class QJsonObject;
QJsonObject *o;
int i;
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
typedef QJsonValueRefPtr pointer;
typedef QJsonValueRef reference;
inline iterator() : o(0), i(0) {}
inline iterator(QJsonObject *obj, int index) : o(obj), i(index) {}
inline QString key() const {
return o->keyAt(i);
}
inline QJsonValueRef value() const {
return QJsonValueRef(o, i);
}
inline QJsonValueRef operator*() const {
return QJsonValueRef(o, i);
}
inline QJsonValueRefPtr operator->() const {
return QJsonValueRefPtr(o, i);
}
inline bool operator==(const iterator &other) const {
return i == other.i;
}
inline bool operator!=(const iterator &other) const {
return i != other.i;
}
inline iterator &operator++() {
++i;
return *this;
}
inline iterator operator++(int) {
iterator r = *this;
++i;
return r;
}
inline iterator &operator--() {
--i;
return *this;
}
inline iterator operator--(int) {
iterator r = *this;
--i;
return r;
}
inline iterator operator+(int j) const {
iterator r = *this;
r.i += j;
return r;
}
inline iterator operator-(int j) const {
return operator+(-j);
}
inline iterator &operator+=(int j) {
i += j;
return *this;
}
inline iterator &operator-=(int j) {
i -= j;
return *this;
}
public:
inline bool operator==(const const_iterator &other) const {
return i == other.i;
}
inline bool operator!=(const const_iterator &other) const {
return i != other.i;
}
};
friend class iterator;
class const_iterator
{
friend class iterator;
const QJsonObject *o;
int i;
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue* value_type;
typedef QJsonValuePtr pointer;
typedef QJsonValue reference;
inline const_iterator() : o(0), i(0) {}
inline const_iterator(const QJsonObject *obj, int index)
: o(obj), i(index) {}
inline const_iterator(const iterator &other)
: o(other.o), i(other.i) {}
inline QString key() const {
return o->keyAt(i);
}
inline QJsonValue value() const {
return o->valueAt(i);
}
inline QJsonValue operator*() const {
return o->valueAt(i);
}
inline QJsonValuePtr operator->() const {
return QJsonValuePtr(o->valueAt(i));
}
inline bool operator==(const const_iterator &other) const {
return i == other.i;
}
inline bool operator!=(const const_iterator &other) const {
return i != other.i;
}
inline const_iterator &operator++() {
++i;
return *this;
}
inline const_iterator operator++(int) {
const_iterator r = *this;
++i;
return r;
}
inline const_iterator &operator--() {
--i;
return *this;
}
inline const_iterator operator--(int) {
const_iterator r = *this;
--i;
return r;
}
inline const_iterator operator+(int j) const {
const_iterator r = *this;
r.i += j;
return r;
}
inline const_iterator operator-(int j) const {
return operator+(-j);
}
inline const_iterator &operator+=(int j) {
i += j;
return *this;
}
inline const_iterator &operator-=(int j) {
i -= j;
return *this;
}
inline bool operator==(const iterator &other) const {
return i == other.i;
}
inline bool operator!=(const iterator &other) const {
return i != other.i;
}
};
friend class const_iterator;
// STL style
inline iterator begin() {
detach();
return iterator(this, 0);
}
inline const_iterator begin() const {
return const_iterator(this, 0);
}
inline const_iterator constBegin() const {
return const_iterator(this, 0);
}
inline iterator end() {
detach();
return iterator(this, size());
}
inline const_iterator end() const {
return const_iterator(this, size());
}
inline const_iterator constEnd() const {
return const_iterator(this, size());
}
iterator erase(iterator it);
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
iterator find(const QString &key);
const_iterator find(const QString &key) const {
return constFind(key);
}
const_iterator constFind(const QString &key) const;
iterator insert(const QString &key, const QJsonValue &value);
// STL compatibility
typedef QJsonValue mapped_type;
typedef QString key_type;
typedef int size_type;
inline bool empty() const {
return isEmpty();
}
private:
friend class QJsonPrivate::Data;
friend class QJsonValue;
friend class QJsonDocument;
friend class QJsonValueRef;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
QJsonObject(QJsonPrivate::Data *data, QJsonPrivate::Object *object);
void detach(uint reserve = 0);
void compact();
QString keyAt(int i) const;
QJsonValue valueAt(int i) const;
void setValueAt(int i, const QJsonValue &val);
QJsonPrivate::Data *d;
QJsonPrivate::Object *o;
};
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
QT_END_NAMESPACE
#endif // QJSONOBJECT_H

View file

@ -1,984 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcoreapplication.h"
#include "qdebug.h"
#include "qjsonparser_p.h"
#include "qjson_p.h"
//#define PARSER_DEBUG
#ifdef PARSER_DEBUG
static int indent = 0;
#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current
#define END --indent
#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
#else
#define BEGIN if (1) ; else qDebug()
#define END do {} while (0)
#define DEBUG if (1) ; else qDebug()
#endif
static const int nestingLimit = 1024;
QT_BEGIN_NAMESPACE
// error strings for the JSON parser
#define JSONERR_OK QT_TRANSLATE_NOOP("QJsonParseError", "no error occurred")
#define JSONERR_UNTERM_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "unterminated object")
#define JSONERR_MISS_NSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing name separator")
#define JSONERR_UNTERM_AR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated array")
#define JSONERR_MISS_VSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing value separator")
#define JSONERR_ILLEGAL_VAL QT_TRANSLATE_NOOP("QJsonParseError", "illegal value")
#define JSONERR_END_OF_NUM QT_TRANSLATE_NOOP("QJsonParseError", "invalid termination by number")
#define JSONERR_ILLEGAL_NUM QT_TRANSLATE_NOOP("QJsonParseError", "illegal number")
#define JSONERR_STR_ESC_SEQ QT_TRANSLATE_NOOP("QJsonParseError", "invalid escape sequence")
#define JSONERR_STR_UTF8 QT_TRANSLATE_NOOP("QJsonParseError", "invalid UTF8 string")
#define JSONERR_UTERM_STR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated string")
#define JSONERR_MISS_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "object is missing after a comma")
#define JSONERR_DEEP_NEST QT_TRANSLATE_NOOP("QJsonParseError", "too deeply nested document")
#define JSONERR_DOC_LARGE QT_TRANSLATE_NOOP("QJsonParseError", "too large document")
/*!
\class QJsonParseError
\inmodule QtCore
\ingroup json
\reentrant
\since 4.9
\brief The QJsonParseError class is used to report errors during JSON parsing.
*/
/*!
\enum QJsonParseError::ParseError
This enum describes the type of error that occurred during the parsing of a JSON document.
\value NoError No error occurred
\value UnterminatedObject An object is not correctly terminated with a closing curly bracket
\value MissingNameSeparator A comma separating different items is missing
\value UnterminatedArray The array is not correctly terminated with a closing square bracket
\value MissingValueSeparator A colon separating keys from values inside objects is missing
\value IllegalValue The value is illegal
\value TerminationByNumber The input stream ended while parsing a number
\value IllegalNumber The number is not well formed
\value IllegalEscapeSequence An illegal escape sequence occurred in the input
\value IllegalUTF8String An illegal UTF8 sequence occurred in the input
\value UnterminatedString A string wasn't terminated with a quote
\value MissingObject An object was expected but couldn't be found
\value DeepNesting The JSON document is too deeply nested for the parser to parse it
\value DocumentTooLarge The JSON document is too large for the parser to parse it
*/
/*!
\variable QJsonParseError::error
Contains the type of the parse error. Is equal to QJsonParseError::NoError if the document
was parsed correctly.
\sa ParseError, errorString()
*/
/*!
\variable QJsonParseError::offset
Contains the offset in the input string where the parse error occurred.
\sa error, errorString()
*/
/*!
Returns the human-readable message appropriate to the reported JSON parsing error.
\sa error
*/
QString QJsonParseError::errorString() const
{
const char *sz = "";
switch (error) {
case NoError:
sz = JSONERR_OK;
break;
case UnterminatedObject:
sz = JSONERR_UNTERM_OBJ;
break;
case MissingNameSeparator:
sz = JSONERR_MISS_NSEP;
break;
case UnterminatedArray:
sz = JSONERR_UNTERM_AR;
break;
case MissingValueSeparator:
sz = JSONERR_MISS_VSEP;
break;
case IllegalValue:
sz = JSONERR_ILLEGAL_VAL;
break;
case TerminationByNumber:
sz = JSONERR_END_OF_NUM;
break;
case IllegalNumber:
sz = JSONERR_ILLEGAL_NUM;
break;
case IllegalEscapeSequence:
sz = JSONERR_STR_ESC_SEQ;
break;
case IllegalUTF8String:
sz = JSONERR_STR_UTF8;
break;
case UnterminatedString:
sz = JSONERR_UTERM_STR;
break;
case MissingObject:
sz = JSONERR_MISS_OBJ;
break;
case DeepNesting:
sz = JSONERR_DEEP_NEST;
break;
case DocumentTooLarge:
sz = JSONERR_DOC_LARGE;
break;
}
return QCoreApplication::translate("QJsonParseError", sz);
}
using namespace QJsonPrivate;
Parser::Parser(const char *json, int length)
: head(json), json(json), data(0), dataLength(0), current(0), nestingLevel(0), lastError(QJsonParseError::NoError)
{
end = json + length;
}
/*
begin-array = ws %x5B ws ; [ left square bracket
begin-object = ws %x7B ws ; { left curly bracket
end-array = ws %x5D ws ; ] right square bracket
end-object = ws %x7D ws ; } right curly bracket
name-separator = ws %x3A ws ; : colon
value-separator = ws %x2C ws ; , comma
Insignificant whitespace is allowed before or after any of the six
structural characters.
ws = *(
%x20 / ; WhiteSpace
%x09 / ; Horizontal tab
%x0A / ; Line feed or New line
%x0D ; Carriage return
)
*/
enum {
WhiteSpace = 0x20,
Tab = 0x09,
LineFeed = 0x0a,
Return = 0x0d,
BeginArray = 0x5b,
BeginObject = 0x7b,
EndArray = 0x5d,
EndObject = 0x7d,
NameSeparator = 0x3a,
ValueSeparator = 0x2c,
Quote = 0x22
};
void Parser::eatBOM()
{
// eat UTF-8 byte order mark
uchar utf8bom[3] = { 0xef, 0xbb, 0xbf };
if (end - json > 3 &&
(uchar)json[0] == utf8bom[0] &&
(uchar)json[1] == utf8bom[1] &&
(uchar)json[2] == utf8bom[2]) {
json += 3;
}
}
bool Parser::eatSpace()
{
while (json < end) {
if (*json > WhiteSpace) {
break;
}
if (*json != WhiteSpace &&
*json != Tab &&
*json != LineFeed &&
*json != Return) {
break;
}
++json;
}
return (json < end);
}
char Parser::nextToken()
{
if (!eatSpace()) {
return 0;
}
char token = *json++;
switch (token) {
case BeginArray:
case BeginObject:
case NameSeparator:
case ValueSeparator:
case EndArray:
case EndObject:
eatSpace();
case Quote:
break;
default:
token = 0;
break;
}
return token;
}
/*
JSON-text = object / array
*/
QJsonDocument Parser::parse(QJsonParseError *error)
{
#ifdef PARSER_DEBUG
indent = 0;
qDebug() << ">>>>> parser begin";
#endif
// allocate some space
dataLength = qMax(end - json, (ptrdiff_t) 256);
data = (char *)malloc(dataLength);
// fill in Header data
QJsonPrivate::Header *h = (QJsonPrivate::Header *)data;
h->tag = QJsonDocument::BinaryFormatTag;
h->version = 1u;
current = sizeof(QJsonPrivate::Header);
eatBOM();
char token = nextToken();
DEBUG << hex << (uint)token;
if (token == BeginArray) {
if (!parseArray()) {
goto error;
}
} else if (token == BeginObject) {
if (!parseObject()) {
goto error;
}
} else {
lastError = QJsonParseError::IllegalValue;
goto error;
}
END;
{
if (error) {
error->offset = 0;
error->error = QJsonParseError::NoError;
}
return QJsonDocument(new QJsonPrivate::Data(data, current));
}
error:
#ifdef PARSER_DEBUG
qDebug() << ">>>>> parser error";
#endif
if (error) {
error->offset = json - head;
error->error = lastError;
}
free(data);
return QJsonDocument();
}
void Parser::ParsedObject::insert(uint offset)
{
const QJsonPrivate::Entry *newEntry = reinterpret_cast<const QJsonPrivate::Entry *>(parser->data + objectPosition +
offset);
int min = 0;
int n = offsets.size();
while (n > 0) {
int half = n >> 1;
int middle = min + half;
if (*entryAt(middle) >= *newEntry) {
n = half;
} else {
min = middle + 1;
n -= half + 1;
}
}
if (min < offsets.size() && *entryAt(min) == *newEntry) {
offsets[min] = offset;
} else {
offsets.insert(min, offset);
}
}
/*
object = begin-object [ member *( value-separator member ) ]
end-object
*/
bool Parser::parseObject()
{
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
return false;
}
int objectOffset = reserveSpace(sizeof(QJsonPrivate::Object));
BEGIN << "parseObject pos=" << objectOffset << current << json;
ParsedObject parsedObject(this, objectOffset);
char token = nextToken();
while (token == Quote) {
int off = current - objectOffset;
if (!parseMember(objectOffset)) {
return false;
}
parsedObject.insert(off);
token = nextToken();
if (token != ValueSeparator) {
break;
}
token = nextToken();
if (token == EndObject) {
lastError = QJsonParseError::MissingObject;
return false;
}
}
DEBUG << "end token=" << token;
if (token != EndObject) {
lastError = QJsonParseError::UnterminatedObject;
return false;
}
DEBUG << "numEntries" << parsedObject.offsets.size();
int table = objectOffset;
// finalize the object
if (parsedObject.offsets.size()) {
int tableSize = parsedObject.offsets.size() * sizeof(uint);
table = reserveSpace(tableSize);
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(data + table, parsedObject.offsets.constData(), tableSize);
#else
offset *o = (offset *)(data + table);
for (int i = 0; i < tableSize; ++i) {
o[i] = parsedObject.offsets[i];
}
#endif
}
QJsonPrivate::Object *o = (QJsonPrivate::Object *)(data + objectOffset);
o->tableOffset = table - objectOffset;
o->size = current - objectOffset;
o->is_object = true;
o->length = parsedObject.offsets.size();
DEBUG << "current=" << current;
END;
--nestingLevel;
return true;
}
/*
member = string name-separator value
*/
bool Parser::parseMember(int baseOffset)
{
int entryOffset = reserveSpace(sizeof(QJsonPrivate::Entry));
BEGIN << "parseMember pos=" << entryOffset;
bool latin1;
if (!parseString(&latin1)) {
return false;
}
char token = nextToken();
if (token != NameSeparator) {
lastError = QJsonParseError::MissingNameSeparator;
return false;
}
QJsonPrivate::Value val;
if (!parseValue(&val, baseOffset)) {
return false;
}
// finalize the entry
QJsonPrivate::Entry *e = (QJsonPrivate::Entry *)(data + entryOffset);
e->value = val;
e->value.latinKey = latin1;
END;
return true;
}
/*
array = begin-array [ value *( value-separator value ) ] end-array
*/
bool Parser::parseArray()
{
BEGIN << "parseArray";
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
return false;
}
int arrayOffset = reserveSpace(sizeof(QJsonPrivate::Array));
QVarLengthArray<QJsonPrivate::Value, 64> values;
if (!eatSpace()) {
lastError = QJsonParseError::UnterminatedArray;
return false;
}
if (*json == EndArray) {
nextToken();
} else {
while (1) {
QJsonPrivate::Value val;
if (!parseValue(&val, arrayOffset)) {
return false;
}
values.append(val);
char token = nextToken();
if (token == EndArray) {
break;
} else if (token != ValueSeparator) {
if (!eatSpace()) {
lastError = QJsonParseError::UnterminatedArray;
} else {
lastError = QJsonParseError::MissingValueSeparator;
}
return false;
}
}
}
DEBUG << "size =" << values.size();
int table = arrayOffset;
// finalize the object
if (values.size()) {
int tableSize = values.size() * sizeof(QJsonPrivate::Value);
table = reserveSpace(tableSize);
memcpy(data + table, values.constData(), tableSize);
}
QJsonPrivate::Array *a = (QJsonPrivate::Array *)(data + arrayOffset);
a->tableOffset = table - arrayOffset;
a->size = current - arrayOffset;
a->is_object = false;
a->length = values.size();
DEBUG << "current=" << current;
END;
--nestingLevel;
return true;
}
/*
value = false / null / true / object / array / number / string
*/
bool Parser::parseValue(QJsonPrivate::Value *val, int baseOffset)
{
BEGIN << "parse Value" << json;
val->_dummy = 0;
switch (*json++) {
case 'n':
if (end - json < 4) {
lastError = QJsonParseError::IllegalValue;
return false;
}
if (*json++ == 'u' &&
*json++ == 'l' &&
*json++ == 'l') {
val->type = QJsonValue::Null;
DEBUG << "value: null";
END;
return true;
}
lastError = QJsonParseError::IllegalValue;
return false;
case 't':
if (end - json < 4) {
lastError = QJsonParseError::IllegalValue;
return false;
}
if (*json++ == 'r' &&
*json++ == 'u' &&
*json++ == 'e') {
val->type = QJsonValue::Bool;
val->value = true;
DEBUG << "value: true";
END;
return true;
}
lastError = QJsonParseError::IllegalValue;
return false;
case 'f':
if (end - json < 5) {
lastError = QJsonParseError::IllegalValue;
return false;
}
if (*json++ == 'a' &&
*json++ == 'l' &&
*json++ == 's' &&
*json++ == 'e') {
val->type = QJsonValue::Bool;
val->value = false;
DEBUG << "value: false";
END;
return true;
}
lastError = QJsonParseError::IllegalValue;
return false;
case Quote: {
val->type = QJsonValue::String;
if (current - baseOffset >= Value::MaxSize) {
lastError = QJsonParseError::DocumentTooLarge;
return false;
}
val->value = current - baseOffset;
bool latin1;
if (!parseString(&latin1)) {
return false;
}
val->latinOrIntValue = latin1;
DEBUG << "value: string";
END;
return true;
}
case BeginArray:
val->type = QJsonValue::Array;
if (current - baseOffset >= Value::MaxSize) {
lastError = QJsonParseError::DocumentTooLarge;
return false;
}
val->value = current - baseOffset;
if (!parseArray()) {
return false;
}
DEBUG << "value: array";
END;
return true;
case BeginObject:
val->type = QJsonValue::Object;
if (current - baseOffset >= Value::MaxSize) {
lastError = QJsonParseError::DocumentTooLarge;
return false;
}
val->value = current - baseOffset;
if (!parseObject()) {
return false;
}
DEBUG << "value: object";
END;
return true;
case EndArray:
lastError = QJsonParseError::MissingObject;
return false;
default:
--json;
if (!parseNumber(val, baseOffset)) {
return false;
}
DEBUG << "value: number";
END;
}
return true;
}
/*
number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E ; .
digit1-9 = %x31-39 ; 1-9
e = %x65 / %x45 ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D ; -
plus = %x2B ; +
zero = %x30 ; 0
*/
bool Parser::parseNumber(QJsonPrivate::Value *val, int baseOffset)
{
BEGIN << "parseNumber" << json;
val->type = QJsonValue::Double;
const char *start = json;
bool isInt = true;
// minus
if (json < end && *json == '-') {
++json;
}
// int = zero / ( digit1-9 *DIGIT )
if (json < end && *json == '0') {
++json;
} else {
while (json < end && *json >= '0' && *json <= '9') {
++json;
}
}
// frac = decimal-point 1*DIGIT
if (json < end && *json == '.') {
isInt = false;
++json;
while (json < end && *json >= '0' && *json <= '9') {
++json;
}
}
// exp = e [ minus / plus ] 1*DIGIT
if (json < end && (*json == 'e' || *json == 'E')) {
isInt = false;
++json;
if (json < end && (*json == '-' || *json == '+')) {
++json;
}
while (json < end && *json >= '0' && *json <= '9') {
++json;
}
}
if (json >= end) {
lastError = QJsonParseError::TerminationByNumber;
return false;
}
QByteArray number(start, json - start);
DEBUG << "numberstring" << number;
if (isInt) {
bool ok;
int n = number.toInt(&ok);
if (ok && n < (1 << 25) && n > -(1 << 25)) {
val->int_value = n;
val->latinOrIntValue = true;
END;
return true;
}
}
bool ok;
union {
quint64 ui;
double d;
};
d = number.toDouble(&ok);
if (!ok) {
lastError = QJsonParseError::IllegalNumber;
return false;
}
int pos = reserveSpace(sizeof(double));
*(quint64 *)(data + pos) = qToLittleEndian(ui);
if (current - baseOffset >= Value::MaxSize) {
lastError = QJsonParseError::DocumentTooLarge;
return false;
}
val->value = pos - baseOffset;
val->latinOrIntValue = false;
END;
return true;
}
/*
string = quotation-mark *char quotation-mark
char = unescaped /
escape (
%x22 / ; " quotation mark U+0022
%x5C / ; \ reverse solidus U+005C
%x2F / ; / solidus U+002F
%x62 / ; b backspace U+0008
%x66 / ; f form feed U+000C
%x6E / ; n line feed U+000A
%x72 / ; r carriage return U+000D
%x74 / ; t tab U+0009
%x75 4HEXDIG ) ; uXXXX U+XXXX
escape = %x5C ; \
quotation-mark = %x22 ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
*/
static inline bool addHexDigit(char digit, uint *result)
{
*result <<= 4;
if (digit >= '0' && digit <= '9') {
*result |= (digit - '0');
} else if (digit >= 'a' && digit <= 'f') {
*result |= (digit - 'a') + 10;
} else if (digit >= 'A' && digit <= 'F') {
*result |= (digit - 'A') + 10;
} else {
return false;
}
return true;
}
static inline bool scanEscapeSequence(const char *&json, const char *end, uint *ch)
{
++json;
if (json >= end) {
return false;
}
DEBUG << "scan escape" << (char)*json;
uint escaped = *json++;
switch (escaped) {
case '"':
*ch = '"';
break;
case '\\':
*ch = '\\';
break;
case '/':
*ch = '/';
break;
case 'b':
*ch = 0x8;
break;
case 'f':
*ch = 0xc;
break;
case 'n':
*ch = 0xa;
break;
case 'r':
*ch = 0xd;
break;
case 't':
*ch = 0x9;
break;
case 'u': {
*ch = 0;
if (json > end - 4) {
return false;
}
for (int i = 0; i < 4; ++i) {
if (!addHexDigit(*json, ch)) {
return false;
}
++json;
}
return true;
}
default:
// this is not as strict as one could be, but allows for more Json files
// to be parsed correctly.
*ch = escaped;
return true;
}
return true;
}
static inline bool scanUtf8Char(const char *&json, const char *end, uint *result)
{
int need;
uint min_uc;
uint uc;
uchar ch = *json++;
if (ch < 128) {
*result = ch;
return true;
} else if ((ch & 0xe0) == 0xc0) {
uc = ch & 0x1f;
need = 1;
min_uc = 0x80;
} else if ((ch & 0xf0) == 0xe0) {
uc = ch & 0x0f;
need = 2;
min_uc = 0x800;
} else if ((ch & 0xf8) == 0xf0) {
uc = ch & 0x07;
need = 3;
min_uc = 0x10000;
} else {
return false;
}
if (json >= end - need) {
return false;
}
for (int i = 0; i < need; ++i) {
ch = *json++;
if ((ch & 0xc0) != 0x80) {
return false;
}
uc = (uc << 6) | (ch & 0x3f);
}
/* Qt 5 Beta 1
if (uc < min_uc || QChar::isNonCharacter(uc) ||
QChar::isSurrogate(uc) || uc > QChar::LastValidCodePoint) {
*/
// Temporary for missing QChar methods. Does not check for non-characters
// or past last valid code point.
if (uc < min_uc ||
QChar::isHighSurrogate(uc) || QChar::isLowSurrogate(uc)) {
return false;
}
*result = uc;
return true;
}
bool Parser::parseString(bool *latin1)
{
*latin1 = true;
const char *start = json;
int outStart = current;
// try to write out a latin1 string
int stringPos = reserveSpace(2);
BEGIN << "parse string stringPos=" << stringPos << json;
while (json < end) {
uint ch = 0;
if (*json == '"') {
break;
} else if (*json == '\\') {
if (!scanEscapeSequence(json, end, &ch)) {
lastError = QJsonParseError::IllegalEscapeSequence;
return false;
}
} else {
if (!scanUtf8Char(json, end, &ch)) {
lastError = QJsonParseError::IllegalUTF8String;
return false;
}
}
if (ch > 0xff) {
*latin1 = false;
break;
}
int pos = reserveSpace(1);
DEBUG << " " << ch << (char)ch;
data[pos] = (uchar)ch;
}
++json;
DEBUG << "end of string";
if (json >= end) {
lastError = QJsonParseError::UnterminatedString;
return false;
}
// no unicode string, we are done
if (*latin1) {
// write string length
*(QJsonPrivate::qle_ushort *)(data + stringPos) = ushort(current - outStart - sizeof(ushort));
int pos = reserveSpace((4 - current) & 3);
while (pos & 3) {
data[pos++] = 0;
}
END;
return true;
}
*latin1 = false;
DEBUG << "not latin";
json = start;
current = outStart + sizeof(int);
while (json < end) {
uint ch = 0;
if (*json == '"') {
break;
} else if (*json == '\\') {
if (!scanEscapeSequence(json, end, &ch)) {
lastError = QJsonParseError::IllegalEscapeSequence;
return false;
}
} else {
if (!scanUtf8Char(json, end, &ch)) {
lastError = QJsonParseError::IllegalUTF8String;
return false;
}
}
if (QChar::requiresSurrogates(ch)) {
int pos = reserveSpace(4);
*(QJsonPrivate::qle_ushort *)(data + pos) = QChar::highSurrogate(ch);
*(QJsonPrivate::qle_ushort *)(data + pos + 2) = QChar::lowSurrogate(ch);
} else {
int pos = reserveSpace(2);
*(QJsonPrivate::qle_ushort *)(data + pos) = (ushort)ch;
}
}
++json;
if (json >= end) {
lastError = QJsonParseError::UnterminatedString;
return false;
}
// write string length
*(QJsonPrivate::qle_int *)(data + stringPos) = (current - outStart - sizeof(int)) / 2;
int pos = reserveSpace((4 - current) & 3);
while (pos & 3) {
data[pos++] = 0;
}
END;
return true;
}
QT_END_NAMESPACE

View file

@ -1,94 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONPARSER_P_H
#define QJSONPARSER_P_H
#include "qjsondocument.h"
#include "qvarlengtharray.h"
QT_BEGIN_NAMESPACE
namespace QJsonPrivate {
class Parser
{
public:
Parser(const char *json, int length);
QJsonDocument parse(QJsonParseError *error);
class ParsedObject
{
public:
ParsedObject(Parser *p, int pos) : parser(p), objectPosition(pos) {}
void insert(uint offset);
Parser *parser;
int objectPosition;
QVarLengthArray<uint, 64> offsets;
inline QJsonPrivate::Entry *entryAt(int i) const {
return reinterpret_cast<QJsonPrivate::Entry *>(parser->data + objectPosition + offsets[i]);
}
};
private:
inline void eatBOM();
inline bool eatSpace();
inline char nextToken();
bool parseObject();
bool parseArray();
bool parseMember(int baseOffset);
bool parseString(bool *latin1);
bool parseValue(QJsonPrivate::Value *val, int baseOffset);
bool parseNumber(QJsonPrivate::Value *val, int baseOffset);
const char *head;
const char *json;
const char *end;
char *data;
int dataLength;
int current;
int nestingLevel;
QJsonParseError::ParseError lastError;
inline int reserveSpace(int space) {
if (current + space >= dataLength) {
dataLength = 2 * dataLength + space;
data = (char *)realloc(data, dataLength);
}
int pos = current;
current += space;
return pos;
}
};
}
QT_END_NAMESPACE
#endif

View file

@ -1,693 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjsonobject.h"
#include "qjsonvalue.h"
#include "qjsonarray.h"
#include "qvariant.h"
#include "qstringlist.h"
#include "qdebug.h"
#include "qjson_p.h"
QT_BEGIN_NAMESPACE
/*!
\class QJsonValue
\inmodule QtCore
\ingroup json
\reentrant
\since 4.9
\brief The QJsonValue class encapsulates a value in JSON.
A value in JSON can be one of 6 basic types:
JSON is a format to store structured data. It has 6 basic data types:
\list
\li bool QJsonValue::Bool
\li double QJsonValue::Double
\li string QJsonValue::String
\li array QJsonValue::Array
\li object QJsonValue::Object
\li null QJsonValue::Null
\endlist
A value can represent any of the above data types. In addition, QJsonValue has one special
flag to represent undefined values. This can be queried with isUndefined().
The type of the value can be queried with type() or accessors like isBool(), isString(), and so on.
Likewise, the value can be converted to the type stored in it using the toBool(), toString() and so on.
Values are strictly typed internally and contrary to QVariant will not attempt to do any implicit type
conversions. This implies that converting to a type that is not stored in the value will return a default
constructed return value.
*/
/*!
Creates a QJsonValue of type \a type.
The default is to create a Null value.
*/
QJsonValue::QJsonValue(Type type)
: b(false), dbl(0), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(type)
{
}
/*!
\internal
*/
QJsonValue::QJsonValue(QJsonPrivate::Data *data, QJsonPrivate::Base *privbase, const QJsonPrivate::Value &v)
: b(false), dbl(0), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(static_cast<Type>(uint(v.type)))
{
switch (t) {
case Undefined:
case Null:
break;
case Bool:
b = v.toBoolean();
break;
case Double:
dbl = v.toDouble(privbase);
break;
case String: {
stringData = new QString(v.toString(privbase));
break;
}
case Array:
case Object:
d = data;
base = v.base(privbase);
break;
}
if (d) {
d->ref.ref();
}
}
/*!
Creates a value of type Bool, with value \a a.
*/
QJsonValue::QJsonValue(bool a)
: b(a), dbl(0), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(Bool)
{
}
/*!
Creates a value of type Double, with value \a n.
*/
QJsonValue::QJsonValue(double n)
: b(false), dbl(n), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(Double)
{
}
/*!
\overload
Creates a value of type Double, with value \a n.
*/
QJsonValue::QJsonValue(int n)
: b(false), dbl(n), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(Double)
{
}
/*!
\overload
Creates a value of type Double, with value \a n.
NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992).
If you pass in values outside this range expect a loss of precision to occur.
*/
QJsonValue::QJsonValue(qint64 n)
: b(false), dbl(n), stringData(Q_NULLPTR), base(Q_NULLPTR), d(Q_NULLPTR), t(Double)
{
}
/*!
Creates a value of type String, with value \a s.
*/
QJsonValue::QJsonValue(const QString &s)
: b(false), dbl(0), stringData(new QString(s)), base(Q_NULLPTR), d(Q_NULLPTR), t(String)
{
}
/*!
Creates a value of type String, with value \a s.
*/
QJsonValue::QJsonValue(QLatin1String s)
: b(false), dbl(0), stringData(new QString(s)), base(Q_NULLPTR), d(Q_NULLPTR), t(String)
{
}
/*!
Creates a value of type Array, with value \a a.
*/
QJsonValue::QJsonValue(const QJsonArray &a)
: b(false), dbl(0), stringData(Q_NULLPTR), base(a.a), d(a.d), t(Array)
{
if (d) {
d->ref.ref();
}
}
/*!
Creates a value of type Object, with value \a o.
*/
QJsonValue::QJsonValue(const QJsonObject &o)
: b(false), dbl(0), stringData(Q_NULLPTR), base(o.o), d(o.d), t(Object)
{
if (d) {
d->ref.ref();
}
}
/*!
Destroys the value.
*/
QJsonValue::~QJsonValue()
{
if (t == String) {
delete stringData;
}
if (d && !d->ref.deref()) {
delete d;
}
}
/*!
Creates a copy of \a other.
*/
QJsonValue::QJsonValue(const QJsonValue &other)
: b(other.b), dbl(other.dbl), stringData(Q_NULLPTR), base(Q_NULLPTR), d(other.d), t(other.t)
{
if (d) {
d->ref.ref();
}
if (t == String && other.stringData) {
stringData = new QString(*other.stringData);
}
}
/*!
Assigns the value stored in \a other to this object.
*/
QJsonValue &QJsonValue::operator =(const QJsonValue &other)
{
if (t == String) {
delete stringData;
stringData = Q_NULLPTR;
}
t = other.t;
b = other.b;
dbl = other.dbl;
qAtomicAssign(d, other.d);
if (t == String && other.stringData) {
stringData = new QString(*other.stringData);
}
return *this;
}
/*!
\fn bool QJsonValue::isNull() const
Returns true if the value is null.
*/
/*!
\fn bool QJsonValue::isBool() const
Returns true if the value contains a boolean.
\sa toBool()
*/
/*!
\fn bool QJsonValue::isDouble() const
Returns true if the value contains a double.
\sa toDouble()
*/
/*!
\fn bool QJsonValue::isString() const
Returns true if the value contains a string.
\sa toString()
*/
/*!
\fn bool QJsonValue::isArray() const
Returns true if the value contains an array.
\sa toArray()
*/
/*!
\fn bool QJsonValue::isObject() const
Returns true if the value contains an object.
\sa toObject()
*/
/*!
\fn bool QJsonValue::isUndefined() const
Returns true if the value is undefined. This can happen in certain
error cases as e.g. accessing a non existing key in a QJsonObject.
*/
/*!
Converts \a variant to a QJsonValue and returns it.
The conversion will convert QVariant types as follows:
\list
\li QVariant::Bool to Bool
\li QVariant::Int
\li QVariant::Double
\li QVariant::LongLong
\li QVariant::ULongLong
\li QVariant::UInt to Double
\li QVariant::String to String
\li QVariant::StringList
\li QVariant::VariantList to Array
\li QVariant::VariantMap to Object
\endlist
For all other QVariant types a conversion to a QString will be attempted. If the returned string
is empty, a Null QJsonValue will be stored, otherwise a String value using the returned QString.
\sa toVariant()
*/
QJsonValue QJsonValue::fromVariant(const QVariant &variant)
{
switch (variant.type()) {
case QVariant::Bool:
return QJsonValue(variant.toBool());
case QVariant::Int:
case QVariant::Double:
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::UInt:
return QJsonValue(variant.toDouble());
case QVariant::String:
return QJsonValue(variant.toString());
case QVariant::StringList:
return QJsonValue(QJsonArray::fromStringList(variant.toStringList()));
case QVariant::List:
return QJsonValue(QJsonArray::fromVariantList(variant.toList()));
case QVariant::Map:
return QJsonValue(QJsonObject::fromVariantMap(variant.toMap()));
default:
break;
}
QByteArray a;
{
QDataStream s(&a, QIODevice::WriteOnly);
s << variant;
}
if (a.isEmpty()) {
return QJsonValue();
}
QString result = QLatin1String("@(");
result += QString::fromLatin1(a.constData(), a.size());
result += QLatin1String(")@");
return QJsonValue(result);
}
/*!
Converts the value to a QVariant.
The QJsonValue types will be converted as follows:
\value Null QVariant()
\value Bool QVariant::Bool
\value Double QVariant::Double
\value String QVariant::String
\value Array QVariantList
\value Object QVariantMap
\value Undefined QVariant()
\sa fromVariant()
*/
QVariant QJsonValue::toVariant() const
{
switch (t) {
case Bool:
return b;
case Double:
return dbl;
case String: {
QVariant variant = toString();
QString string = variant.toString();
if (string.startsWith(QLatin1String("@(")) && string.endsWith(")@")) {
QByteArray a(string.toLatin1());
a.remove(0, 2);
a.chop(2);
QDataStream stream(&a, QIODevice::ReadOnly);
QVariant result;
stream >> result;
return result;
}
return variant;
}
case Array:
return d ?
QJsonArray(d, static_cast<QJsonPrivate::Array *>(base)).toVariantList() :
QVariantList();
case Object:
return d ?
QJsonObject(d, static_cast<QJsonPrivate::Object *>(base)).toVariantMap() :
QVariantMap();
case Null:
case Undefined:
return QVariant();
}
return QVariant();
}
/*!
\enum QJsonValue::Type
This enum describes the type of the JSON value.
\value Null A Null value
\value Bool A boolean value. Use toBool() to convert to a bool.
\value Double A double. Use toDouble() to convert to a double.
\value String A string. Use toString() to convert to a QString.
\value Array An array. Use toArray() to convert to a QJsonArray.
\value Object An object. Use toObject() to convert to a QJsonObject.
\value Undefined The value is undefined. This is usually returned as an
error condition, when trying to read an out of bounds value
in an array or a non existent key in an object.
*/
/*!
Returns the type of the value.
\sa QJsonValue::Type
*/
QJsonValue::Type QJsonValue::type() const
{
return t;
}
/*!
Converts the value to a bool and returns it.
If type() is not bool, the \a defaultValue will be returned.
*/
bool QJsonValue::toBool(bool defaultValue) const
{
if (t != Bool) {
return defaultValue;
}
return b;
}
/*!
Converts the value to an int and returns it.
If type() is not Double or the value is not a whole number,
the \a defaultValue will be returned.
*/
int QJsonValue::toInt(int defaultValue) const
{
if (t == Double && int(dbl) == dbl) {
return dbl;
}
return defaultValue;
}
/*!
Converts the value to a double and returns it.
If type() is not Double, the \a defaultValue will be returned.
*/
double QJsonValue::toDouble(double defaultValue) const
{
if (t != Double) {
return defaultValue;
}
return dbl;
}
/*!
Converts the value to a QString and returns it.
If type() is not String, the \a defaultValue will be returned.
*/
QString QJsonValue::toString(const QString &defaultValue) const
{
if (t != String) {
return defaultValue;
}
return *stringData;
}
/*!
Converts the value to an array and returns it.
If type() is not Array, the \a defaultValue will be returned.
*/
QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const
{
if (!d || t != Array) {
return defaultValue;
}
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(base));
}
/*!
\overload
Converts the value to an array and returns it.
If type() is not Array, a QJsonArray() will be returned.
*/
QJsonArray QJsonValue::toArray() const
{
return toArray(QJsonArray());
}
/*!
Converts the value to an object and returns it.
If type() is not Object, the \a defaultValue will be returned.
*/
QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const
{
if (!d || t != Object) {
return defaultValue;
}
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(base));
}
/*!
\overload
Converts the value to an object and returns it.
If type() is not Object, the QJsonObject() will be returned.
*/
QJsonObject QJsonValue::toObject() const
{
return toObject(QJsonObject());
}
/*!
Returns true if the value is equal to \a other.
*/
bool QJsonValue::operator==(const QJsonValue &other) const
{
if (t != other.t) {
return false;
}
switch (t) {
case Undefined:
case Null:
break;
case Bool:
return b == other.b;
case Double:
return dbl == other.dbl;
case String:
return toString() == other.toString();
case Array:
if (base == other.base) {
return true;
}
if (!base || !other.base) {
return false;
}
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(base))
== QJsonArray(other.d, static_cast<QJsonPrivate::Array *>(other.base));
case Object:
if (base == other.base) {
return true;
}
if (!base || !other.base) {
return false;
}
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(base))
== QJsonObject(other.d, static_cast<QJsonPrivate::Object *>(other.base));
}
return true;
}
/*!
Returns true if the value is not equal to \a other.
*/
bool QJsonValue::operator!=(const QJsonValue &other) const
{
return !(*this == other);
}
/*!
\internal
*/
void QJsonValue::detach()
{
if (!d) {
return;
}
qAtomicAssign(d, d->clone(base));
base = static_cast<QJsonPrivate::Object *>(d->header->root());
}
/*!
\class QJsonValueRef
\inmodule QtCore
\reentrant
\brief The QJsonValueRef class is a helper class for QJsonValue.
\internal
\ingroup json
When you get an object of type QJsonValueRef, if you can assign to it,
the assignment will apply to the character in the string from
which you got the reference. That is its whole purpose in life.
You can use it exactly in the same way as a reference to a QJsonValue.
The QJsonValueRef becomes invalid once modifications are made to the
string: if you want to keep the character, copy it into a QJsonValue.
Most of the QJsonValue member functions also exist in QJsonValueRef.
However, they are not explicitly documented here.
*/
QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
{
if (is_object) {
o->setValueAt(index, val);
} else {
a->replace(index, val);
}
return *this;
}
QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref)
{
if (is_object) {
o->setValueAt(index, ref);
} else {
a->replace(index, ref);
}
return *this;
}
QJsonArray QJsonValueRef::toArray() const
{
return toValue().toArray();
}
QJsonObject QJsonValueRef::toObject() const
{
return toValue().toObject();
}
QJsonValue QJsonValueRef::toValue() const
{
if (!is_object) {
return a->at(index);
}
return o->valueAt(index);
}
QDebug operator<<(QDebug dbg, const QJsonValue &o)
{
switch (o.t) {
case QJsonValue::Undefined:
dbg.nospace() << "QJsonValue(undefined)";
break;
case QJsonValue::Null:
dbg.nospace() << "QJsonValue(null)";
break;
case QJsonValue::Bool:
dbg.nospace() << "QJsonValue(bool, " << o.toBool() << ")";
break;
case QJsonValue::Double:
dbg.nospace() << "QJsonValue(double, " << o.toDouble() << ")";
break;
case QJsonValue::String:
dbg.nospace() << "QJsonValue(string, " << o.toString() << ")";
break;
case QJsonValue::Array:
dbg.nospace() << "QJsonValue(array, ";
dbg.nospace() << o.toArray();
dbg.nospace() << ")";
break;
case QJsonValue::Object:
dbg.nospace() << "QJsonValue(object, ";
dbg.nospace() << o.toObject();
dbg.nospace() << ")";
break;
}
return dbg.space();
}
QT_END_NAMESPACE

View file

@ -1,235 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONVALUE_H
#define QJSONVALUE_H
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
class QDebug;
class QVariant;
class QJsonArray;
class QJsonObject;
namespace QJsonPrivate {
class Data;
class Base;
class Object;
class Header;
class Array;
class Value;
class Entry;
}
class Q_CORE_EXPORT QJsonValue
{
public:
enum Type {
Null = 0x0,
Bool = 0x1,
Double = 0x2,
String = 0x3,
Array = 0x4,
Object = 0x5,
Undefined = 0x80
};
QJsonValue(Type = Null);
QJsonValue(bool b);
QJsonValue(double n);
QJsonValue(int n);
QJsonValue(qint64 n);
QJsonValue(const QString &s);
QJsonValue(QLatin1String s);
QJsonValue(const QJsonArray &a);
QJsonValue(const QJsonObject &o);
~QJsonValue();
QJsonValue(const QJsonValue &other);
QJsonValue &operator =(const QJsonValue &other);
static QJsonValue fromVariant(const QVariant &variant);
QVariant toVariant() const;
Type type() const;
inline bool isNull() const {
return type() == Null;
}
inline bool isBool() const {
return type() == Bool;
}
inline bool isDouble() const {
return type() == Double;
}
inline bool isString() const {
return type() == String;
}
inline bool isArray() const {
return type() == Array;
}
inline bool isObject() const {
return type() == Object;
}
inline bool isUndefined() const {
return type() == Undefined;
}
bool toBool(bool defaultValue = false) const;
int toInt(int defaultValue = 0) const;
double toDouble(double defaultValue = 0) const;
QString toString(const QString &defaultValue = QString()) const;
QJsonArray toArray() const;
QJsonArray toArray(const QJsonArray &defaultValue) const;
QJsonObject toObject() const;
QJsonObject toObject(const QJsonObject &defaultValue) const;
bool operator==(const QJsonValue &other) const;
bool operator!=(const QJsonValue &other) const;
private:
// avoid implicit conversions from char * to bool
inline QJsonValue(const void *) {}
friend class QJsonPrivate::Value;
friend class QJsonArray;
friend class QJsonObject;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
QJsonValue(QJsonPrivate::Data *d, QJsonPrivate::Base *b, const QJsonPrivate::Value &v);
void detach();
bool b;
double dbl;
QString *stringData;
QJsonPrivate::Base *base;
QJsonPrivate::Data *d; // needed for Objects and Arrays
Type t;
};
class Q_CORE_EXPORT QJsonValueRef
{
public:
QJsonValueRef(QJsonArray *array, int idx)
: a(array), is_object(false), index(idx) {}
QJsonValueRef(QJsonObject *object, int idx)
: o(object), is_object(true), index(idx) {}
inline operator QJsonValue() const {
return toValue();
}
QJsonValueRef &operator = (const QJsonValue &val);
QJsonValueRef &operator = (const QJsonValueRef &val);
inline QJsonValue::Type type() const {
return toValue().type();
}
inline bool isNull() const {
return type() == QJsonValue::Null;
}
inline bool isBool() const {
return type() == QJsonValue::Bool;
}
inline bool isDouble() const {
return type() == QJsonValue::Double;
}
inline bool isString() const {
return type() == QJsonValue::String;
}
inline bool isArray() const {
return type() == QJsonValue::Array;
}
inline bool isObject() const {
return type() == QJsonValue::Object;
}
inline bool isUndefined() const {
return type() == QJsonValue::Undefined;
}
inline bool toBool() const {
return toValue().toBool();
}
inline int toInt() const {
return toValue().toInt();
}
inline double toDouble() const {
return toValue().toDouble();
}
inline QString toString() const {
return toValue().toString();
}
QJsonArray toArray() const;
QJsonObject toObject() const;
inline bool operator==(const QJsonValue &other) const {
return toValue() == other;
}
inline bool operator!=(const QJsonValue &other) const {
return toValue() != other;
}
private:
QJsonValue toValue() const;
union {
QJsonArray *a;
QJsonObject *o;
};
bool is_object;
int index;
};
class Q_CORE_EXPORT QJsonValueRefPtr {
public:
template<typename T1, typename T2>
QJsonValueRefPtr(T1 a, T2 b)
: m_ref(a, b) { }
QJsonValueRef* operator->() const { return &m_ref; };
private:
mutable QJsonValueRef m_ref;
};
class Q_CORE_EXPORT QJsonValuePtr {
public:
QJsonValuePtr(QJsonValue val)
: m_value(val) { }
const QJsonValue * operator->() const { return &m_value; };
private:
const QJsonValue m_value;
};
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
QT_END_NAMESPACE
#endif // QJSONVALUE_H

View file

@ -1,255 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjsonwriter_p.h"
#include "qjson_p.h"
QT_BEGIN_NAMESPACE
using namespace QJsonPrivate;
static void objectContentToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact);
static void arrayContentToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact);
static inline uchar hexdig(uint u)
{
return (u < 0xa ? '0' + u : 'a' + u - 0xa);
}
static QByteArray escapedString(const QString &s)
{
const uchar replacement = '?';
QByteArray ba(s.length(), Qt::Uninitialized);
uchar *cursor = (uchar *)ba.data();
const uchar *ba_end = cursor + ba.length();
const QChar *ch = (const QChar *)s.constData();
const QChar *end = ch + s.length();
int surrogate_high = -1;
while (ch < end) {
if (cursor >= ba_end - 6) {
// ensure we have enough space
int pos = cursor - (const uchar *)ba.constData();
ba.resize(ba.size() * 2);
cursor = (uchar *)ba.data() + pos;
ba_end = (const uchar *)ba.constData() + ba.length();
}
uint u = ch->unicode();
if (surrogate_high >= 0) {
if (ch->isLowSurrogate()) {
u = QChar::surrogateToUcs4(surrogate_high, u);
surrogate_high = -1;
} else {
// high surrogate without low
*cursor = replacement;
++ch;
surrogate_high = -1;
continue;
}
} else if (ch->isLowSurrogate()) {
// low surrogate without high
*cursor = replacement;
++ch;
continue;
} else if (ch->isHighSurrogate()) {
surrogate_high = u;
++ch;
continue;
}
if (u < 0x80) {
if (u < 0x20 || u == 0x22 || u == 0x5c) {
*cursor++ = '\\';
switch (u) {
case 0x22:
*cursor++ = '"';
break;
case 0x5c:
*cursor++ = '\\';
break;
case 0x8:
*cursor++ = 'b';
break;
case 0xc:
*cursor++ = 'f';
break;
case 0xa:
*cursor++ = 'n';
break;
case 0xd:
*cursor++ = 'r';
break;
case 0x9:
*cursor++ = 't';
break;
default:
*cursor++ = 'u';
*cursor++ = '0';
*cursor++ = '0';
*cursor++ = hexdig(u >> 4);
*cursor++ = hexdig(u & 0xf);
}
} else {
*cursor++ = (uchar)u;
}
} else {
if (u < 0x0800) {
*cursor++ = 0xc0 | ((uchar) (u >> 6));
} else {
/* Qt 5 Beta 1
// is it one of the Unicode non-characters?
if (QChar::isNonCharacter(u)) {
*cursor++ = replacement;
++ch;
continue;
}
*/
if (QChar::requiresSurrogates(u)) {
*cursor++ = 0xf0 | ((uchar) (u >> 18));
*cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
} else {
*cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
}
*cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
}
*cursor++ = 0x80 | ((uchar) (u & 0x3f));
}
++ch;
}
ba.resize(cursor - (const uchar *)ba.constData());
return ba;
}
static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value &v, QByteArray &json, int indent,
bool compact)
{
QJsonValue::Type type = (QJsonValue::Type)(uint)v.type;
switch (type) {
case QJsonValue::Bool:
json += v.toBoolean() ? "true" : "false";
break;
case QJsonValue::Double:
json += QByteArray::number(v.toDouble(b), 'g', 17);
break;
case QJsonValue::String:
json += '"';
json += escapedString(v.toString(b));
json += '"';
break;
case QJsonValue::Array:
json += compact ? "[" : "[\n";
arrayContentToJson(static_cast<QJsonPrivate::Array *>(v.base(b)), json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += "]";
break;
case QJsonValue::Object:
json += compact ? "{" : "{\n";
objectContentToJson(static_cast<QJsonPrivate::Object *>(v.base(b)), json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += "}";
break;
case QJsonValue::Null:
default:
json += "null";
}
}
static void arrayContentToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact)
{
if (!a || !a->length) {
return;
}
QByteArray indentString(4 * indent, ' ');
uint i = 0;
while (1) {
json += indentString;
valueToJson(a, a->at(i), json, indent, compact);
if (++i == a->length) {
if (!compact) {
json += '\n';
}
break;
}
json += compact ? "," : ",\n";
}
}
static void objectContentToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact)
{
if (!o || !o->length) {
return;
}
QByteArray indentString(4 * indent, ' ');
uint i = 0;
while (1) {
QJsonPrivate::Entry *e = o->entryAt(i);
json += indentString;
json += '"';
json += escapedString(e->key());
json += "\": ";
valueToJson(o, e->value, json, indent, compact);
if (++i == o->length) {
if (!compact) {
json += '\n';
}
break;
}
json += compact ? "," : ",\n";
}
}
void Writer::objectToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact)
{
json.reserve(json.size() + (o ? (int)o->size : 16));
json += compact ? "{" : "{\n";
objectContentToJson(o, json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += compact ? "}" : "}\n";
}
void Writer::arrayToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact)
{
json.reserve(json.size() + (a ? (int)a->size : 16));
json += compact ? "[" : "[\n";
arrayContentToJson(a, json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += compact ? "]" : "]\n";
}
QT_END_NAMESPACE

View file

@ -1,45 +0,0 @@
/****************************************************************************
**
** Copyright (c) 2012-2015 Barbara Geller
** Copyright (c) 2012-2015 Ansel Sermersheim
** Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONWRITER_P_H
#define QJSONWRITER_P_H
#include "qjsonvalue.h"
QT_BEGIN_NAMESPACE
namespace QJsonPrivate {
class Writer
{
public:
static void objectToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact = false);
static void arrayToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact = false);
};
}
QT_END_NAMESPACE
#endif

View file

@ -31,9 +31,6 @@
#ifndef QT_BOOTSTRAPPED
# include "qeasingcurve.h"
# include "qjsonvalue.h"
# include "qjsonobject.h"
# include "qjsonarray.h"
# include "qjsondocument.h"
# include "qbitarray.h"
# include "qurl.h"
@ -117,9 +114,6 @@ QT_BEGIN_NAMESPACE
\value QPointF QPointF
\value QRegExp QRegExp
\value QEasingCurve QEasingCurve
\value QJsonValue QJsonValue
\value QJsonObject QJsonObject
\value QJsonArray QJsonArray
\value QJsonDocument QJsonDocument
\value QVariantHash QVariantHash
\value QVariantList QVariantList
@ -244,9 +238,6 @@ static const struct MetaTypeTblData {
QT_ADD_STATIC_METATYPE("QPointF", QMetaType::QPointF),
QT_ADD_STATIC_METATYPE("QRegExp", QMetaType::QRegExp),
QT_ADD_STATIC_METATYPE("QEasingCurve", QMetaType::QEasingCurve),
QT_ADD_STATIC_METATYPE("QJsonValue", QMetaType:: QJsonValue),
QT_ADD_STATIC_METATYPE("QJsonObject", QMetaType::QJsonObject),
QT_ADD_STATIC_METATYPE("QJsonArray", QMetaType::QJsonArray),
QT_ADD_STATIC_METATYPE("QJsonDocument", QMetaType::QJsonDocument),
QT_ADD_STATIC_METATYPE("QVariantHash", QMetaType::QVariantHash),
QT_ADD_STATIC_METATYPE("QVariantList", QMetaType::QVariantList),
@ -621,9 +612,6 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
case QMetaType::QWidgetStar:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonArray:
case QMetaType::QJsonDocument:
return false;
case QMetaType::Long:
@ -818,9 +806,6 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
case QMetaType::QWidgetStar:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonArray:
case QMetaType::QJsonDocument:
return false;
case QMetaType::Long: {
@ -1094,12 +1079,6 @@ void *QMetaType::construct(int type, const void *copy)
#ifndef QT_BOOTSTRAPPED
case QMetaType::QEasingCurve:
return new NS(QEasingCurve)(*static_cast<const NS(QEasingCurve)*>(copy));
case QMetaType::QJsonValue:
return new NS(QJsonValue)(*static_cast<const NS(QJsonValue)*>(copy));
case QMetaType::QJsonObject:
return new NS(QJsonObject)(*static_cast<const NS(QJsonObject)*>(copy));
case QMetaType::QJsonArray:
return new NS(QJsonArray)(*static_cast<const NS(QJsonArray)*>(copy));
case QMetaType::QJsonDocument:
return new NS(QJsonDocument)(*static_cast<const NS(QJsonDocument)*>(copy));
#endif
@ -1362,15 +1341,6 @@ void QMetaType::destroy(int type, void *data)
case QMetaType::QEasingCurve:
delete static_cast< NS(QEasingCurve)* >(data);
break;
case QMetaType::QJsonValue:
delete static_cast< NS(QJsonValue)* >(data);
break;
case QMetaType::QJsonObject:
delete static_cast< NS(QJsonObject)* >(data);
break;
case QMetaType::QJsonArray:
delete static_cast< NS(QJsonArray)* >(data);
break;
case QMetaType::QJsonDocument:
delete static_cast< NS(QJsonDocument)* >(data);
break;

View file

@ -45,9 +45,8 @@ public:
QByteArray = 11, QBitArray = 12, QDate = 13, QTime = 14,
QDateTime = 15, QUrl = 16, QLocale = 17, QRect = 18, QRectF = 19,
QSize = 20, QSizeF = 21, QLine = 22, QLineF = 23, QPoint = 24,
QPointF = 25, QRegExp = 26, QEasingCurve = 27, QJsonValue = 28,
QJsonObject = 29, QJsonArray = 30, QJsonDocument = 31,
QVariantHash = 32, QVariantList = 33, QVariantMap = 34,
QPointF = 25, QRegExp = 26, QEasingCurve = 27, QJsonDocument = 28,
QVariantHash = 29, QVariantList = 30, QVariantMap = 31,
LastCoreType = QVariantMap,
FirstGuiType = 64 /* QFont */,
@ -262,9 +261,6 @@ class QPointF;
#ifndef QT_NO_REGEXP
class QRegExp;
#endif
class QJsonValue;
class QJsonObject;
class QJsonArray;
class QJsonDocument;
class QEasingCurve;
class QWidget;
@ -327,9 +323,6 @@ Q_DECLARE_BUILTIN_METATYPE(QPointF, QPointF)
Q_DECLARE_BUILTIN_METATYPE(QRegExp, QRegExp)
#endif
Q_DECLARE_BUILTIN_METATYPE(QEasingCurve, QEasingCurve)
Q_DECLARE_BUILTIN_METATYPE(QJsonValue, QJsonValue)
Q_DECLARE_BUILTIN_METATYPE(QJsonObject, QJsonObject)
Q_DECLARE_BUILTIN_METATYPE(QJsonArray, QJsonArray)
Q_DECLARE_BUILTIN_METATYPE(QJsonDocument, QJsonDocument)
// QVariantHash
// QVariantList

View file

@ -36,9 +36,6 @@
#ifndef QT_BOOTSTRAPPED
# include "qeasingcurve.h"
# include "qjsonvalue.h"
# include "qjsonobject.h"
# include "qjsonarray.h"
# include "qjsondocument.h"
# include "qsize.h"
# include "qpoint.h"
@ -133,15 +130,6 @@ static void construct(QVariant::Private *x, const void *copy)
case QVariant::EasingCurve:
v_construct<QEasingCurve>(x, copy);
break;
case QVariant::JsonValue:
v_construct<QJsonValue>(x, copy);
break;
case QVariant::JsonObject:
v_construct<QJsonObject>(x, copy);
break;
case QVariant::JsonArray:
v_construct<QJsonArray>(x, copy);
break;
case QVariant::JsonDocument:
v_construct<QJsonDocument>(x, copy);
break;
@ -265,15 +253,6 @@ static void clear(QVariant::Private *d)
case QVariant::EasingCurve:
v_clear<QEasingCurve>(d);
break;
case QVariant::JsonValue:
v_clear<QJsonValue>(d);
break;
case QVariant::JsonObject:
v_clear<QJsonObject>(d);
break;
case QVariant::JsonArray:
v_clear<QJsonArray>(d);
break;
case QVariant::JsonDocument:
v_clear<QJsonDocument>(d);
break;
@ -335,12 +314,8 @@ static bool isNull(const QVariant::Private *d)
return v_cast<QPoint>(d)->isNull();
case QVariant::PointF:
return v_cast<QPointF>(d)->isNull();
case QVariant::JsonValue:
return v_cast<QJsonValue>(d)->isNull();
case QVariant::JsonDocument:
return v_cast<QJsonDocument>(d)->isNull();
case QVariant::JsonObject:
case QVariant::JsonArray:
case QVariant::EasingCurve:
case QVariant::Url:
#endif
@ -464,12 +439,6 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b)
#ifndef QT_BOOTSTRAPPED
case QVariant::EasingCurve:
return *v_cast<QEasingCurve>(a) == *v_cast<QEasingCurve>(b);
case QVariant::JsonValue:
return *v_cast<QJsonValue>(a) == *v_cast<QJsonValue>(b);
case QVariant::JsonObject:
return *v_cast<QJsonObject>(a) == *v_cast<QJsonObject>(b);
case QVariant::JsonArray:
return *v_cast<QJsonArray>(a) == *v_cast<QJsonArray>(b);
case QVariant::JsonDocument:
return *v_cast<QJsonDocument>(a) == *v_cast<QJsonDocument>(b);
#endif
@ -534,10 +503,6 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d)
return qRound64(d->data.f);
case QVariant::Double:
return qRound64(d->data.d);
#ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue:
return v_cast<QJsonValue>(d)->toDouble(0.0);
#endif
}
Q_ASSERT(false);
return 0;
@ -574,12 +539,6 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok)
return v_cast<QByteArray>(d)->toLongLong(ok);
case QVariant::Bool:
return qlonglong(d->data.b);
#ifndef QT_BOOTSTRAPPED
case QVariant::JsonValue:
if (!v_cast<QJsonValue>(d)->isDouble())
break;
return qlonglong(v_cast<QJsonValue>(d)->toDouble(0.0));
#endif
case QVariant::Double:
case QVariant::Int:
case QMetaType::Char:
@ -613,12 +572,6 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok)
return v_cast<QByteArray>(d)->toULongLong(ok);
case QVariant::Bool:
return qulonglong(d->data.b);
#ifndef QT_BOOTSTRAPPED
case QVariant::JsonValue:
if (!v_cast<QJsonValue>(d)->isDouble())
break;
return qulonglong(v_cast<QJsonValue>(d)->toDouble(0.0));
#endif
case QVariant::Double:
case QVariant::Int:
case QMetaType::Char:
@ -716,12 +669,6 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QVariant::Url:
*str = v_cast<QUrl>(d)->toString();
return true;
case QMetaType::QJsonValue:
if (v_cast<QJsonValue>(d)->isString()) {
*str = v_cast<QJsonValue>(d)->toString();
return true;
}
return false;
#endif
default:
return false;
@ -946,13 +893,6 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QMetaType::ULong:
*static_cast<bool *>(result) = qMetaTypeUNumber(d) != Q_UINT64_C(0);
return true;
#ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue:
if (!v_cast<QJsonValue>(d)->isBool())
return false;
*static_cast<bool *>(result) = v_cast<QJsonValue>(d)->toBool(false);
return true;
#endif
default:
return false;
}
@ -986,13 +926,6 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QMetaType::ULong:
*static_cast<double *>(result) = double(qMetaTypeUNumber(d));
return true;
#ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue:
if (!v_cast<QJsonValue>(d)->isDouble())
return false;
*static_cast<double *>(result) = v_cast<QJsonValue>(d)->toDouble(0.0);
return true;
#endif
default:
return false;
}
@ -1026,13 +959,6 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QMetaType::ULong:
*static_cast<float *>(result) = float(qMetaTypeUNumber(d));
return true;
#ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue:
if (!v_cast<QJsonValue>(d)->isDouble())
return false;
*static_cast<float *>(result) = v_cast<QJsonValue>(d)->toDouble(0.0);
return true;
#endif
default:
return false;
}
@ -1047,48 +973,18 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
} else if (d->type == QVariant::List) {
*static_cast<QVariantList *>(result) = *static_cast<QList<QVariant> *>(d->data.shared->ptr);
return true;
#ifndef QT_BOOTSTRAPPED
} else if (d->type == QMetaType::QJsonValue) {
if (!v_cast<QJsonValue>(d)->isArray())
return false;
*static_cast<QVariantList *>(result) = v_cast<QJsonValue>(d)->toArray().toVariantList();
return true;
} else if (d->type == QMetaType::QJsonArray) {
*static_cast<QVariantList *>(result) = v_cast<QJsonArray>(d)->toVariantList();
return true;
#endif
}
return false;
case QVariant::Map:
if (d->type == QVariant::Map) {
*static_cast<QVariantMap *>(result) = *static_cast<QMap<QString, QVariant> *>(d->data.shared->ptr);
return true;
#ifndef QT_BOOTSTRAPPED
} else if (d->type == QMetaType::QJsonValue) {
if (!v_cast<QJsonValue>(d)->isObject())
return false;
*static_cast<QVariantMap *>(result) = v_cast<QJsonValue>(d)->toObject().toVariantMap();
return true;
} else if (d->type == QMetaType::QJsonObject) {
*static_cast<QVariantMap *>(result) = v_cast<QJsonObject>(d)->toVariantMap();
return true;
#endif
}
return false;
case QVariant::Hash:
if (d->type == QVariant::Hash) {
*static_cast<QVariantHash *>(result) = *static_cast<QHash<QString, QVariant> *>(d->data.shared->ptr);
return true;
#ifndef QT_BOOTSTRAPPED
} else if (d->type == QMetaType::QJsonValue) {
if (!v_cast<QJsonValue>(d)->isObject())
return false;
*static_cast<QVariantHash *>(result) = v_cast<QJsonValue>(d)->toObject().toVariantHash();
return true;
} else if (d->type == QMetaType::QJsonObject) {
*static_cast<QVariantHash *>(result) = v_cast<QJsonObject>(d)->toVariantHash();
return true;
#endif
}
return false;
#ifndef QT_BOOTSTRAPPED
@ -1187,15 +1083,6 @@ static void streamDebug(QDebug dbg, const QVariant &v)
case QVariant::EasingCurve:
dbg.nospace() << v.toEasingCurve();
break;
case QVariant::JsonValue:
dbg.nospace() << v.toJsonValue();
break;
case QVariant::JsonObject:
dbg.nospace() << v.toJsonObject();
break;
case QVariant::JsonArray:
dbg.nospace() << v.toJsonArray();
break;
case QVariant::JsonDocument:
dbg.nospace() << v.toJsonDocument();
break;
@ -1368,9 +1255,6 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value DateTime a QDateTime
\value Double a double
\value EasingCurve a QEasingCurve
\value QJsonValue QJsonValue
\value QJsonObject QJsonObject
\value QJsonArray QJsonArray
\value QJsonDocument QJsonDocument
\value Font a QFont
\value Hash a QVariantHash
@ -1586,27 +1470,6 @@ QVariant::QVariant(const char *val)
Constructs a new variant with a date/time value, \a val.
*/
/*!
\since 4.9
\fn QVariant::QVariant(const QJsonValue &val)
Constructs a new variant with a json value, \a val.
*/
/*!
\since 4.9
\fn QVariant::QVariant(const QJsonObject &val)
Constructs a new variant with a json object value, \a val.
*/
/*!
\since 4.9
\fn QVariant::QVariant(const QJsonArray &val)
Constructs a new variant with a json array value, \a val.
*/
/*!
\since 4.9
\fn QVariant::QVariant(const QJsonDocument &val)
@ -1812,9 +1675,6 @@ QVariant::QVariant(const QDateTime &val)
#ifndef QT_BOOTSTRAPPED
QVariant::QVariant(const QEasingCurve &val)
{ d.is_null = false; d.type = EasingCurve; v_construct<QEasingCurve>(&d, val); }
QVariant::QVariant(const QJsonValue &jsonValue) { d.is_null = false; d.type = JsonValue; v_construct<QJsonValue>(&d, jsonValue); }
QVariant::QVariant(const QJsonObject &jsonObject) { d.is_null = false; d.type = JsonObject; v_construct<QJsonObject>(&d, jsonObject); }
QVariant::QVariant(const QJsonArray &jsonArray) { d.is_null = false; d.type = JsonArray; v_construct<QJsonArray>(&d, jsonArray); }
QVariant::QVariant(const QJsonDocument &jsonDocument) { d.is_null = false; d.type = JsonDocument; v_construct<QJsonDocument>(&d, jsonDocument); }
#endif
QVariant::QVariant(const QList<QVariant> &list)
@ -2251,45 +2111,6 @@ QEasingCurve QVariant::toEasingCurve() const
return qVariantToHelper<QEasingCurve>(d, EasingCurve, handler);
}
/*!
\since 4.9
Returns the variant as a QJsonValue if the variant has userType() \l
QJsonValue; otherwise returns a default constructed QJsonValue.
\sa canConvert(), convert()
*/
QJsonValue QVariant::toJsonValue() const
{
return qVariantToHelper<QJsonValue>(d, JsonValue, handler);
}
/*!
\since 4.9
Returns the variant as a QJsonObject if the variant has userType() \l
QJsonObject; otherwise returns a default constructed QJsonObject.
\sa canConvert(), convert()
*/
QJsonObject QVariant::toJsonObject() const
{
return qVariantToHelper<QJsonObject>(d, JsonObject, handler);
}
/*!
\since 4.9
Returns the variant as a QJsonArray if the variant has userType() \l
QJsonArray; otherwise returns a default constructed QJsonArray.
\sa canConvert(), convert()
*/
QJsonArray QVariant::toJsonArray() const
{
return qVariantToHelper<QJsonArray>(d, JsonArray, handler);
}
/*!
\since 4.9
@ -2972,44 +2793,6 @@ bool QVariant::canConvert(Type t) const
/* RegExp */
/* Hash */
/* EasingCurve */
} else if (d.type == QVariant::JsonValue) {
switch (int(t)) {
case QVariant::String:
case QVariant::Bool:
case QVariant::Int:
case QVariant::UInt:
case QVariant::Double:
case QVariant::Float:
case QMetaType::ULong:
case QMetaType::Long:
case QVariant::LongLong:
case QVariant::ULongLong:
case QMetaType::UShort:
case QMetaType::UChar:
case QMetaType::Char:
case QMetaType::Short:
case QVariant::List:
case QVariant::Map:
case QVariant::Hash:
return true;
default:
return false;
}
} else if (d.type == QVariant::JsonObject) {
switch (t) {
case QVariant::Map:
case QVariant::Hash:
return true;
default:
return false;
}
} else if (d.type == QVariant::JsonArray) {
switch (t) {
case QVariant::List:
return true;
default:
return false;
}
/* JsonDocument */
} else if (t == QVariant::Font) {
switch (d.type) {

View file

@ -36,9 +36,6 @@ class QDate;
class QDateTime;
#ifndef QT_BOOTSTRAPPED
class QEasingCurve;
class QJsonValue;
class QJsonObject;
class QJsonArray;
class QJsonDocument;
#endif
class QLine;
@ -105,9 +102,6 @@ class Q_CORE_EXPORT QVariant
RegExp = QMetaType::QRegExp,
Hash = QMetaType::QVariantHash,
EasingCurve = QMetaType::QEasingCurve,
JsonValue = QMetaType::QJsonValue,
JsonObject = QMetaType::QJsonObject,
JsonArray = QMetaType::QJsonArray,
JsonDocument = QMetaType::QJsonDocument,
LastCoreType = QMetaType::LastCoreType,
@ -191,9 +185,6 @@ class Q_CORE_EXPORT QVariant
#endif
#ifndef QT_BOOTSTRAPPED
QVariant(const QEasingCurve &easing);
QVariant(const QJsonValue &jsonValue);
QVariant(const QJsonObject &jsonObject);
QVariant(const QJsonArray &jsonArray);
QVariant(const QJsonDocument &jsonDocument);
#endif
@ -258,9 +249,6 @@ class Q_CORE_EXPORT QVariant
#endif
#ifndef QT_BOOTSTRAPPED
QEasingCurve toEasingCurve() const;
QJsonValue toJsonValue() const;
QJsonObject toJsonObject() const;
QJsonArray toJsonArray() const;
QJsonDocument toJsonDocument() const;
#endif

View file

@ -0,0 +1,408 @@
/****************************************************************************
**
** Copyright (C) 2020 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjsondocument.h"
#include "qstringlist.h"
#include "qvariant.h"
#include "qscopedpointer.h"
#include "qcoreapplication.h"
#include <jansson.h>
QT_BEGIN_NAMESPACE
class QJsonDocumentPrivate {
public:
QJsonDocumentPrivate() : ref(1) { }
QVariantMap jsonToMap(const QByteArray &jsondata);
QByteArray mapToJson(const QVariantMap &jsonmap);
QAtomicInt ref;
QByteArray json;
QVariantMap map;
QString error;
};
QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
{
QVariantMap result;
if (jsondata.isEmpty()) {
error = QCoreApplication::translate("QJsonDocument", "Data is empty");
return result;
}
json_error_t jerror;
json_t *jroot = json_loads(jsondata.constData(), 0, &jerror);
if (!jroot) {
error = jerror.text;
return result;
}
switch(json_typeof(jroot)) {
case JSON_OBJECT: {
const char *jkey;
json_t *jobject;
json_object_foreach(jroot, jkey, jobject) {
switch(json_typeof(jobject)) {
case JSON_OBJECT: {
result.insert(jkey, jsonToMap(json_dumps(jobject, 0)));
break;
}
case JSON_ARRAY: {
QVariantList listvalue;
for (size_t i = 0; i < json_array_size(jobject); i++) {
json_t *jarray = json_array_get(jobject, i);
switch(json_typeof(jarray)) {
case JSON_OBJECT: {
listvalue.append(jsonToMap(json_dumps(jarray, 0)));
break;
}
case JSON_STRING: {
listvalue.append(QVariant(json_string_value(jarray)));
break;
}
case JSON_INTEGER: {
listvalue.append(QVariant(json_integer_value(jarray)));
break;
}
case JSON_REAL: {
listvalue.append(QVariant(json_real_value(jarray)));
break;
}
case JSON_TRUE: {
listvalue.append(QVariant(true));
break;
}
case JSON_FALSE: {
listvalue.append(QVariant(false));
break;
}
case JSON_NULL: {
listvalue.append(QVariant());
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown JSON type in array");
break;
}
}
}
result.insert(jkey, listvalue);
break;
}
case JSON_STRING: {
result.insert(jkey, QVariant(json_string_value(jobject)));
break;
}
case JSON_INTEGER: {
result.insert(jkey, QVariant(json_integer_value(jobject)));
break;
}
case JSON_REAL: {
result.insert(jkey, QVariant(json_real_value(jobject)));
break;
}
case JSON_TRUE: {
result.insert(jkey, QVariant(true));
break;
}
case JSON_FALSE: {
result.insert(jkey, QVariant(false));
break;
}
case JSON_NULL: {
result.insert(jkey, QVariant());
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown JSON type");
break;
}
}
}
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Rootless array/values are not supported");
break;
}
}
json_decref(jroot);
// qDebug() << "converted" << jsondata << "to" << result;
return result;
}
QByteArray QJsonDocumentPrivate::mapToJson(const QVariantMap &jsonmap)
{
QByteArray result;
if (jsonmap.isEmpty()) {
error = QCoreApplication::translate("QJsonDocument", "Data map is empty");
return result;
}
static const size_t jflags = JSON_SORT_KEYS | JSON_INDENT(4);
json_t *jroot = json_object();
foreach(const QString &key, jsonmap.keys()) {
const QVariant value = jsonmap.value(key);
const QByteArray bytearraykey = key.toUtf8();
switch(value.type()) {
case QVariant::Invalid: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_null());
break;
}
case QVariant::Bool: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), value.toBool() ? json_true() : json_false());
break;
}
case QVariant::Int:
case QVariant::LongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toLongLong()));
break;
}
case QVariant::UInt:
case QVariant::ULongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toULongLong()));
break;
}
case QVariant::Float:
case QVariant::Double: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_real(value.toReal()));
break;
}
case QVariant::Char:
case QVariant::ByteArray:
case QVariant::String: {
const QByteArray bytearrayvalue = value.toByteArray();
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_string(bytearrayvalue.constData()));
break;
}
case QVariant::List: // TODO: this works only for QString-convertable types
case QVariant::StringList: {
json_t *jarray = json_array();
foreach(const QString &listvalue, value.toStringList()) {
const QByteArray bytearrayvalue = listvalue.toUtf8();
json_array_append_new(jarray, json_stringn_nocheck(bytearrayvalue.constData(), bytearrayvalue.size()));
}
json_object_set_new_nocheck(jroot, bytearraykey.constData(), jarray);
break;
}
case QVariant::Hash:
case QVariant::Map: {
result += mapToJson(value.toMap());
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown JSON type");
break;
}
}
}
result += json_dumps(jroot, jflags);
json_decref(jroot);
// qDebug() << "converted" << jsonmap << "to" << result;
return result;
}
QJsonDocument::QJsonDocument()
: d_ptr(Q_NULLPTR)
{
}
QJsonDocument::~QJsonDocument()
{
Q_D(QJsonDocument);
if (d && !d->ref.deref()) {
delete d;
}
}
QJsonDocument::QJsonDocument(const QJsonDocument &other)
{
qAtomicAssign(d_ptr, other.d_ptr);
}
/*!
Assigns the \a other document to this QJsonDocument.
Returns a reference to this object.
*/
QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
{
qAtomicAssign(d_ptr, other.d_ptr);
return *this;
}
/*!
Creates a QJsonDocument from the QVariant \a variant.
If the \a variant contains any other type than a QVariant::Invalid,
QVariant::Bool, QVariant::Int, QVariant::LongLong, QVariant::UInt,
QVariant::ULongLong, QVariant::Float, QVariant::Double, QVariant::Char,
QVariant::ByteArray, QVariant::String, QVariant::List,
QVariant::StringList, QVariant::Hash or QVariant::Map the returned document
is null.
\sa toVariant()
*/
QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
{
QScopedPointer<QJsonDocumentPrivate> d(new QJsonDocumentPrivate());
d->map = variant.toMap();
d->json = d->mapToJson(d->map);
QJsonDocument jd;
if (Q_UNLIKELY(!d->error.isEmpty())) {
d->json.clear();
d->map.clear();
}
jd.d_ptr = d.take();
// qDebug() << "QJsonDocument::fromVariant" << jd.errorString();
return jd;
}
/*!
Returns a QVariant representing the Json document.
The returned variant will be a QVariantList if the document is
a array and a QVariantMap if the document is a object.
\sa fromVariant()
*/
QVariant QJsonDocument::toVariant() const
{
Q_D(const QJsonDocument);
if (!d) {
return QVariant();
}
return d->map;
}
/*!
Parses a UTF-8 encoded JSON document and creates a QJsonDocument
from it.
\a json contains the json document to be parsed.
\sa toJson(), errorString()
*/
QJsonDocument QJsonDocument::fromJson(const QByteArray &json)
{
QScopedPointer<QJsonDocumentPrivate> d(new QJsonDocumentPrivate());
d->json = json;
d->map = d->jsonToMap(json);
if (Q_UNLIKELY(!d->error.isEmpty())) {
d->json.clear();
d->map.clear();
}
QJsonDocument jd;
jd.d_ptr = d.take();
// qDebug() << "QJsonDocument::fromJson" << jd.errorString();
return jd;
}
QByteArray QJsonDocument::toJson() const
{
Q_D(const QJsonDocument);
if (!d) {
return QByteArray();
}
return d->json;
}
/*!
Returns \c true if the \a other document is equal to this document.
*/
bool QJsonDocument::operator==(const QJsonDocument &other) const
{
Q_D(const QJsonDocument);
if (d == other.d_ptr) {
return true;
}
if (!d || !other.d_ptr) {
return false;
}
return (d->json == other.d_ptr->json && d->map == other.d_ptr->map);
}
/*!
\fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
returns \c true if \a other is not equal to this document
*/
/*!
returns true if this document is null.
Null documents are documents created through the default constructor.
Documents created from UTF-8 encoded text are validated during parsing. If
validation fails, the returned document will be null.
*/
bool QJsonDocument::isNull() const
{
Q_D(const QJsonDocument);
return (!d || (d->json.isEmpty() && d->map.isEmpty()));
}
QString QJsonDocument::errorString() const
{
Q_D(const QJsonDocument);
if (!d) {
return QString();
}
return d->error;
}
QDebug operator<<(QDebug dbg, const QJsonDocument &jd)
{
if (jd.isNull()) {
dbg << "QJsonDocument()";
return dbg;
}
dbg.nospace() << "QJsonDocument("
<< jd.toJson().constData()
<< ")";
return dbg.space();
}
QT_END_NAMESPACE

View file

@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2020 Ivailo Monev
**
** This file is part of the QtCore module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJSONDOCUMENT_H
#define QJSONDOCUMENT_H
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
class QJsonDocumentPrivate;
class Q_CORE_EXPORT QJsonDocument
{
Q_DECLARE_PRIVATE(QJsonDocument)
public:
QJsonDocument();
~QJsonDocument();
QJsonDocument(const QJsonDocument &other);
QJsonDocument &operator =(const QJsonDocument &other);
static QJsonDocument fromVariant(const QVariant &variant);
QVariant toVariant() const;
static QJsonDocument fromJson(const QByteArray &json);
QByteArray toJson() const;
bool isNull() const;
QString errorString() const;
bool operator==(const QJsonDocument &other) const;
bool operator!=(const QJsonDocument &other) const {
return !(*this == other);
}
private:
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
QJsonDocumentPrivate *d_ptr;
};
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
QT_END_NAMESPACE
#endif // QJSONDOCUMENT_H

View file

@ -371,14 +371,7 @@ static const struct ClassTblData {
{ QLatin1String("QItemSelection"), QLatin1String("QtGui/qitemselectionmodel.h") },
{ QLatin1String("QItemSelectionModel"), QLatin1String("QtGui/qitemselectionmodel.h") },
{ QLatin1String("QItemSelectionRange"), QLatin1String("QtGui/qitemselectionmodel.h") },
{ QLatin1String("QJsonArray"), QLatin1String("QtCore/qjsonarray.h") },
{ QLatin1String("QJsonDocument"), QLatin1String("QtCore/qjsondocument.h") },
{ QLatin1String("QJsonObject"), QLatin1String("QtCore/qjsonobject.h") },
{ QLatin1String("QJsonParseError"), QLatin1String("QtCore/qjsondocument.h") },
{ QLatin1String("QJsonValue"), QLatin1String("QtCore/qjsonvalue.h") },
{ QLatin1String("QJsonValuePtr"), QLatin1String("QtCore/qjsonvalue.h") },
{ QLatin1String("QJsonValueRef"), QLatin1String("QtCore/qjsonvalue.h") },
{ QLatin1String("QJsonValueRefPtr"), QLatin1String("QtCore/qjsonvalue.h") },
{ QLatin1String("QKeyEvent"), QLatin1String("QtGui/qevent.h") },
{ QLatin1String("QKeySequence"), QLatin1String("QtGui/qkeysequence.h") },
{ QLatin1String("QLCDNumber"), QLatin1String("QtGui/qlcdnumber.h") },

View file

@ -0,0 +1,3 @@
katie_test(tst_qjsondocument
${CMAKE_CURRENT_SOURCE_DIR}/tst_qjsondocument.cpp
)

View file

@ -0,0 +1,5 @@
{
"Qt/GUIEffects": [
"none"
],
}

View file

@ -0,0 +1,35 @@
{
"Qt/GUIEffects": [
"none"
],
"Qt/Palette/active": [
],
"Qt/Palette/disabled": [
],
"Qt/Palette/inactive": [
],
"Qt/cursorFlashTime": 1000,
"Qt/doubleClickInterval": 400,
"Qt/embedFonts": true,
"Qt/font": "Sans Serif,9,-1,5,50,0,0,0,0",
"Qt/fontPath": [
],
"Qt/globalStrut/height": 0,
"Qt/globalStrut/width": 0,
"Qt/resolveSymlinks": false,
"Qt/style": "Cleanlooks",
"Qt/useRtlExtensions": false,
"Qt/wheelScrollLines": 3,
"MixedArray": [
1,
"a"
],
"NestedObject": {
"MixedArray": [
2,
"b"
]
}
}

View file

@ -0,0 +1,147 @@
/****************************************************************************
**
** Copyright (C) 2021 Ivailo Monev
**
** This file is part of the test suite of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtCore/QtCore>
//TESTED_CLASS=QJsonDocument
//TESTED_FILES=qjsondocument.cpp,qjsondocument.h
static QString testinvalidfile = QString::fromLatin1(SRCDIR "/invalidjson.json");
static QString testjsonfile = QString::fromLatin1(SRCDIR "/qjsondocument.json");
static QVariantMap testjsondata;
class tst_QJsonDocument : public QObject
{
Q_OBJECT
public slots:
void init();
void cleanup();
private slots:
void read();
void write();
void error();
};
void tst_QJsonDocument::init()
{
testjsondata.insert("Qt/GUIEffects", QStringList() << "none");
testjsondata.insert("Qt/doubleClickInterval", 400);
testjsondata.insert("Qt/embedFonts", true);
testjsondata.insert("Qt/style", "Cleanlooks");
testjsondata.insert("MixedArray", QVariantList() << 1 << "a");
QVariantMap NestedObject;
NestedObject.insert("MixedArray", QVariantList() << 2 << "b");
testjsondata.insert("NestedObject", NestedObject);
}
void tst_QJsonDocument::cleanup()
{
testjsondata.clear();
}
void tst_QJsonDocument::read()
{
QJsonDocument jsondoc = QJsonDocument::fromVariant(testjsondata);
QVERIFY(jsondoc.errorString().isEmpty());
QVariantMap jsonmap = jsondoc.toVariant().toMap();
QStringList GUIEffects = jsonmap.value("Qt/GUIEffects").toStringList();
QCOMPARE(GUIEffects, QStringList() << "none");
int doubleClickInterval = jsonmap.value("Qt/doubleClickInterval").toInt();
QCOMPARE(doubleClickInterval, 400);
bool embedFonts = jsonmap.value("Qt/embedFonts").toBool();
QCOMPARE(embedFonts, true);
QString style = jsonmap.value("Qt/style").toString();
QCOMPARE(style, QLatin1String("Cleanlooks"));
QVariantList MixedArray = jsonmap.value("MixedArray").toList();
QCOMPARE(MixedArray, QVariantList() << 1 << "a");
QVariantList NestedObject = jsonmap.value("NestedObject").toMap().value("MixedArray").toList();
QCOMPARE(NestedObject, QVariantList() << 2 << "b");
QFile jsonfile(testjsonfile);
QVERIFY(jsonfile.open(QIODevice::ReadOnly));
jsondoc = QJsonDocument::fromJson(jsonfile.readAll());
QVERIFY(jsondoc.errorString().isEmpty());
jsonmap = jsondoc.toVariant().toMap();
GUIEffects = jsonmap.value("Qt/GUIEffects").toStringList();
QCOMPARE(GUIEffects, QStringList() << "none");
doubleClickInterval = jsonmap.value("Qt/doubleClickInterval").toInt();
QCOMPARE(doubleClickInterval, 400);
embedFonts = jsonmap.value("Qt/embedFonts").toBool();
QCOMPARE(embedFonts, true);
style = jsonmap.value("Qt/style").toString();
QCOMPARE(style, QLatin1String("Cleanlooks"));
MixedArray = jsonmap.value("MixedArray").toList();
QCOMPARE(MixedArray, QVariantList() << 1 << "a");
NestedObject = jsonmap.value("NestedObject").toMap().value("MixedArray").toList();
QCOMPARE(NestedObject, QVariantList() << 2 << "b");
// TODO: test other types too
}
void tst_QJsonDocument::write()
{
QJsonDocument jsondoc = QJsonDocument::fromVariant(testjsondata);
// TODO: compare to desired output
QVERIFY(!jsondoc.toJson().isEmpty());
QFile jsonfile(testjsonfile);
QVERIFY(jsonfile.open(QIODevice::ReadOnly));
QByteArray jsoncontent = jsonfile.readAll();
jsondoc = QJsonDocument::fromJson(jsoncontent);
QCOMPARE(jsoncontent, jsondoc.toJson());
}
void tst_QJsonDocument::error()
{
QFile jsonfile(testinvalidfile);
QVERIFY(jsonfile.open(QIODevice::ReadOnly));
QJsonDocument jsondoc = QJsonDocument::fromJson(jsonfile.readAll());
// not testing for specific string on purpose
QVERIFY(!jsondoc.errorString().isEmpty());
QVERIFY(jsondoc.isNull());
jsondoc = QJsonDocument::fromVariant(QVariantMap());
QCOMPARE(jsondoc.errorString(), QLatin1String("Data map is empty"));
QVERIFY(jsondoc.isNull());
// TODO: indermediate error test
}
QTEST_MAIN(tst_QJsonDocument)
#include "moc_tst_qjsondocument.cpp"

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-05 06:17+0200\n"
"POT-Creation-Date: 2021-02-11 01:35+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,11 +17,11 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/tools/qtconfig/previewframe.cpp:75
#: src/tools/qtconfig/previewframe.cpp:63
msgid "Desktop settings will only take effect after an application restart."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:68
#: src/tools/qtconfig/mainwindow.cpp:56
msgctxt "MainWindow"
msgid ""
"<p><b><font size+=2>Appearance</font></b></p><hr><p>Use this tab to "
@ -36,7 +36,7 @@ msgid ""
"Window shows what the selected Style and colors look like."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:84
#: src/tools/qtconfig/mainwindow.cpp:72
msgctxt "MainWindow"
msgid ""
"<p><b><font size+=2>Fonts</font></b></p><hr><p>Use this tab to select the "
@ -54,7 +54,7 @@ msgid ""
"text)."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:103
#: src/tools/qtconfig/mainwindow.cpp:91
msgctxt "MainWindow"
msgid ""
"<p><b><font size+=2>Interface</font></b></p><hr><p>Use this tab to customize "
@ -69,7 +69,7 @@ msgid ""
"disable the Global Strut feature."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:118
#: src/tools/qtconfig/mainwindow.cpp:106
msgctxt "MainWindow"
msgid ""
"<p><b><font size+=2>Printer</font></b></p><hr><p>Use this tab to configure "
@ -82,755 +82,755 @@ msgid ""
"the X server font path is used."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:201
#: src/tools/qtconfig/mainwindow.cpp:189
msgid "Desktop Settings (Default)"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:207
#: src/tools/qtconfig/mainwindow.cpp:195
msgid "Choose style and palette based on your desktop settings."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:222
#: src/tools/qtconfig/mainwindow.cpp:210
msgid "Unknown"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:368
#: src/tools/qtconfig/mainwindow.cpp:356
msgid "No changes to be saved."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:372
#: src/tools/qtconfig/mainwindow.cpp:360
msgid "Saving changes..."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:457
#: src/tools/qtconfig/mainwindow.cpp:445
msgid "Saved changes."
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:723
#: src/tools/qtconfig/mainwindow.cpp:711
msgid "Select a Directory"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:738
#: src/tools/qtconfig/mainwindow.cpp:726
msgid ""
"<h3>%1</h3><br/>Version %2<br/><br/>Copyright (C) 2015 The Qt Company Ltd."
"<br/><br/>Copyright (C) 2016 Ivailo Monev"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:743 src/tools/qtconfig/mainwindow.cpp:744
#: src/tools/qtconfig/mainwindow.cpp:751
#: src/tools/qtconfig/mainwindow.cpp:731 src/tools/qtconfig/mainwindow.cpp:732
#: src/tools/qtconfig/mainwindow.cpp:739
msgid "Katie Configuration"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:770
#: src/tools/qtconfig/mainwindow.cpp:758
msgid "Save Changes"
msgstr ""
#: src/tools/qtconfig/mainwindow.cpp:771
#: src/tools/qtconfig/mainwindow.cpp:759
msgid "Save changes to settings?"
msgstr ""
#: src/tools/qtconfig/paletteeditoradvanced.cpp:46
#: src/tools/qtconfig/paletteeditoradvanced.cpp:52
#: src/tools/qtconfig/paletteeditoradvanced.cpp:34
#: src/tools/qtconfig/paletteeditoradvanced.cpp:40
msgid "Choose a color"
msgstr ""
#: src/tools/qtconfig/paletteeditoradvanced.cpp:47
#: src/tools/qtconfig/paletteeditoradvanced.cpp:35
msgid "Choose a color for the selected central color role."
msgstr ""
#: src/tools/qtconfig/paletteeditoradvanced.cpp:53
#: src/tools/qtconfig/paletteeditoradvanced.cpp:41
msgid "Choose a color for the selected effect color role."
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:63
#: src/tools/qdbusviewer/qdbusviewermain.cpp:51
msgctxt "QtDBusViewer"
msgid "Katie D-Bus Viewer"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:70
#: src/tools/qdbusviewer/qdbusviewermain.cpp:58
msgid "Session Bus"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:71
#: src/tools/qdbusviewer/qdbusviewermain.cpp:59
msgid "System Bus"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:73
#: src/tools/designer/qdesigner_workbench.cpp:188
#: src/tools/qdbusviewer/qdbusviewermain.cpp:61
#: src/tools/designer/qdesigner_workbench.cpp:176
msgid "&File"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:74
#: src/tools/designer/qdesigner_actions.cpp:177
#: src/tools/qdbusviewer/qdbusviewermain.cpp:62
#: src/tools/designer/qdesigner_actions.cpp:165
msgid "&Quit"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:77
#: src/tools/designer/qdesigner_workbench.cpp:205
#: src/tools/qdbusviewer/qdbusviewermain.cpp:65
#: src/tools/designer/qdesigner_workbench.cpp:193
msgid "&Help"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:78
#: src/tools/qdbusviewer/qdbusviewermain.cpp:66
msgid "&About"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewermain.cpp:82
#: src/tools/qdbusviewer/qdbusviewermain.cpp:70
msgid "About &Katie"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:75
#: src/tools/qdbusviewer/qdbusviewer.cpp:63
msgid "Search..."
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:86
#: src/tools/qdbusviewer/qdbusviewer.cpp:74
msgid "&Refresh"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:202
#: src/tools/qdbusviewer/qdbusviewer.cpp:190
msgid "Arguments"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:203
#: src/tools/qdbusviewer/qdbusviewer.cpp:191
msgid "Please enter the value of the property %1 (type %2)"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:211
#: src/tools/qdbusviewer/qdbusviewer.cpp:199
msgid "Unable to marshall"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:212
#: src/tools/qdbusviewer/qdbusviewer.cpp:200
msgid "Value conversion failed, unable to set property"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:249
#: src/tools/qdbusviewer/qdbusviewer.cpp:237
msgid "Unable to find method"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:250
#: src/tools/qdbusviewer/qdbusviewer.cpp:238
msgid "Unable to find method %1 on path %2 in interface %3"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:272
#: src/tools/qdbusviewer/qdbusviewer.cpp:260
msgid "Please enter parameters for the method \"%1\""
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:322
#: src/tools/qdbusviewer/qdbusviewer.cpp:310
msgid "&Connect"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:327
#: src/tools/qdbusviewer/qdbusviewer.cpp:315
msgid "&Call"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:332
#: src/tools/qdbusviewer/qdbusviewer.cpp:320
msgid "&Set value"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:334
#: src/tools/qdbusviewer/qdbusviewer.cpp:322
msgid "&Get value"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:367
#: src/tools/qdbusviewer/qdbusviewer.cpp:355
msgid "Unable to connect to service %1, path %2, interface %3, signal %4"
msgstr ""
#: src/tools/qdbusviewer/qdbusviewer.cpp:489
#: src/tools/qdbusviewer/qdbusviewer.cpp:490
#: src/tools/qdbusviewer/qdbusviewer.cpp:477
#: src/tools/qdbusviewer/qdbusviewer.cpp:478
msgid "D-Bus Viewer"
msgstr ""
#: src/tools/designer/versiondialog.cpp:158
#: src/tools/designer/versiondialog.cpp:146
msgid "<h3>%1</h3><br/><br/>Version %2"
msgstr ""
#: src/tools/designer/versiondialog.cpp:159
#: src/tools/designer/mainwindow.cpp:127
#: src/tools/designer/versiondialog.cpp:147
#: src/tools/designer/mainwindow.cpp:115
msgid "Katie Designer"
msgstr ""
#: src/tools/designer/versiondialog.cpp:160
#: src/tools/designer/versiondialog.cpp:148
msgid ""
"<br/>Katie Designer is a graphical user interface designer for Qt "
"applications.<br/>"
msgstr ""
#: src/tools/designer/versiondialog.cpp:162
#: src/tools/designer/versiondialog.cpp:150
msgid ""
"%1<br/>Copyright (C) 2015 The Qt Company Ltd.<br/>Copyright (C) 2016 Ivailo "
"Monev"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:143
#: src/tools/designer/appfontdialog.cpp:131
msgctxt "AppFontManager"
msgid "'%1' is not a file."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:147
#: src/tools/designer/appfontdialog.cpp:135
msgctxt "AppFontManager"
msgid "The font file '%1' does not have read permissions."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:155
#: src/tools/designer/appfontdialog.cpp:143
msgctxt "AppFontManager"
msgid "The font file '%1' is already loaded."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:162
#: src/tools/designer/appfontdialog.cpp:150
msgctxt "AppFontManager"
msgid "The font file '%1' could not be loaded."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:179
#: src/tools/designer/appfontdialog.cpp:167
msgctxt "AppFontManager"
msgid "'%1' is not a valid font id."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:190
#: src/tools/designer/appfontdialog.cpp:178
msgctxt "AppFontManager"
msgid "There is no loaded font matching the id '%1'."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:205
#: src/tools/designer/appfontdialog.cpp:193
msgctxt "AppFontManager"
msgid "The font '%1' (%2) could not be unloaded."
msgstr ""
#: src/tools/designer/appfontdialog.cpp:231
#: src/tools/designer/appfontdialog.cpp:219
msgid "Fonts"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:289
#: src/tools/designer/appfontdialog.cpp:277
msgid "Add font files"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:294
#: src/tools/designer/appfontdialog.cpp:282
msgid "Remove current font file"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:298
#: src/tools/designer/appfontdialog.cpp:286
msgid "Remove all font files"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:317
#: src/tools/designer/appfontdialog.cpp:305
msgid "Add Font Files"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:318
#: src/tools/designer/appfontdialog.cpp:306
msgid "Font files (*.ttf)"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:331
#: src/tools/designer/appfontdialog.cpp:319
msgid "Error Adding Fonts"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:355
#: src/tools/designer/appfontdialog.cpp:343
msgid "Error Removing Fonts"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:377
#: src/tools/designer/appfontdialog.cpp:365
msgid "Remove Fonts"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:377
#: src/tools/designer/appfontdialog.cpp:365
msgid "Would you like to remove all fonts?"
msgstr ""
#: src/tools/designer/appfontdialog.cpp:410
#: src/tools/designer/appfontdialog.cpp:398
msgid "Additional Fonts"
msgstr ""
#: src/tools/designer/qdesigner_formwindow.cpp:209
#: src/tools/designer/qdesigner_formwindow.cpp:197
msgid "%1 - %2[*]"
msgstr ""
#: src/tools/designer/qdesigner_formwindow.cpp:219
#: src/tools/designer/qdesigner_actions.cpp:824
#: src/tools/designer/qdesigner_actions.cpp:864
#: src/tools/designer/qdesigner_formwindow.cpp:207
#: src/tools/designer/qdesigner_actions.cpp:812
#: src/tools/designer/qdesigner_actions.cpp:852
msgid "Save Form?"
msgstr ""
#: src/tools/designer/qdesigner_formwindow.cpp:220
#: src/tools/designer/qdesigner_formwindow.cpp:208
msgid "Do you want to save the changes to this document before closing?"
msgstr ""
#: src/tools/designer/qdesigner_formwindow.cpp:222
#: src/tools/designer/qdesigner_formwindow.cpp:210
msgid "If you don't save, your changes will be lost."
msgstr ""
#: src/tools/designer/newform.cpp:65
#: src/tools/designer/newform.cpp:53
msgid "Show this Dialog on Startup"
msgstr ""
#: src/tools/designer/newform.cpp:66
#: src/tools/designer/newform.cpp:54
msgctxt "NewForm"
msgid "C&reate"
msgstr ""
#: src/tools/designer/newform.cpp:67
#: src/tools/designer/newform.cpp:55
msgctxt "NewForm"
msgid "Recent"
msgstr ""
#: src/tools/designer/newform.cpp:70
#: src/tools/designer/newform.cpp:58
msgid "New Form"
msgstr ""
#: src/tools/designer/newform.cpp:99
#: src/tools/designer/newform.cpp:87
msgctxt "NewForm"
msgid "&Close"
msgstr ""
#: src/tools/designer/newform.cpp:102
#: src/tools/designer/newform.cpp:90
msgctxt "NewForm"
msgid "&Open..."
msgstr ""
#: src/tools/designer/newform.cpp:106
#: src/tools/designer/qdesigner_actions.cpp:481
#: src/tools/designer/newform.cpp:94
#: src/tools/designer/qdesigner_actions.cpp:469
msgid "&Recent Forms"
msgstr ""
#: src/tools/designer/newform.cpp:170
#: src/tools/designer/qdesigner_actions.cpp:742
#: src/tools/designer/newform.cpp:158
#: src/tools/designer/qdesigner_actions.cpp:730
msgid "Read error"
msgstr ""
#: src/tools/designer/newform.cpp:193
#: src/tools/designer/newform.cpp:181
msgid "A temporary form file could not be created in %1."
msgstr ""
#: src/tools/designer/newform.cpp:199
#: src/tools/designer/newform.cpp:187
msgid "The temporary form file %1 could not be written."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:117
#: src/tools/designer/qdesigner_actions.cpp:105
msgid "Saved %1."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:143
#: src/tools/designer/qdesigner_actions.cpp:131
msgid ""
"%1 already exists.\n"
"Do you want to replace it?"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:167
#: src/tools/designer/qdesigner_actions.cpp:155
msgid "Edit Widgets"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:168
#: src/tools/designer/qdesigner_actions.cpp:156
msgid "&New..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:169
#: src/tools/designer/qdesigner_actions.cpp:157
msgid "&Open..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:170
#: src/tools/designer/qdesigner_actions.cpp:158
msgid "&Save"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:171
#: src/tools/designer/qdesigner_actions.cpp:159
msgid "Save &As..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:172
#: src/tools/designer/qdesigner_actions.cpp:160
msgid "Save A&ll"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:173
#: src/tools/designer/qdesigner_actions.cpp:161
msgid "Save As &Template..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:174
#: src/tools/designer/qdesigner_actions.cpp:1023
#: src/tools/designer/qdesigner_actions.cpp:162
#: src/tools/designer/qdesigner_actions.cpp:1011
msgid "&Close"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:175
#: src/tools/designer/qdesigner_actions.cpp:163
msgid "Save &Image..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:176
#: src/tools/designer/qdesigner_actions.cpp:164
msgid "&Print..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:179
#: src/tools/designer/qdesigner_actions.cpp:167
msgid "View &Code..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:180
#: src/tools/designer/qdesigner_actions.cpp:168
msgid "&Minimize"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:182
#: src/tools/designer/qdesigner_actions.cpp:170
msgid "Bring All to Front"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:184
#: src/tools/designer/qdesigner_actions.cpp:172
msgid "Preferences..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:185
#: src/tools/designer/qdesigner_actions.cpp:173
msgid "Additional Fonts..."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:257
#: src/tools/designer/qdesigner_actions.cpp:245
msgid "CTRL+SHIFT+S"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:378
#: src/tools/designer/qdesigner_actions.cpp:366
msgid "CTRL+R"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:396
#: src/tools/designer/qdesigner_actions.cpp:384
msgid "CTRL+M"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:427
#: src/tools/designer/qdesigner_actions.cpp:415
msgid "About Plugins"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:433
#: src/tools/designer/qdesigner_actions.cpp:1004
#: src/tools/designer/qdesigner_actions.cpp:421
#: src/tools/designer/qdesigner_actions.cpp:992
msgid "About Katie Designer"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:439
#: src/tools/designer/qdesigner_actions.cpp:427
msgid "About Katie"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:475
#: src/tools/designer/qdesigner_actions.cpp:463
msgid "Clear &Menu"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:558
#: src/tools/designer/qdesigner_actions.cpp:755
#: src/tools/designer/qdesigner_actions.cpp:546
#: src/tools/designer/qdesigner_actions.cpp:743
msgid "Open Form"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:559
#: src/tools/designer/qdesigner_actions.cpp:596
#: src/tools/designer/qdesigner_actions.cpp:756
#: src/tools/designer/qdesigner_actions.cpp:547
#: src/tools/designer/qdesigner_actions.cpp:584
#: src/tools/designer/qdesigner_actions.cpp:744
msgid "Designer UI files (*.%1);;All Files (*)"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:596
#: src/tools/designer/qdesigner_actions.cpp:844
#: src/tools/designer/qdesigner_actions.cpp:584
#: src/tools/designer/qdesigner_actions.cpp:832
msgid "Save Form As"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:683
#: src/tools/designer/qdesigner_actions.cpp:671
msgid "Designer"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:683
#: src/tools/designer/qdesigner_actions.cpp:671
msgid "Feature not implemented yet!"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:698
#: src/tools/designer/qdesigner_actions.cpp:686
msgid "Code generation failed"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:743
#: src/tools/designer/qdesigner_actions.cpp:731
msgid ""
"%1\n"
"Do you want to update the file location or generate a new form?"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:746
#: src/tools/designer/qdesigner_actions.cpp:734
msgid "&Update"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:747
#: src/tools/designer/qdesigner_actions.cpp:735
msgid "&New Form"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:825
#: src/tools/designer/qdesigner_actions.cpp:813
msgid "Could not open file"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:829
#: src/tools/designer/qdesigner_actions.cpp:817
msgid ""
"The file %1 could not be opened.\n"
"Reason: %2\n"
"Would you like to retry or select a different file?"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:835
#: src/tools/designer/qdesigner_actions.cpp:823
msgid "Select New File"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:865
#: src/tools/designer/qdesigner_actions.cpp:853
msgid "Could not write file"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:868
#: src/tools/designer/qdesigner_actions.cpp:856
msgid ""
"It was not possible to write the entire file %1 to disk.\n"
"Reason:%2\n"
"Would you like to retry?"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1021
#: src/tools/designer/qdesigner_actions.cpp:1009
msgid "&Close Preview"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1062
#: src/tools/designer/qdesigner_actions.cpp:1085
#: src/tools/designer/qdesigner_actions.cpp:1050
#: src/tools/designer/qdesigner_actions.cpp:1073
msgid "The backup file %1 could not be written."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1192
#: src/tools/designer/qdesigner_actions.cpp:1180
msgid "The backup directory %1 could not be created."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1198
#: src/tools/designer/qdesigner_actions.cpp:1186
msgid "The temporary backup directory %1 could not be created."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1228
#: src/tools/designer/qdesigner_actions.cpp:1216
msgid "Preview failed"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1252
#: src/tools/designer/qdesigner_actions.cpp:1240
msgid "Image files (*.%1)"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1261
#: src/tools/designer/qdesigner_actions.cpp:1278
#: src/tools/designer/qdesigner_actions.cpp:1249
#: src/tools/designer/qdesigner_actions.cpp:1266
msgid "Save Image"
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1274
#: src/tools/designer/qdesigner_actions.cpp:1262
msgid "Saved image %1."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1279
#: src/tools/designer/qdesigner_actions.cpp:1267
msgid "The file %1 could not be written."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1292
#: src/tools/designer/qdesigner_actions.cpp:1280
msgid "Please close all forms to enable the loading of additional fonts."
msgstr ""
#: src/tools/designer/qdesigner_actions.cpp:1343
#: src/tools/designer/qdesigner_actions.cpp:1331
msgid "Printed %1."
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:64
#: src/tools/designer/saveformastemplate.cpp:52
msgid "Add path..."
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:87
#: src/tools/designer/saveformastemplate.cpp:75
msgid "Template Exists"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:88
#: src/tools/designer/saveformastemplate.cpp:76
msgid ""
"A template with the name %1 already exists.\n"
"Do you want overwrite the template?"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:91
#: src/tools/designer/saveformastemplate.cpp:79
msgid "Overwrite Template"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:98
#: src/tools/designer/saveformastemplate.cpp:86
msgid "Open Error"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:99
#: src/tools/designer/saveformastemplate.cpp:87
msgid "There was an error opening template %1 for writing. Reason: %2"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:112
#: src/tools/designer/saveformastemplate.cpp:100
msgid "Write Error"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:113
#: src/tools/designer/saveformastemplate.cpp:101
msgid "There was an error writing the template %1 to disk. Reason: %2"
msgstr ""
#: src/tools/designer/saveformastemplate.cpp:140
#: src/tools/designer/saveformastemplate.cpp:128
msgid "Pick a directory to save templates in"
msgstr ""
#: src/tools/designer/mainwindow.cpp:111
#: src/tools/designer/mainwindow.cpp:99
msgid "Main"
msgstr ""
#: src/tools/designer/mainwindow.cpp:117 src/tools/designer/mainwindow.cpp:247
#: src/tools/designer/mainwindow.cpp:105 src/tools/designer/mainwindow.cpp:235
msgid "File"
msgstr ""
#: src/tools/designer/mainwindow.cpp:118 src/tools/designer/mainwindow.cpp:251
#: src/tools/designer/mainwindow.cpp:106 src/tools/designer/mainwindow.cpp:239
msgid "Edit"
msgstr ""
#: src/tools/designer/mainwindow.cpp:119 src/tools/designer/mainwindow.cpp:255
#: src/tools/designer/mainwindow.cpp:107 src/tools/designer/mainwindow.cpp:243
msgid "Tools"
msgstr ""
#: src/tools/designer/mainwindow.cpp:120 src/tools/designer/mainwindow.cpp:259
#: src/tools/designer/mainwindow.cpp:108 src/tools/designer/mainwindow.cpp:247
msgid "Form"
msgstr ""
#: src/tools/designer/mainwindow.cpp:216
#: src/tools/designer/mainwindow.cpp:204
msgid "Configure Toolbars..."
msgstr ""
#: src/tools/designer/mainwindow.cpp:231
#: src/tools/designer/mainwindow.cpp:219
msgid "Window"
msgstr ""
#: src/tools/designer/mainwindow.cpp:232
#: src/tools/designer/mainwindow.cpp:220
msgid "Help"
msgstr ""
#: src/tools/designer/mainwindow.cpp:239
#: src/tools/designer/mainwindow.cpp:227
msgid "Style"
msgstr ""
#: src/tools/designer/mainwindow.cpp:241
#: src/tools/designer/mainwindow.cpp:229
msgid "Dock views"
msgstr ""
#: src/tools/designer/mainwindow.cpp:263
#: src/tools/designer/qdesigner_workbench.cpp:228
#: src/tools/designer/mainwindow.cpp:251
#: src/tools/designer/qdesigner_workbench.cpp:216
msgid "Toolbars"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:179
#: src/tools/designer/qdesigner_toolwindow.cpp:167
msgid "Property Editor"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:233
#: src/tools/designer/qdesigner_toolwindow.cpp:221
msgid "Action Editor"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:275
#: src/tools/designer/qdesigner_toolwindow.cpp:263
msgid "Object Inspector"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:310
#: src/tools/designer/qdesigner_toolwindow.cpp:298
msgid "Resource Browser"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:344
#: src/tools/designer/qdesigner_toolwindow.cpp:332
msgid "Signal/Slot Editor"
msgstr ""
#: src/tools/designer/qdesigner_toolwindow.cpp:385
#: src/tools/designer/qdesigner_workbench.cpp:394
#: src/tools/designer/qdesigner_toolwindow.cpp:373
#: src/tools/designer/qdesigner_workbench.cpp:382
msgid "Widget Box"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:190
#: src/tools/designer/qdesigner_workbench.cpp:178
msgid "&Edit"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:194
#: src/tools/designer/qdesigner_workbench.cpp:182
msgid "F&orm"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:195
#: src/tools/designer/qdesigner_workbench.cpp:183
msgid "Preview in"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:199
#: src/tools/designer/qdesigner_workbench.cpp:187
msgid "&View"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:201
#: src/tools/designer/qdesigner_workbench.cpp:189
msgid "&Settings"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:203
#: src/tools/designer/qdesigner_workbench.cpp:191
msgid "&Window"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:683
#: src/tools/designer/qdesigner_workbench.cpp:671
msgid "Save Forms?"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:684
#: src/tools/designer/qdesigner_workbench.cpp:672
msgid ""
"There are %1 forms with unsaved changes. Do you want to review these changes "
"before quitting?"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:687
#: src/tools/designer/qdesigner_workbench.cpp:675
msgid "If you do not review your documents, all your changes will be lost."
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:688
#: src/tools/designer/qdesigner_workbench.cpp:676
msgid "Discard Changes"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:690
#: src/tools/designer/qdesigner_workbench.cpp:678
msgid "Review Changes"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:785
#: src/tools/designer/qdesigner_workbench.cpp:773
msgid "Backup Information"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:786
#: src/tools/designer/qdesigner_workbench.cpp:774
msgid ""
"The last session of Designer was not terminated correctly. Backup files were "
"left behind. Do you want to load them?"
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:896
#: src/tools/designer/qdesigner_workbench.cpp:884
msgid "The file <b>%1</b> could not be opened."
msgstr ""
#: src/tools/designer/qdesigner_workbench.cpp:942
#: src/tools/designer/qdesigner_workbench.cpp:930
msgid "The file <b>%1</b> is not a valid Designer UI file."
msgstr ""
#: src/tools/designer/qdesigner_appearanceoptions.cpp:77
#: src/tools/designer/qdesigner_appearanceoptions.cpp:65
msgid "Docked Window"
msgstr ""
#: src/tools/designer/qdesigner_appearanceoptions.cpp:78
#: src/tools/designer/qdesigner_appearanceoptions.cpp:66
msgid "Multiple Top-Level Windows"
msgstr ""
#: src/tools/designer/qdesigner_appearanceoptions.cpp:83
#: src/tools/designer/qdesigner_appearanceoptions.cpp:71
msgid "Toolwindow Font"
msgstr ""
#: src/tools/designer/qdesigner_appearanceoptions.cpp:128
#: src/tools/designer/qdesigner_appearanceoptions.cpp:116
msgctxt "QDesignerAppearanceOptionsPage"
msgid "Appearance"
msgstr ""
#: src/tools/designer/qdesigner.cpp:121
#: src/tools/designer/qdesigner.cpp:109
msgctxt "QDesigner"
msgid "%1 - warning"
msgstr ""
#: src/tools/designer/qttoolbardialog/qttoolbardialog.cpp:1234
#: src/tools/designer/qttoolbardialog/qttoolbardialog.cpp:1222
msgid "Custom Toolbar"
msgstr ""
#: src/tools/designer/qttoolbardialog/qttoolbardialog.cpp:1777
#: src/tools/designer/qttoolbardialog/qttoolbardialog.cpp:1765
msgid "< S E P A R A T O R >"
msgstr ""
#: src/tools/designer/fontpanel/fontpanel.cpp:54
#: src/tools/designer/fontpanel/fontpanel.cpp:42
msgid "Font"
msgstr ""
#: src/tools/designer/fontpanel/fontpanel.cpp:59
#: src/tools/designer/fontpanel/fontpanel.cpp:47
msgid "&Family"
msgstr ""
#: src/tools/designer/fontpanel/fontpanel.cpp:63
#: src/tools/designer/fontpanel/fontpanel.cpp:51
msgid "&Style"
msgstr ""
#: src/tools/designer/fontpanel/fontpanel.cpp:67
#: src/tools/designer/fontpanel/fontpanel.cpp:55
msgid "&Point size"
msgstr ""