diff options
| -rw-r--r-- | LICENSES/LicenseRef-SHA1-Public-Domain.txt | 3 | ||||
| -rw-r--r-- | dependencies.yaml | 4 | ||||
| -rw-r--r-- | src/3rdparty/sha1/REUSE.toml | 8 | ||||
| -rw-r--r-- | src/3rdparty/sha1/qt_attribution.json | 15 | ||||
| -rw-r--r-- | src/3rdparty/sha1/sha1.cpp | 225 | ||||
| -rw-r--r-- | src/scxml/qscxmlinvokableservice.cpp | 6 | ||||
| -rw-r--r-- | src/scxml/qscxmlstatemachine.cpp | 8 | ||||
| -rw-r--r-- | tools/qscxmlc/generator.cpp | 50 | ||||
| -rw-r--r-- | tools/qscxmlc/generator.h | 6 | ||||
| -rw-r--r-- | tools/qscxmlc/moc.cpp | 93 | ||||
| -rw-r--r-- | tools/qscxmlc/moc.h | 5 | ||||
| -rw-r--r-- | tools/qscxmlc/moc_patches/generator.cpp.patch | 69 | ||||
| -rw-r--r-- | tools/qscxmlc/moc_patches/generator.h.patch | 21 | ||||
| -rw-r--r-- | tools/qscxmlc/moc_patches/moc.cpp.patch | 14 | ||||
| -rw-r--r-- | tools/qscxmlc/moc_patches/moc.h.patch | 10 | ||||
| -rw-r--r-- | tools/qscxmlc/moc_patches/outputrevision.h.patch | 2 | ||||
| -rw-r--r-- | tools/qscxmlc/scxmlcppdumper.cpp | 30 |
17 files changed, 468 insertions, 101 deletions
diff --git a/LICENSES/LicenseRef-SHA1-Public-Domain.txt b/LICENSES/LicenseRef-SHA1-Public-Domain.txt new file mode 100644 index 0000000..2ebbf9a --- /dev/null +++ b/LICENSES/LicenseRef-SHA1-Public-Domain.txt @@ -0,0 +1,3 @@ +100% free public domain implementation of the SHA-1 algorithm +by Dominik Reichl <dominik.reichl@t-online.de> +Web: http://www.dominik-reichl.de/ diff --git a/dependencies.yaml b/dependencies.yaml index ba73fbb..45a9542 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -1,7 +1,7 @@ dependencies: ../qtbase: - ref: bd04c5d7a4b907b8c4a2d2dda4ba3f24f687fb7f + ref: 4fd88011fa7975ce64d5648698a234f85bac359c required: true ../qtdeclarative: - ref: 59da4b17158303fc671869547bcb91b675bf4702 + ref: fc162d455eedbb68f22f302dee45f7faf4146dd0 required: false diff --git a/src/3rdparty/sha1/REUSE.toml b/src/3rdparty/sha1/REUSE.toml new file mode 100644 index 0000000..93b18a4 --- /dev/null +++ b/src/3rdparty/sha1/REUSE.toml @@ -0,0 +1,8 @@ +version = 1 + +[[annotations]] +path = ["**"] +precedence = "closest" +SPDX-FileCopyrightText = ["Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>", + "Copyright (C) 2016 The Qt Company Ltd"] +SPDX-License-Identifier = "LicenseRef-SHA1-Public-Domain" diff --git a/src/3rdparty/sha1/qt_attribution.json b/src/3rdparty/sha1/qt_attribution.json new file mode 100644 index 0000000..bbcced6 --- /dev/null +++ b/src/3rdparty/sha1/qt_attribution.json @@ -0,0 +1,15 @@ +{ + "Id": "sha1", + "Name": "Secure Hash Algorithm SHA-1", + "QDocModule": "qtcore", + "QtUsage": "Used in Qt SCXML (Qt moc copy).", + + "Description": "Implements the Secure Hash Algorithms SHA 1", + "PURL": "pkg:generic/csha1?download_url=https://www.dominik-reichl.de/projects/csha1/", + "Homepage": "http://www.dominik-reichl.de/projects/csha1/", + "License": "Public Domain", + "LicenseId": "LicenseRef-SHA1-Public-Domain", + "Copyright": ["Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>", + "Copyright (C) 2016 The Qt Company Ltd"], + "Comment": "no relevant CPE found" +} diff --git a/src/3rdparty/sha1/sha1.cpp b/src/3rdparty/sha1/sha1.cpp new file mode 100644 index 0000000..6dd25e3 --- /dev/null +++ b/src/3rdparty/sha1/sha1.cpp @@ -0,0 +1,225 @@ +// Based on the public domain implementation of the SHA-1 algorithm by Dominik Reichl +// +// Copyright (C) Dominik Reichl <dominik.reichl@t-online.de> +// Copyright (C) 2016 The Qt Company Ltd. +// +// SPDX-License-Identifier: LicenseRef-SHA1-Public-Domain + +#include <QtCore/qendian.h> + +#ifdef Q_CC_MSVC +# include <stdlib.h> +#endif + +QT_BEGIN_NAMESPACE + +// Test Vectors (from FIPS PUB 180-1) +// +// SHA1("abc") = +// A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +// +// SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = +// 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +// +// SHA1(A million repetitions of "a") = +// 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +// + + +// #define or #undef this, if you want the to wipe all +// temporary variables after processing +#define SHA1_WIPE_VARIABLES + + +struct Sha1State +{ + quint32 h0; + quint32 h1; + quint32 h2; + quint32 h3; + quint32 h4; + + quint64 messageSize; + unsigned char buffer[64]; +}; + + +typedef union +{ + quint8 bytes[64]; + quint32 words[16]; +} Sha1Chunk; + +static inline quint32 rol32(quint32 value, unsigned int shift) +{ +#ifdef Q_CC_MSVC + return _rotl(value, shift); +#else + return ((value << shift) | (value >> (32 - shift))); +#endif +} + +static inline quint32 sha1Word(Sha1Chunk *chunk, const uint position) +{ + return (chunk->words[position & 0xf] = rol32( chunk->words[(position+13) & 0xf] + ^ chunk->words[(position+ 8) & 0xf] + ^ chunk->words[(position+ 2) & 0xf] + ^ chunk->words[(position) & 0xf], 1)); +} + +static inline void sha1Round0(Sha1Chunk *chunk, const uint position, + quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) +{ + z += ((( w & (x ^ y)) ^ y) + chunk->words[position] + 0x5A827999 + rol32(v, 5)); + w = rol32(w, 30); +} + +static inline void sha1Round1(Sha1Chunk *chunk, const uint position, + quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) +{ + z += ((( w & (x ^ y)) ^ y) + sha1Word(chunk,position) + 0x5A827999 + rol32(v, 5)); + w = rol32(w, 30); +} + +static inline void sha1Round2(Sha1Chunk *chunk, const uint position, + quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) +{ + z += (( w ^ x ^ y) + sha1Word(chunk, position) + 0x6ED9EBA1 + rol32(v, 5)); + w = rol32(w, 30); +} + +static inline void sha1Round3(Sha1Chunk *chunk, const uint position, + quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) +{ + z += (((( w | x) & y) | (w & x)) + sha1Word(chunk, position) + 0x8F1BBCDC + rol32(v, 5)); + w = rol32(w, 30); +} + +static inline void sha1Round4(Sha1Chunk *chunk, const uint position, + quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) +{ + z += ((w ^ x ^ y) + sha1Word(chunk, position) + 0xCA62C1D6 + rol32(v, 5)); + w = rol32(w, 30); +} + +static inline void sha1ProcessChunk(Sha1State *state, const unsigned char *buffer) +{ + // Copy state[] to working vars + quint32 a = state->h0; + quint32 b = state->h1; + quint32 c = state->h2; + quint32 d = state->h3; + quint32 e = state->h4; + + quint8 chunkBuffer[64]; + memcpy(chunkBuffer, buffer, 64); + + Sha1Chunk *chunk = reinterpret_cast<Sha1Chunk*>(&chunkBuffer); + + for (int i = 0; i < 16; ++i) + chunk->words[i] = qFromBigEndian(chunk->words[i]); + + sha1Round0(chunk, 0, a,b,c,d,e); sha1Round0(chunk, 1, e,a,b,c,d); sha1Round0(chunk, 2, d,e,a,b,c); sha1Round0(chunk, 3, c,d,e,a,b); + sha1Round0(chunk, 4, b,c,d,e,a); sha1Round0(chunk, 5, a,b,c,d,e); sha1Round0(chunk, 6, e,a,b,c,d); sha1Round0(chunk, 7, d,e,a,b,c); + sha1Round0(chunk, 8, c,d,e,a,b); sha1Round0(chunk, 9, b,c,d,e,a); sha1Round0(chunk, 10, a,b,c,d,e); sha1Round0(chunk, 11, e,a,b,c,d); + sha1Round0(chunk, 12, d,e,a,b,c); sha1Round0(chunk, 13, c,d,e,a,b); sha1Round0(chunk, 14, b,c,d,e,a); sha1Round0(chunk, 15, a,b,c,d,e); + sha1Round1(chunk, 16, e,a,b,c,d); sha1Round1(chunk, 17, d,e,a,b,c); sha1Round1(chunk, 18, c,d,e,a,b); sha1Round1(chunk, 19, b,c,d,e,a); + sha1Round2(chunk, 20, a,b,c,d,e); sha1Round2(chunk, 21, e,a,b,c,d); sha1Round2(chunk, 22, d,e,a,b,c); sha1Round2(chunk, 23, c,d,e,a,b); + sha1Round2(chunk, 24, b,c,d,e,a); sha1Round2(chunk, 25, a,b,c,d,e); sha1Round2(chunk, 26, e,a,b,c,d); sha1Round2(chunk, 27, d,e,a,b,c); + sha1Round2(chunk, 28, c,d,e,a,b); sha1Round2(chunk, 29, b,c,d,e,a); sha1Round2(chunk, 30, a,b,c,d,e); sha1Round2(chunk, 31, e,a,b,c,d); + sha1Round2(chunk, 32, d,e,a,b,c); sha1Round2(chunk, 33, c,d,e,a,b); sha1Round2(chunk, 34, b,c,d,e,a); sha1Round2(chunk, 35, a,b,c,d,e); + sha1Round2(chunk, 36, e,a,b,c,d); sha1Round2(chunk, 37, d,e,a,b,c); sha1Round2(chunk, 38, c,d,e,a,b); sha1Round2(chunk, 39, b,c,d,e,a); + sha1Round3(chunk, 40, a,b,c,d,e); sha1Round3(chunk, 41, e,a,b,c,d); sha1Round3(chunk, 42, d,e,a,b,c); sha1Round3(chunk, 43, c,d,e,a,b); + sha1Round3(chunk, 44, b,c,d,e,a); sha1Round3(chunk, 45, a,b,c,d,e); sha1Round3(chunk, 46, e,a,b,c,d); sha1Round3(chunk, 47, d,e,a,b,c); + sha1Round3(chunk, 48, c,d,e,a,b); sha1Round3(chunk, 49, b,c,d,e,a); sha1Round3(chunk, 50, a,b,c,d,e); sha1Round3(chunk, 51, e,a,b,c,d); + sha1Round3(chunk, 52, d,e,a,b,c); sha1Round3(chunk, 53, c,d,e,a,b); sha1Round3(chunk, 54, b,c,d,e,a); sha1Round3(chunk, 55, a,b,c,d,e); + sha1Round3(chunk, 56, e,a,b,c,d); sha1Round3(chunk, 57, d,e,a,b,c); sha1Round3(chunk, 58, c,d,e,a,b); sha1Round3(chunk, 59, b,c,d,e,a); + sha1Round4(chunk, 60, a,b,c,d,e); sha1Round4(chunk, 61, e,a,b,c,d); sha1Round4(chunk, 62, d,e,a,b,c); sha1Round4(chunk, 63, c,d,e,a,b); + sha1Round4(chunk, 64, b,c,d,e,a); sha1Round4(chunk, 65, a,b,c,d,e); sha1Round4(chunk, 66, e,a,b,c,d); sha1Round4(chunk, 67, d,e,a,b,c); + sha1Round4(chunk, 68, c,d,e,a,b); sha1Round4(chunk, 69, b,c,d,e,a); sha1Round4(chunk, 70, a,b,c,d,e); sha1Round4(chunk, 71, e,a,b,c,d); + sha1Round4(chunk, 72, d,e,a,b,c); sha1Round4(chunk, 73, c,d,e,a,b); sha1Round4(chunk, 74, b,c,d,e,a); sha1Round4(chunk, 75, a,b,c,d,e); + sha1Round4(chunk, 76, e,a,b,c,d); sha1Round4(chunk, 77, d,e,a,b,c); sha1Round4(chunk, 78, c,d,e,a,b); sha1Round4(chunk, 79, b,c,d,e,a); + + // Add the working vars back into state + state->h0 += a; + state->h1 += b; + state->h2 += c; + state->h3 += d; + state->h4 += e; + + // Wipe variables +#ifdef SHA1_WIPE_VARIABLES + a = b = c = d = e = 0; + memset(chunkBuffer, 0, 64); +#endif +} + +static inline void sha1InitState(Sha1State *state) +{ + state->h0 = 0x67452301; + state->h1 = 0xEFCDAB89; + state->h2 = 0x98BADCFE; + state->h3 = 0x10325476; + state->h4 = 0xC3D2E1F0; + + state->messageSize = 0; +} + +static inline void sha1Update(Sha1State *state, const unsigned char *data, qint64 len) +{ + quint32 rest = static_cast<quint32>(state->messageSize & Q_UINT64_C(63)); + + quint64 availableData = static_cast<quint64>(len) + static_cast<quint64>(rest); + state->messageSize += len; + + if (availableData < Q_UINT64_C(64)) { + memcpy(&state->buffer[rest], &data[0], len); + + } else { + qint64 i = static_cast<qint64>(64 - rest); + memcpy(&state->buffer[rest], &data[0], static_cast<qint32>(i)); + sha1ProcessChunk(state, state->buffer); + + qint64 lastI = len - ((len + rest) & Q_INT64_C(63)); + for( ; i < lastI; i += 64) + sha1ProcessChunk(state, &data[i]); + + memcpy(&state->buffer[0], &data[i], len - i); + } +} + +static inline void sha1FinalizeState(Sha1State *state) +{ + quint64 messageSize = state->messageSize; + unsigned char sizeInBits[8]; + qToBigEndian(messageSize << 3, sizeInBits); + + sha1Update(state, (const unsigned char *)"\200", 1); + + unsigned char zero[64]; + memset(zero, 0, 64); + if (static_cast<int>(messageSize & 63) > 56 - 1) { + sha1Update(state, zero, 64 - 1 - static_cast<int>(messageSize & 63)); + sha1Update(state, zero, 64 - 8); + } else { + sha1Update(state, zero, 64 - 1 - 8 - static_cast<int>(messageSize & 63)); + } + + sha1Update(state, sizeInBits, 8); +#ifdef SHA1_WIPE_VARIABLES + memset(state->buffer, 0, 64); + memset(zero, 0, 64); + state->messageSize = 0; +#endif +} + +static inline void sha1ToHash(Sha1State *state, unsigned char* buffer) +{ + qToBigEndian(state->h0, buffer); + qToBigEndian(state->h1, buffer + 4); + qToBigEndian(state->h2, buffer + 8); + qToBigEndian(state->h3, buffer + 12); + qToBigEndian(state->h4, buffer + 16); +} + +QT_END_NAMESPACE diff --git a/src/scxml/qscxmlinvokableservice.cpp b/src/scxml/qscxmlinvokableservice.cpp index 0665406..8845d51 100644 --- a/src/scxml/qscxmlinvokableservice.cpp +++ b/src/scxml/qscxmlinvokableservice.cpp @@ -287,6 +287,12 @@ QScxmlScxmlService::~QScxmlScxmlService() } /*! + \class QScxmlScxmlService + \inmodule QtScxml + \internal +*/ + +/*! Creates a SCXML service wrapping \a stateMachine, invoked from \a parentStateMachine, as a child of \a factory. */ diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp index cb35778..ac8247d 100644 --- a/src/scxml/qscxmlstatemachine.cpp +++ b/src/scxml/qscxmlstatemachine.cpp @@ -487,11 +487,17 @@ void QScxmlStateMachinePrivate::submitDelayedEvent(QScxmlEvent *event) } /*! + \class QScxmlStateMachinePrivate + \inmodule QtScxml + \internal +*/ + +/*! * Submits an error event to the external event queue of this state machine. * * The type of the error is specified by \a type. The value of type has to begin * with the string \e error. For example \c {error.execution}. The message, - * \a message, decribes the error and is passed to the event as the + * \a message, describes the error and is passed to the event as the * \c errorMessage property. The \a sendId of the message causing the error is specified, if it has * one. */ diff --git a/tools/qscxmlc/generator.cpp b/tools/qscxmlc/generator.cpp index 50f1822..006dd81 100644 --- a/tools/qscxmlc/generator.cpp +++ b/tools/qscxmlc/generator.cpp @@ -104,20 +104,21 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) } // -- QtScxml -Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, +Generator::Generator(const ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, - QIODevice &outfile, - bool requireCompleteTypes) - : out(outfile), - cdef(classDef), - metaTypes(metaTypes), - knownQObjectClasses(knownQObjectClasses), - knownGadgets(knownGadgets), - requireCompleteTypes(requireCompleteTypes) + const QHash<QByteArray, QByteArray> &hashes, + QIODevice &outfile, bool requireCompleteTypes) + : out(outfile), + cdef(classDef), + metaTypes(metaTypes), + knownQObjectClasses(knownQObjectClasses), + knownGadgets(knownGadgets), + hashes(hashes), + requireCompleteTypes(requireCompleteTypes) { - if (cdef->superclassList.size()) - purestSuperClass = cdef->superclassList.constFirst().classname; + if (cdef->superclassList.size()) + purestSuperClass = cdef->superclassList.constFirst().classname; } // -- QtScxml @@ -255,28 +256,11 @@ void Generator::generateCode() bool isQObject = (cdef->classname == "QObject"); bool isConstructible = !cdef->constructorList.isEmpty(); - // filter out undeclared enumerators and sets - { - QList<EnumDef> enumList; - for (EnumDef def : std::as_const(cdef->enumList)) { - if (cdef->enumDeclarations.contains(def.name)) { - enumList += def; - } - def.enumName = def.name; - QByteArray alias = cdef->flagAliases.value(def.name); - if (cdef->enumDeclarations.contains(alias)) { - def.name = alias; - def.flags |= cdef->enumDeclarations[alias]; - enumList += def; - } - } - cdef->enumList = enumList; - } - // // Register all strings used in data section // strreg(cdef->qualified); + strreg(hashes[cdef->qualified]); registerClassInfoStrings(); registerFunctionStrings(cdef->signalList); registerFunctionStrings(cdef->slotList); @@ -337,6 +321,8 @@ void Generator::generateCode() addEnums(); fprintf(out, " };\n"); + fprintf(out, " uint qt_metaObjectHashIndex = %d;\n", stridx(hashes[cdef->qualified])); + const char *uintDataParams = ""; if (isConstructible || !cdef->classInfoList.isEmpty()) { if (isConstructible) { @@ -369,7 +355,7 @@ void Generator::generateCode() if (!requireCompleteness) tagType = "qt_meta_tag_" + qualifiedClassNameIdentifier + "_t"; fprintf(out, " return QtMocHelpers::metaObjectData<%s, %s>(%s, qt_stringData,\n" - " qt_methods, qt_properties, qt_enums%s);\n" + " qt_methods, qt_properties, qt_enums, qt_metaObjectHashIndex%s);\n" "}\n", ownType, tagType.constData(), metaObjectFlags, uintDataParams); } @@ -803,6 +789,10 @@ void Generator::addProperties() addFlag("Constant"); if (p.final) addFlag("Final"); + if (p.virtual_) + addFlag("Virtual"); + if (p.override) + addFlag("Override"); if (p.user != "false") addFlag("User"); if (p.required) diff --git a/tools/qscxmlc/generator.h b/tools/qscxmlc/generator.h index 63cceef..8b8c58e 100644 --- a/tools/qscxmlc/generator.h +++ b/tools/qscxmlc/generator.h @@ -17,13 +17,14 @@ QT_BEGIN_NAMESPACE class Generator { QIODevice &out; // -- QtScxml - ClassDef *cdef; + const ClassDef *cdef; QList<uint> meta_data; public: - Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, + Generator(const ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, + const QHash<QByteArray, QByteArray> &hashes, QIODevice &outfile, // -- QtScxml bool requireCompleteTypes = false); void generateCode(); @@ -67,6 +68,7 @@ private: QList<QByteArray> metaTypes; QHash<QByteArray, QByteArray> knownQObjectClasses; QHash<QByteArray, QByteArray> knownGadgets; + QHash<QByteArray, QByteArray> hashes; bool requireCompleteTypes; }; diff --git a/tools/qscxmlc/moc.cpp b/tools/qscxmlc/moc.cpp index a57c1b2..ce102c7 100644 --- a/tools/qscxmlc/moc.cpp +++ b/tools/qscxmlc/moc.cpp @@ -68,6 +68,8 @@ bool Moc::parseClassHead(ClassDef *def) const QByteArrayView lex = lexemView(); if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL") name = lexem(); + else + def->isFinal = true; } def->qualified += name; @@ -85,6 +87,8 @@ bool Moc::parseClassHead(ClassDef *def) const QByteArrayView lex = lexemView(); if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL") return false; + else + def->isFinal = true; } if (test(COLON)) { @@ -553,6 +557,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) bool scopedFunctionName = false; if (test(LPAREN)) { def->name = def->type.name; + def->lineNumber = symbol().lineNum; scopedFunctionName = def->type.isScoped; if (def->name == cdef->classname) { def->isDestructor = tilde; @@ -586,6 +591,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) if (!test(LPAREN)) return false; def->name = tempType.name; + def->lineNumber = symbol().lineNum; scopedFunctionName = tempType.isScoped; } @@ -1185,6 +1191,24 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes) return required; } +QByteArray classDefJsonObjectHash(const QJsonObject &object) +{ + const QByteArray json = QJsonDocument(object).toJson(QJsonValue::JsonFormat::Compact); + QByteArray hash(20, 0); // SHA1 produces 160 bits of data + + { + Sha1State state; + sha1InitState(&state); + sha1Update(&state, reinterpret_cast<const uchar *>(json.constData()), json.size()); + sha1FinalizeState(&state); + sha1ToHash(&state, reinterpret_cast<uchar *>(hash.data())); + } + + static const char revisionPrefix[] = "0$"; + const QByteArray hashB64 = hash.toBase64(QByteArray::OmitTrailingEquals); + return revisionPrefix + hashB64; +} + void Moc::generate(FILE *out, FILE *jsonOutput) { QByteArrayView fn = strippedFileName(); @@ -1241,14 +1265,40 @@ void Moc::generate(FILE *out, FILE *jsonOutput) "#endif\n\n"); #endif + // filter out undeclared enumerators and sets + for (ClassDef &cdef : classList) { + QList<EnumDef> enumList; + for (EnumDef def : std::as_const(cdef.enumList)) { + if (cdef.enumDeclarations.contains(def.name)) { + enumList += def; + } + def.enumName = def.name; + QByteArray alias = cdef.flagAliases.value(def.name); + if (cdef.enumDeclarations.contains(alias)) { + def.name = alias; + def.flags |= cdef.enumDeclarations[alias]; + enumList += def; + } + } + cdef.enumList = enumList; + } + fprintf(out, "QT_WARNING_PUSH\n"); fprintf(out, "QT_WARNING_DISABLE_DEPRECATED\n"); fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n"); + QHash<QByteArray, QJsonObject> classDefJsonObjects; + QHash<QByteArray, QByteArray> metaObjectHashes; + for (const ClassDef &def : std::as_const(classList)) { + const QJsonObject jsonObject = def.toJson(); + classDefJsonObjects.insert(def.qualified, jsonObject); + metaObjectHashes.insert(def.qualified, classDefJsonObjectHash(jsonObject)); + } + fputs("", out); - for (ClassDef &def : classList) { - Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, out, - requireCompleteTypes); + for (const ClassDef &def : std::as_const(classList)) { + Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, + metaObjectHashes, out, requireCompleteTypes); generator.generateCode(); // generator.generateCode() should have already registered all strings @@ -1267,13 +1317,20 @@ void Moc::generate(FILE *out, FILE *jsonOutput) mocData["inputFile"_L1] = QLatin1StringView(fn.constData()); QJsonArray classesJsonFormatted; + QJsonObject hashesJsonObject; - for (const ClassDef &cdef: std::as_const(classList)) - classesJsonFormatted.append(cdef.toJson()); + for (const ClassDef &cdef : std::as_const(classList)) { + classesJsonFormatted.append(classDefJsonObjects[cdef.qualified]); + hashesJsonObject.insert(QString::fromLatin1(cdef.qualified), + QString::fromLatin1(metaObjectHashes[cdef.qualified])); + } if (!classesJsonFormatted.isEmpty()) mocData["classes"_L1] = classesJsonFormatted; + if (!hashesJsonObject.isEmpty()) + mocData["hashes"_L1] = hashesJsonObject; + QJsonDocument jsonDoc(mocData); fputs(jsonDoc.toJson().constData(), jsonOutput); } @@ -1428,6 +1485,9 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) next(IDENTIFIER); propDef.name = lexem(); continue; + } else if (l[0] == 'O' && l == "OVERRIDE") { + propDef.override = true; + continue; } else if (l[0] == 'R' && l == "REQUIRED") { propDef.required = true; continue; @@ -1435,6 +1495,9 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) prev(); propDef.revision = parseRevision().toEncodedVersion<int>(); continue; + } else if (l[0] == 'V' && l == "VIRTUAL") { + propDef.virtual_ = true; + continue; } QByteArray v, v2; @@ -1539,6 +1602,24 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) propDef.write = ""; warning(msg.constData()); } + if (propDef.override && propDef.virtual_) { + const QByteArray msg = "Issue with property declaration " + propDef.name + + ": VIRTUAL is redundant when overriding a property. The OVERRIDE " + "must only be used when actually overriding an existing property; using it on a " + "new property is an error."; + error(msg.constData()); + } + if (propDef.override && propDef.final) { + const QByteArray msg = "Issue with property declaration " + propDef.name + + ": OVERRIDE is redundant when property is marked FINAL"; + error(msg.constData()); + } + if (propDef.virtual_ && propDef.final) { + const QByteArray msg = "Issue with property declaration " + propDef.name + + ": The VIRTUAL cannot be combined with FINAL, as these attributes are mutually " + "exclusive"; + error(msg.constData()); + } } void Moc::parseProperty(ClassDef *def, Moc::PropertyMode mode) @@ -2054,6 +2135,8 @@ QJsonObject ClassDef::toJson() const cls["className"_L1] = QString::fromUtf8(classname.constData()); cls["qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData()); cls["lineNumber"_L1] = lineNumber; + if (isFinal) + cls["final"_L1] = true; QJsonArray classInfos; for (const auto &info: std::as_const(classInfoList)) { diff --git a/tools/qscxmlc/moc.h b/tools/qscxmlc/moc.h index fbcf150..f8008b3 100644 --- a/tools/qscxmlc/moc.h +++ b/tools/qscxmlc/moc.h @@ -136,6 +136,8 @@ struct PropertyDef TypeTags typeTag; bool constant = false; bool final = false; + bool virtual_ = false; + bool override = false; bool required = false; int relativeIndex = -1; // property index in current metaobject int lineNumber = 0; @@ -217,6 +219,7 @@ struct ClassDef : BaseDef { bool hasQGadget = false; bool hasQNamespace = false; bool requireCompleteMethodTypes = false; + bool isFinal = false; QJsonObject toJson() const; }; @@ -305,7 +308,7 @@ public: QByteArray lexemUntil(Token); bool until(Token); - // test for Q_INVOCABLE, Q_SCRIPTABLE, etc. and set the flags + // test for Q_INVOKABLE, Q_SCRIPTABLE, etc. and set the flags // in FunctionDef accordingly bool testFunctionAttribute(FunctionDef *def); bool testFunctionAttribute(Token tok, FunctionDef *def); diff --git a/tools/qscxmlc/moc_patches/generator.cpp.patch b/tools/qscxmlc/moc_patches/generator.cpp.patch index 21b8fd0..3ecf6e8 100644 --- a/tools/qscxmlc/moc_patches/generator.cpp.patch +++ b/tools/qscxmlc/moc_patches/generator.cpp.patch @@ -1,5 +1,5 @@ ---- .upstream/generator.cpp 2025-06-23 08:04:34.541288406 +0200 -+++ generator.cpp 2025-08-05 10:52:45.130291770 +0200 +--- .upstream/generator.cpp 2025-12-08 08:44:49.600222497 +0100 ++++ generator.cpp 2025-12-08 11:36:34.441647201 +0100 @@ -4,7 +4,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 @@ -40,45 +40,40 @@ static int nameToBuiltinType(const QByteArray &name) { if (name.isEmpty()) -@@ -78,21 +103,23 @@ +@@ -78,23 +103,24 @@ return nullptr; } -- Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes, +- Generator::Generator(Moc *moc, const ClassDef *classDef, const QList<QByteArray> &metaTypes, - const QHash<QByteArray, QByteArray> &knownQObjectClasses, -- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile, -- bool requireCompleteTypes) +- const QHash<QByteArray, QByteArray> &knownGadgets, +- const QHash<QByteArray, QByteArray> &hashes, +- FILE *outfile, bool requireCompleteTypes) - : parser(moc), - out(outfile), -- cdef(classDef), -- metaTypes(metaTypes), -- knownQObjectClasses(knownQObjectClasses), -- knownGadgets(knownGadgets), -- requireCompleteTypes(requireCompleteTypes) -- { -- if (cdef->superclassList.size()) -- purestSuperClass = cdef->superclassList.constFirst().classname; +// -- QtScxml -+Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, ++Generator::Generator(const ClassDef *classDef, const QList<QByteArray> &metaTypes, + const QHash<QByteArray, QByteArray> &knownQObjectClasses, + const QHash<QByteArray, QByteArray> &knownGadgets, -+ QIODevice &outfile, -+ bool requireCompleteTypes) -+ : out(outfile), -+ cdef(classDef), -+ metaTypes(metaTypes), -+ knownQObjectClasses(knownQObjectClasses), -+ knownGadgets(knownGadgets), -+ requireCompleteTypes(requireCompleteTypes) ++ const QHash<QByteArray, QByteArray> &hashes, ++ QIODevice &outfile, bool requireCompleteTypes) ++ : out(outfile), + cdef(classDef), + metaTypes(metaTypes), + knownQObjectClasses(knownQObjectClasses), + knownGadgets(knownGadgets), + hashes(hashes), + requireCompleteTypes(requireCompleteTypes) +- { +{ -+ if (cdef->superclassList.size()) -+ purestSuperClass = cdef->superclassList.constFirst().classname; + if (cdef->superclassList.size()) + purestSuperClass = cdef->superclassList.constFirst().classname; } +// -- QtScxml static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i) { -@@ -119,7 +146,7 @@ +@@ -121,7 +147,7 @@ // Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The // opening and closing quotes are NOT included (it's up to the caller). @@ -87,7 +82,7 @@ { static constexpr int ColumnWidth = 68; const qsizetype len = s.size(); -@@ -263,8 +290,10 @@ +@@ -248,8 +274,10 @@ bool hasStaticMetaCall = (cdef->hasQObject || !cdef->methodList.isEmpty() || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); @@ -98,7 +93,7 @@ const QByteArray qualifiedClassNameIdentifier = generateQualifiedClassNameIdentifier(cdef->qualified); -@@ -525,8 +554,10 @@ +@@ -512,8 +540,10 @@ } fprintf(out, "}\n"); @@ -109,7 +104,7 @@ // // Generate internal qt_metacall() function -@@ -542,7 +573,9 @@ +@@ -529,7 +559,9 @@ // // Generate plugin meta data // @@ -119,7 +114,7 @@ // // Generate function to make sure the non-class signals exist in the parent classes -@@ -1011,6 +1044,13 @@ +@@ -1002,6 +1034,13 @@ const FunctionDef &f = methodList.at(methodindex); Q_ASSERT(!f.normalizedType.isEmpty()); fprintf(out, " case %d: ", methodindex); @@ -133,7 +128,7 @@ if (f.normalizedType != "void") fprintf(out, "{ %s _r = ", disambiguatedTypeName(noRef(f.normalizedType)).constData()); fprintf(out, "_t->"); -@@ -1087,6 +1127,10 @@ +@@ -1078,6 +1117,10 @@ const FunctionDef &f = cdef->signalList.at(methodindex); if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic) continue; @@ -144,7 +139,7 @@ fprintf(out, " if (QtMocHelpers::indexOfMethod<%s (%s::*)(", f.type.rawName.constData() , cdef->classname.constData()); -@@ -1105,7 +1149,7 @@ +@@ -1096,7 +1139,7 @@ } fprintf(out, ")%s>(_a, &%s::%s, %d))\n", f.isConst ? " const" : "", @@ -153,7 +148,7 @@ fprintf(out, " return;\n"); } fprintf(out, " }\n"); -@@ -1182,9 +1226,12 @@ +@@ -1173,9 +1216,12 @@ propindex, cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData(), prefix.constData(), p.bind.constData()); else if (!p.read.isEmpty()) @@ -168,7 +163,7 @@ else fprintf(out, " case %d: *reinterpret_cast<%s%s*>(_v) = %s%s; break;\n", propindex, cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData(), -@@ -1303,6 +1350,10 @@ +@@ -1294,6 +1340,10 @@ { if (def->wasCloned || def->isAbstract) return; @@ -179,7 +174,7 @@ fprintf(out, "\n// SIGNAL %d\n%s %s::%s(", index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData()); -@@ -1364,6 +1415,36 @@ +@@ -1355,6 +1405,36 @@ fprintf(out, "}\n"); } @@ -216,7 +211,7 @@ static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v); static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o) { -@@ -1491,6 +1572,8 @@ +@@ -1482,6 +1562,8 @@ fputs("\n", out); } @@ -225,7 +220,7 @@ QByteArray Generator::disambiguatedTypeName(const QByteArray &name) { -@@ -1524,4 +1607,6 @@ +@@ -1515,4 +1597,6 @@ QT_END_NAMESPACE diff --git a/tools/qscxmlc/moc_patches/generator.h.patch b/tools/qscxmlc/moc_patches/generator.h.patch index cc0cab6..7e45c84 100644 --- a/tools/qscxmlc/moc_patches/generator.h.patch +++ b/tools/qscxmlc/moc_patches/generator.h.patch @@ -1,6 +1,6 @@ ---- .upstream/generator.h 2025-06-20 07:16:49.211901974 +0200 -+++ generator.h 2025-08-05 10:37:10.298870121 +0200 -@@ -6,23 +6,34 @@ +--- .upstream/generator.h 2025-12-08 08:44:49.600222497 +0100 ++++ generator.h 2025-12-08 11:38:46.170083870 +0100 +@@ -6,24 +6,35 @@ #include "moc.h" @@ -17,17 +17,18 @@ - Moc *parser = nullptr; - FILE *out; + QIODevice &out; // -- QtScxml - ClassDef *cdef; + const ClassDef *cdef; QList<uint> meta_data; public: -- Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes, -+ Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, +- Generator(Moc *moc, const ClassDef *classDef, const QList<QByteArray> &metaTypes, ++ Generator(const ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, -- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr, -+ const QHash<QByteArray, QByteArray> &knownGadgets, + const QHash<QByteArray, QByteArray> &knownGadgets, + const QHash<QByteArray, QByteArray> &hashes, +- FILE *outfile = nullptr, bool requireCompleteTypes = false); + QIODevice &outfile, // -- QtScxml - bool requireCompleteTypes = false); ++ bool requireCompleteTypes = false); void generateCode(); qsizetype registeredStringsCount() { return strings.size(); } @@ -39,7 +40,7 @@ private: bool registerableMetaType(const QByteArray &propertyType); void registerClassInfoStrings(); -@@ -39,7 +50,9 @@ +@@ -40,7 +51,9 @@ void generateMetacall(); void generateStaticMetacall(); void generateSignal(const FunctionDef *def, int index); diff --git a/tools/qscxmlc/moc_patches/moc.cpp.patch b/tools/qscxmlc/moc_patches/moc.cpp.patch index f048095..c32b7ed 100644 --- a/tools/qscxmlc/moc_patches/moc.cpp.patch +++ b/tools/qscxmlc/moc_patches/moc.cpp.patch @@ -1,6 +1,6 @@ ---- .upstream/moc.cpp 2025-08-05 10:30:37.641278729 +0200 -+++ moc.cpp 2025-08-05 10:35:50.718576253 +0200 -@@ -12,15 +12,15 @@ +--- .upstream/moc.cpp 2025-12-08 08:44:49.600222497 +0100 ++++ moc.cpp 2025-12-08 11:47:45.363161643 +0100 +@@ -12,19 +12,15 @@ #include <QtCore/qdir.h> #include <QtCore/qjsondocument.h> @@ -8,6 +8,10 @@ -#include <private/qmetaobject_p.h> -#include <private/qmetaobject_moc_p.h> -#include <private/qduplicatetracker_p.h> +- +-// This is a bootstrapped tool, so we can't rely on QCryptographicHash for the +-// faster SHA1 implementations from OpenSSL. +-#include "../../3rdparty/sha1/sha1.cpp" +// -- QtScxml +#include <QtCore/qjsonobject.h> +// -- QtScxml @@ -20,7 +24,7 @@ // only moc needs this function static QByteArray normalizeType(const QByteArray &ba) { -@@ -2046,6 +2046,7 @@ +@@ -2131,6 +2127,7 @@ } } } @@ -28,7 +32,7 @@ QJsonObject ClassDef::toJson() const { -@@ -2242,8 +2243,8 @@ +@@ -2329,8 +2326,8 @@ def["alias"_L1] = QString::fromUtf8(enumName); if (!type.isEmpty()) def["type"_L1] = QString::fromUtf8(type); diff --git a/tools/qscxmlc/moc_patches/moc.h.patch b/tools/qscxmlc/moc_patches/moc.h.patch index 39d433d..af29acf 100644 --- a/tools/qscxmlc/moc_patches/moc.h.patch +++ b/tools/qscxmlc/moc_patches/moc.h.patch @@ -1,5 +1,5 @@ ---- .upstream/moc.h 2025-07-04 08:47:51.556486285 +0200 -+++ moc.h 2025-08-05 10:35:50.722576269 +0200 +--- .upstream/moc.h 2025-12-08 08:44:49.600222497 +0100 ++++ moc.h 2025-12-08 11:22:49.550907139 +0100 @@ -4,15 +4,13 @@ #ifndef MOC_H #define MOC_H @@ -68,7 +68,7 @@ }; Q_DECLARE_TYPEINFO(FunctionDef, Q_RELOCATABLE_TYPE); -@@ -137,6 +143,10 @@ +@@ -139,6 +145,10 @@ qsizetype location = -1; // token index, used for error reporting QJsonObject toJson() const; @@ -79,7 +79,7 @@ }; Q_DECLARE_TYPEINFO(PropertyDef, Q_RELOCATABLE_TYPE); -@@ -219,6 +229,7 @@ +@@ -222,6 +232,7 @@ }; Q_DECLARE_TYPEINFO(NamespaceDef, Q_RELOCATABLE_TYPE); @@ -87,7 +87,7 @@ class Moc : public Parser { public: -@@ -309,6 +320,7 @@ +@@ -312,6 +323,7 @@ void checkListSizes(const ClassDef &def); }; diff --git a/tools/qscxmlc/moc_patches/outputrevision.h.patch b/tools/qscxmlc/moc_patches/outputrevision.h.patch index 8e1f746..8f652f6 100644 --- a/tools/qscxmlc/moc_patches/outputrevision.h.patch +++ b/tools/qscxmlc/moc_patches/outputrevision.h.patch @@ -1,5 +1,5 @@ --- .upstream/outputrevision.h 2024-11-15 07:24:09.762842614 +0100 -+++ outputrevision.h 2025-08-05 10:35:50.714576239 +0200 ++++ outputrevision.h 2025-12-08 11:22:49.542907112 +0100 @@ -4,7 +4,13 @@ #ifndef OUTPUTREVISION_H #define OUTPUTREVISION_H diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp index be6ce7e..4f406c8 100644 --- a/tools/qscxmlc/scxmlcppdumper.cpp +++ b/tools/qscxmlc/scxmlcppdumper.cpp @@ -3,12 +3,14 @@ #include "scxmlcppdumper.h" #include "generator.h" +#include "../../src/3rdparty/sha1/sha1.cpp" #include <QtScxml/private/qscxmlexecutablecontent_p.h> -#include <QtCore/qfileinfo.h> #include <QtCore/qbuffer.h> #include <QtCore/qfile.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qjsonobject.h> #include <QtCore/qresource.h> #include <algorithm> @@ -723,6 +725,24 @@ QString CppDumper::generateSignalDecls(const GeneratedTableData::MetaDataInfo &i return decls; } +QByteArray classDefJsonObjectHash(const QJsonObject &object) +{ + const QByteArray json = QJsonDocument(object).toJson(QJsonValue::JsonFormat::Compact); + QByteArray hash(20, 0); // SHA1 produces 160 bits of data + + { + Sha1State state; + sha1InitState(&state); + sha1Update(&state, reinterpret_cast<const uchar *>(json.constData()), json.size()); + sha1FinalizeState(&state); + sha1ToHash(&state, reinterpret_cast<uchar *>(hash.data())); + } + + static const char revisionPrefix[] = "0$"; + const QByteArray hashB64 = hash.toBase64(QByteArray::OmitTrailingEquals); + return revisionPrefix + hashB64; +} + QString CppDumper::generateMetaObject(const QString &className, const GeneratedTableData::MetaDataInfo &info) { @@ -793,10 +813,16 @@ QString CppDumper::generateMetaObject(const QString &className, QHash<QByteArray, QByteArray> knownQObjectClasses; knownQObjectClasses.insert(QByteArray("QScxmlStateMachine"), QByteArray()); + QHash<QByteArray, QJsonObject> classDefJsonObjects; + QHash<QByteArray, QByteArray> metaObjectHashes; + const QJsonObject jsonObject = classDef.toJson(); + classDefJsonObjects.insert(classDef.qualified, jsonObject); + metaObjectHashes.insert(classDef.qualified, classDefJsonObjectHash(jsonObject)); + QBuffer buf; buf.open(QIODevice::WriteOnly); Generator generator(&classDef, QList<QByteArray>(), knownQObjectClasses, - QHash<QByteArray, QByteArray>(), buf); + QHash<QByteArray, QByteArray>(), metaObjectHashes, buf); generator.generateCode(); if (m_translationUnit->stateMethods) { generator.generateAccessorDefs(); |
