summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2018-06-26 22:46:49 -0700
committerThiago Macieira <thiago.macieira@intel.com>2018-09-01 15:19:39 +0000
commitd9766ddc3d525cf08acec4c3483e61d86c9899a8 (patch)
tree755b9c9181a24cbc1663714e888e2e3f4cd4db45 /src/tools
parent7391662f80470549b9f9c182da43cf433efabdf7 (diff)
Plugins: store the metadata in CBOR instead of binary JSON
In preparation for Qt 6 deprecating the binary JSON format. Also reduces the size of the metadata a little: for the xcb platform plugin, it went down from 264 bytes to 138; for the jpeg image plugin, it went from 320 to 135. I've had to change the signature so older versions of Qt won't try to parse the CBOR data as Binary JSON. Unfortunately, before QJsonDocument could get a chance to reject it, qJsonFromRawLibraryMetaData() needed to allocate memory and that causes crashes with Qt < 5.11.2. Change-Id: Ieb48f7c0dd0e4e0fb35efffd153bee34e16ce347 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/moc/cbordevice.h94
-rw-r--r--src/tools/moc/generator.cpp158
-rw-r--r--src/tools/moc/moc.pri6
3 files changed, 211 insertions, 47 deletions
diff --git a/src/tools/moc/cbordevice.h b/src/tools/moc/cbordevice.h
new file mode 100644
index 0000000000..25b75b79eb
--- /dev/null
+++ b/src/tools/moc/cbordevice.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CBORDEVICE_H
+#define CBORDEVICE_H
+
+#include <memory>
+#include <stdio.h>
+
+#define CBOR_API inline
+#define CBOR_PRIVATE_API inline
+#define CBOR_NO_PARSER_API 1
+#include <cbor.h>
+
+class CborDevice
+{
+public:
+ CborDevice(FILE *out) : out(out) {}
+
+ void nextItem(const char *comment = nullptr)
+ {
+ i = 0;
+ if (comment)
+ fprintf(out, "\n // %s", comment);
+ }
+
+ static CborError callback(void *self, const void *ptr, size_t len, CborEncoderAppendType t)
+ {
+ auto that = static_cast<CborDevice *>(self);
+ auto data = static_cast<const char *>(ptr);
+ if (t == CborEncoderAppendCborData) {
+ while (len--)
+ that->putByte(*data++);
+ } else {
+ while (len--)
+ that->putChar(*data++);
+ }
+ return CborNoError;
+ }
+
+private:
+ FILE *out;
+ int i = 0;
+
+ void putNewline()
+ {
+ if ((i++ % 8) == 0)
+ fputs("\n ", out);
+ }
+
+ void putByte(uint8_t c)
+ {
+ putNewline();
+ fprintf(out, " 0x%02x, ", c);
+ }
+
+ void putChar(char c)
+ {
+ putNewline();
+ if (c < 0x20 || c >= 0x7f)
+ fprintf(out, " '\\x%x',", uint8_t(c));
+ else if (c == '\'' || c == '\\')
+ fprintf(out, " '\\%c',", c);
+ else
+ fprintf(out, " '%c', ", c);
+ }
+};
+
+#endif // CBORDEVICE_H
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index a3ef1147d6..e5154b779b 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
@@ -28,6 +29,7 @@
****************************************************************************/
#include "generator.h"
+#include "cbordevice.h"
#include "outputrevision.h"
#include "utils.h"
#include <QtCore/qmetatype.h>
@@ -36,9 +38,13 @@
#include <QtCore/qjsonvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qplugin.h>
+#include <QtCore/qstringview.h>
+
+#include <math.h>
#include <stdio.h>
#include <private/qmetaobject_p.h> //for the flags.
+#include <private/qplugin_p.h> //for the flags.
QT_BEGIN_NAMESPACE
@@ -1560,31 +1566,56 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "}\n");
}
-static void writePluginMetaData(FILE *out, const QJsonObject &data)
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
+static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
{
- const QJsonDocument doc(data);
+ auto it = o.constBegin();
+ auto end = o.constEnd();
+ CborEncoder map;
+ cbor_encoder_create_map(parent, &map, o.size());
+
+ for ( ; it != end; ++it) {
+ QByteArray key = it.key().toUtf8();
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonValueToCbor(&map, it.value());
+ }
+ return cbor_encoder_close_container(parent, &map);
+}
- fputs("\nQT_PLUGIN_METADATA_SECTION\n"
- "static const unsigned char qt_pluginMetaData[] = {\n"
- " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',\n ", out);
-#if 0
- fprintf(out, "\"%s\";\n", doc.toJson().constData());
-#else
- const QByteArray binary = doc.toBinaryData();
- const int last = binary.size() - 1;
- for (int i = 0; i < last; ++i) {
- uchar c = (uchar)binary.at(i);
- if (c < 0x20 || c >= 0x7f)
- fprintf(out, " 0x%02x,", c);
- else if (c == '\'' || c == '\\')
- fprintf(out, " '\\%c',", c);
- else
- fprintf(out, " '%c', ", c);
- if (!((i + 1) % 8))
- fputs("\n ", out);
+static CborError jsonArrayToCbor(CborEncoder *parent, const QJsonArray &a)
+{
+ CborEncoder array;
+ cbor_encoder_create_array(parent, &array, a.size());
+ for (const QJsonValue &v : a)
+ jsonValueToCbor(&array, v);
+ return cbor_encoder_close_container(parent, &array);
+}
+
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v)
+{
+ switch (v.type()) {
+ case QJsonValue::Null:
+ case QJsonValue::Undefined:
+ return cbor_encode_null(parent);
+ case QJsonValue::Bool:
+ return cbor_encode_boolean(parent, v.toBool());
+ case QJsonValue::Array:
+ return jsonArrayToCbor(parent, v.toArray());
+ case QJsonValue::Object:
+ return jsonObjectToCbor(parent, v.toObject());
+ case QJsonValue::String: {
+ QByteArray s = v.toString().toUtf8();
+ return cbor_encode_text_string(parent, s.constData(), s.size());
}
- fprintf(out, " 0x%02x\n};\n", (uchar)binary.at(last));
-#endif
+ case QJsonValue::Double: {
+ double d = v.toDouble();
+ if (d == floor(d) && fabs(d) <= (Q_INT64_C(1) << std::numeric_limits<double>::digits))
+ return cbor_encode_int(parent, qint64(d));
+ return cbor_encode_double(parent, d);
+ }
+ }
+ Q_UNREACHABLE();
+ return CborUnknownError;
}
void Generator::generatePluginMetaData()
@@ -1592,32 +1623,59 @@ void Generator::generatePluginMetaData()
if (cdef->pluginData.iid.isEmpty())
return;
- // Write plugin meta data #ifdefed QT_NO_DEBUG with debug=false,
- // true, respectively.
-
- QJsonObject data;
- const QString debugKey = QStringLiteral("debug");
- data.insert(QStringLiteral("IID"), QLatin1String(cdef->pluginData.iid.constData()));
- data.insert(QStringLiteral("className"), QLatin1String(cdef->classname.constData()));
- data.insert(QStringLiteral("version"), (int)QT_VERSION);
- data.insert(debugKey, QJsonValue(false));
- data.insert(QStringLiteral("MetaData"), cdef->pluginData.metaData.object());
+ fputs("\nQT_PLUGIN_METADATA_SECTION\n"
+ "static const unsigned char qt_pluginMetaData[] = {\n"
+ " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',", out);
+
+ CborDevice dev(out);
+ CborEncoder enc;
+ cbor_encoder_init_writer(&enc, CborDevice::callback, &dev);
+
+ CborEncoder map;
+ cbor_encoder_create_map(&enc, &map, CborIndefiniteLength);
+
+ dev.nextItem("\"version\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::QtVersion));
+ cbor_encode_int(&map, QT_VERSION);
+
+ fputs("\n#ifdef QT_NO_DEBUG", out);
+ dev.nextItem("\"debug\" = false");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::Debug));
+ cbor_encode_boolean(&map, false);
+ fputs("\n#else", out);
+ dev.nextItem("\"debug\" = true");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::Debug));
+ cbor_encode_boolean(&map, true);
+ fputs("\n#endif", out);
+
+ dev.nextItem("\"IID\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID));
+ cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size());
+
+ dev.nextItem("\"className\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName));
+ cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size());
+
+ QJsonObject o = cdef->pluginData.metaData.object();
+ if (!o.isEmpty()) {
+ dev.nextItem("\"MetaData\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData));
+ jsonObjectToCbor(&map, o);
+ }
// Add -M args from the command line:
- for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it)
- data.insert(it.key(), it.value());
-
- fputs("\nQT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;\n\n"
- "#ifdef QT_NO_DEBUG\n", out);
- writePluginMetaData(out, data);
-
- fputs("\n#else // QT_NO_DEBUG\n", out);
-
- data.remove(debugKey);
- data.insert(debugKey, QJsonValue(true));
- writePluginMetaData(out, data);
+ for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) {
+ const QJsonArray &a = it.value();
+ QByteArray key = it.key().toUtf8();
+ dev.nextItem(QByteArray("command-line \"" + key + "\"").constData());
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonArrayToCbor(&map, a);
+ }
- fputs("#endif // QT_NO_DEBUG\n\n", out);
+ // Close the CBOR map manually
+ dev.nextItem();
+ cbor_encoder_close_container(&enc, &map);
+ fputs("\n};\n", out);
// 'Use' all namespaces.
int pos = cdef->qualified.indexOf("::");
@@ -1627,4 +1685,14 @@ void Generator::generatePluginMetaData()
cdef->qualified.constData(), cdef->classname.constData());
}
+QT_WARNING_DISABLE_GCC("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
+QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+
+#define CBOR_ENCODER_WRITER_CONTROL 1
+#define CBOR_ENCODER_WRITE_FUNCTION CborDevice::callback
+
QT_END_NAMESPACE
+
+#include "cborencoder.c"
diff --git a/src/tools/moc/moc.pri b/src/tools/moc/moc.pri
index b689a35478..90839a445b 100644
--- a/src/tools/moc/moc.pri
+++ b/src/tools/moc/moc.pri
@@ -1,5 +1,6 @@
-INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD \
+ $$PWD/../../3rdparty/tinycbor/src
HEADERS = $$PWD/moc.h \
$$PWD/preprocessor.h \
@@ -8,7 +9,8 @@ HEADERS = $$PWD/moc.h \
$$PWD/token.h \
$$PWD/utils.h \
$$PWD/generator.h \
- $$PWD/outputrevision.h
+ $$PWD/outputrevision.h \
+ $$PWD/cbordevice.h
SOURCES = $$PWD/moc.cpp \
$$PWD/preprocessor.cpp \
$$PWD/generator.cpp \