summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/activeqt/container/qaxbase.cpp3
-rw-r--r--tests/auto/dumpcpp/tst_dumpcpp.cpp1
-rw-r--r--tools/dumpcpp/dumpcpp.pro3
-rw-r--r--tools/dumpcpp/main.cpp521
-rw-r--r--tools/dumpcpp/moc.cpp300
-rw-r--r--tools/dumpcpp/moc.h48
6 files changed, 386 insertions, 490 deletions
diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp
index ab661a4..c1b38e2 100644
--- a/src/activeqt/container/qaxbase.cpp
+++ b/src/activeqt/container/qaxbase.cpp
@@ -3452,7 +3452,6 @@ int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v)
if (dispid == DISPID_UNKNOWN)
return index;
- Q_ASSERT(d->metaobj);
// property found, so everthing that goes wrong now should not bother the caller
index -= mo->propertyCount();
@@ -3555,8 +3554,6 @@ int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v)
const QMetaObjectExtra &moExtra = moextra_cache.value(d->metaObject());
DISPID dispid = moExtra.dispIDofName(slotname, disp);
- Q_ASSERT(d->metaobj);
-
if (dispid == DISPID_UNKNOWN && slotname.toLower().startsWith("set")) {
// see if we are calling a property set function as a slot
slotname.remove(0, 3);
diff --git a/tests/auto/dumpcpp/tst_dumpcpp.cpp b/tests/auto/dumpcpp/tst_dumpcpp.cpp
index cf542f3..039c090 100644
--- a/tests/auto/dumpcpp/tst_dumpcpp.cpp
+++ b/tests/auto/dumpcpp/tst_dumpcpp.cpp
@@ -41,7 +41,6 @@ private slots:
// A simple test to verify that an object can be instantiated and interacted with
void tst_dumpcpp::toggleAddressBar()
{
- QSKIP("Crashes in Qt 6 pending rewrite of dumpcpp for new QMetaObject", Abort); // Qt 6 Fixme
SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser;
QVERIFY(webBrowser);
bool addressBar = webBrowser->AddressBar();
diff --git a/tools/dumpcpp/dumpcpp.pro b/tools/dumpcpp/dumpcpp.pro
index aaaf5f8..5b56cea 100644
--- a/tools/dumpcpp/dumpcpp.pro
+++ b/tools/dumpcpp/dumpcpp.pro
@@ -1,7 +1,8 @@
QT += axcontainer widgets core-private
DEFINES += QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS
-SOURCES = main.cpp
+SOURCES = main.cpp moc.cpp
+HEADERS += moc.h
QMAKE_TARGET_DESCRIPTION = "Active Qt DumpCpp"
load(qt_tool)
diff --git a/tools/dumpcpp/main.cpp b/tools/dumpcpp/main.cpp
index 1545a39..d50c65d 100644
--- a/tools/dumpcpp/main.cpp
+++ b/tools/dumpcpp/main.cpp
@@ -26,10 +26,13 @@
**
****************************************************************************/
+#include "moc.h"
+
#include <QAxObject>
#include <QFile>
#include <QMetaObject>
#include <QMetaEnum>
+#include <QDebug>
#include <QTextStream>
#include <QSettings>
#include <QStringList>
@@ -85,17 +88,8 @@ void writeEnums(QTextStream &out, const QMetaObject *mo)
{
// enums
for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) {
- QMetaEnum metaEnum = mo->enumerator(ienum);
- out << " enum " << metaEnum.name() << " {" << Qt::endl;
- for (int k = 0; k < metaEnum.keyCount(); ++k) {
- QByteArray key(metaEnum.key(k));
- out << " " << key.leftJustified(24) << "= " << metaEnum.value(k);
- if (k < metaEnum.keyCount() - 1)
- out << ',';
- out << Qt::endl;
- }
- out << " };" << Qt::endl;
- out << Qt::endl;
+ formatCppEnum(out, mo->enumerator(ienum));
+ out << '\n';
}
}
@@ -184,9 +178,12 @@ static void formatConstructorSignature(QTextStream &out, ObjectCategories catego
out << ')';
}
-static void formatConstructorBody(QTextStream &out, const QByteArray &className,
+static void formatConstructorBody(QTextStream &out, const QByteArray &nameSpace,
+ const QByteArray &className,
const QString &controlID, ObjectCategories category)
{
+ if (!nameSpace.isEmpty())
+ out << nameSpace << "::";
out << className << "::" << className;
formatConstructorSignature(out, category, false);
out << " :" << Qt::endl << " ";
@@ -258,21 +255,8 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo,
functions << className;
// enums
- if (nameSpace.isEmpty() && !(category & OnlyInlines)) {
- for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) {
- QMetaEnum metaEnum = mo->enumerator(ienum);
- out << " enum " << metaEnum.name() << " {" << Qt::endl;
- for (int k = 0; k < metaEnum.keyCount(); ++k) {
- QByteArray key(metaEnum.key(k));
- out << " " << key.leftJustified(24) << "= " << metaEnum.value(k);
- if (k < metaEnum.keyCount() - 1)
- out << ',';
- out << Qt::endl;
- }
- out << " };" << Qt::endl;
- out << Qt::endl;
- }
- }
+ if (nameSpace.isEmpty() && !(category & OnlyInlines))
+ writeEnums(out, mo);
// QAxBase public virtual functions.
QByteArrayList axBase_vfuncs;
axBase_vfuncs.append("metaObject");
@@ -366,13 +350,7 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo,
functions << propertyName;
if (property.isWritable()) {
- QByteArray setter(propertyName);
- if (isupper(setter.at(0))) {
- setter = "Set" + setter;
- } else {
- setter[0] = char(toupper(setter[0]));
- setter = "set" + setter;
- }
+ const QByteArray setter = setterName(propertyName);
out << indent << "inline " << "void ";
if (category & OnlyInlines)
@@ -558,168 +536,10 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo,
}
}
-#define addStringIdx(string) \
- out << stridx(string) << ", ";
-
-// The following functions were copied from moc generator with only some minor changes
-void strreg(const QByteArray &s)
-{
- if (!stringIndex.contains(s)) {
- stringIndex.insert(s, strings.size());
- strings.append(s);
- }
-}
-
-void strDetachAndRegister(QByteArray s)
-{
- s.detach();
- strreg(s);
-}
-
-int stridx(const QByteArray &s)
-{
- int i = stringIndex.value(s);
- Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
- return i;
-}
-
-const char *metaTypeEnumValueString(int type)
-{
-#define RETURN_METATYPENAME_STRING(MetaTypeName, MetaTypeId, RealType) \
- case QMetaType::MetaTypeName: return #MetaTypeName;
-
- switch (type) {
-QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
- }
-#undef RETURN_METATYPENAME_STRING
- return nullptr;
-}
-
-int nameToBuiltinType(const QByteArray &name)
-{
- if (name.isEmpty())
- return 0;
-
- const int tp = QMetaType::type(name.constData());
- return tp < QMetaType::User ? tp : QMetaType::UnknownType;
-}
-
-void copyFileToStream(QFile *file, QTextStream *stream)
-{
- file->seek(0);
- QByteArray buffer;
- const int bufferSize = 4096 * 1024;
- buffer.resize(bufferSize);
- while (!file->atEnd()) {
- const int bytesRead = static_cast<int>(file->read(buffer.data(), bufferSize));
- if (bytesRead < bufferSize) {
- buffer.resize(bytesRead);
- *stream << buffer;
- buffer.resize(bufferSize);
- } else {
- *stream << buffer;
- }
- }
-}
-
-void generateTypeInfo(QTextStream &out, const QByteArray &typeName)
-{
- if (QtPrivate::isBuiltinType(typeName)) {
- int type;
- QByteArray valueString;
- if (typeName == "qreal") {
- type = QMetaType::UnknownType;
- valueString = "QReal";
- } else {
- type = nameToBuiltinType(typeName);
- valueString = metaTypeEnumValueString(type);
- }
- if (!valueString.isEmpty()) {
- out << "QMetaType::" << valueString;
- } else {
- Q_ASSERT(type != QMetaType::UnknownType);
- out << type;
- }
- } else {
- Q_ASSERT(!typeName.isEmpty());
- out << "0x80000000 | " << stridx(typeName);
- }
-}
-// End functions copied from moc generator
-
-void generateMethods(QTextStream &out, const QMetaObject *mo, const QMetaMethod::MethodType funcType, int &paramsIndex)
-{
- out << "// ";
- MethodFlags funcTypeFlag;
- if (funcType == QMetaMethod::Signal) {
- out << "signal";
- funcTypeFlag = MethodSignal;
- } else {
- out << "slot";
- funcTypeFlag = MethodSlot;
- }
- out << ": name, argc, parameters, tag, flags" << Qt::endl;
-
- int methodCount = mo->methodCount();
- for (int i = mo->methodOffset(); i < methodCount; ++i) {
- const QMetaMethod method(mo->method(i));
- if (method.methodType() != funcType)
- continue;
- out << " ";
- addStringIdx(method.name());
- out << method.parameterCount() << ", ";
- out << paramsIndex << ", ";
- addStringIdx(method.tag());
- out << (AccessProtected | method.attributes() | funcTypeFlag) << ',' << Qt::endl;
- paramsIndex += 1 + method.parameterCount() * 2;
- }
- out << Qt::endl;
-}
-
-void generateMethodParameters(QTextStream &out, const QMetaObject *mo, const QMetaMethod::MethodType funcType)
-{
- out << "// ";
- if (funcType == QMetaMethod::Signal)
- out << "signal";
- else if (funcType == QMetaMethod::Slot)
- out << "slot";
- out << ": parameters" << Qt::endl;
-
- int methodCount = mo->methodCount();
- for (int i = mo->methodOffset(); i < methodCount; ++i) {
- const QMetaMethod method(mo->method(i));
- if (method.methodType() != funcType)
- continue;
-
- out << " ";
-
- int argsCount = method.parameterCount();
-
- // Return type
- generateTypeInfo(out, method.typeName());
- out << ',';
-
- // Parameter types
- const auto parameterTypes = method.parameterTypes();
- for (int j = 0; j < argsCount; ++j) {
- out << ' ';
- generateTypeInfo(out, parameterTypes.at(j));
- out << ',';
- }
-
- // Parameter names
- const auto parameterNames = method.parameterNames();
- for (int j = 0; j < argsCount; ++j)
- out << ' ' << stridx(parameterNames.at(j)) << ',';
-
- out << Qt::endl;
- }
- out << Qt::endl;
-}
-
-void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className,
+bool generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className,
const QString &controlID,
- const QByteArray &nameSpace, ObjectCategories category)
+ const QByteArray &nameSpace, ObjectCategories category,
+ QString *errorString)
{
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "dumpcpp should generate the same version as moc");
@@ -727,203 +547,20 @@ void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray
if (!nameSpace.isEmpty())
qualifiedClassName = nameSpace + "::";
qualifiedClassName += className;
- QByteArray qualifiedClassNameIdentifier = qualifiedClassName;
- qualifiedClassNameIdentifier.replace(':', '_');
-
- int allClassInfoCount = mo->classInfoCount();
- int allMethodCount = mo->methodCount();
- int allPropertyCount = mo->propertyCount();
- int allEnumCount = mo->enumeratorCount();
-
- int thisClassInfoCount = allClassInfoCount - mo->classInfoOffset();
- int thisEnumCount = allEnumCount - mo->enumeratorOffset();
- int thisMethodCount = allMethodCount - mo->methodOffset();
- int thisPropertyCount = allPropertyCount - mo->propertyOffset();
-
- int signalCount = 0;
- int slotCount = 0;
- int combinedParameterCount = 0;
- int enumStart = MetaObjectPrivateFieldCount;
-
- // Register strings
- strreg(qualifiedClassName);
- for (int i = mo->classInfoOffset(); i < allClassInfoCount; ++i) {
- const QMetaClassInfo classInfo = mo->classInfo(i);
- strreg(classInfo.name());
- strreg(classInfo.value());
- }
- for (int i = mo->methodOffset(); i < allMethodCount; ++i) {
- const QMetaMethod method(mo->method(i));
- if (method.methodType() == QMetaMethod::Signal)
- signalCount++;
- if (method.methodType() == QMetaMethod::Slot)
- slotCount++;
- int argsCount = method.parameterCount();
- combinedParameterCount += argsCount;
-
- strDetachAndRegister(method.name());
- QByteArray typeName = method.typeName();
- if (!QtPrivate::isBuiltinType(typeName))
- strreg(typeName);
- strreg(method.tag());
-
- const auto parameterNames = method.parameterNames();
- const auto parameterTypes = method.parameterTypes();
- for (int j = 0; j < argsCount; ++j) {
- if (!QtPrivate::isBuiltinType(parameterTypes.at(j)))
- strDetachAndRegister(parameterTypes.at(j));
- strDetachAndRegister(parameterNames.at(j));
- }
- }
- for (int i = mo->propertyOffset(); i < allPropertyCount; ++i) {
- const QMetaProperty property = mo->property(i);
- strreg(property.name());
- if (!QtPrivate::isBuiltinType(property.typeName()))
- strreg(property.typeName());
- }
- for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) {
- const QMetaEnum enumerator = mo->enumerator(i);
- strreg(enumerator.name());
- for (int j = 0; j < enumerator.keyCount(); ++j)
- strreg(enumerator.key(j));
- }
-
- // Build data array
- out << "static const uint qt_meta_data_" << qualifiedClassNameIdentifier << "[] = {" << Qt::endl;
- out << Qt::endl;
- out << " // content:" << Qt::endl;
- out << " 7, // revision" << Qt::endl;
- out << " ";
- addStringIdx(qualifiedClassName);
- out << " // classname" << Qt::endl;
- out << " " << thisClassInfoCount << ", " << (thisClassInfoCount ? enumStart : 0) << ", // classinfo" << Qt::endl;
- enumStart += thisClassInfoCount * 2;
- out << " " << thisMethodCount << ", " << (thisMethodCount ? enumStart : 0) << ", // methods" << Qt::endl;
- enumStart += thisMethodCount * 5;
- int paramsIndex = enumStart;
- enumStart += (combinedParameterCount * 2); // parameter types + names
- enumStart += thisMethodCount; // return types
- out << " " << thisPropertyCount << ", " << (thisPropertyCount ? enumStart : 0) << ", // properties" << Qt::endl;
- enumStart += thisPropertyCount * 3;
- out << " " << thisEnumCount << ", " << (thisEnumCount ? enumStart : 0) << ", // enums/sets" << Qt::endl;
- out << " 0, 0, // constructors" << Qt::endl;
- out << " 0, // flags" << Qt::endl;
- out << " " << signalCount << ", // signal count" << Qt::endl;
- out << Qt::endl;
-
- if (thisClassInfoCount) {
- out << " // classinfo: key, value" << Qt::endl;
- for (int i = mo->classInfoOffset(); i < allClassInfoCount; ++i) {
- QMetaClassInfo classInfo = mo->classInfo(i);
- out << " ";
- addStringIdx(classInfo.name());
- addStringIdx(classInfo.value());
- out << Qt::endl;
- }
- out << Qt::endl;
- }
-
- // Signal/Slot arrays
- if (signalCount)
- generateMethods(out, mo, QMetaMethod::Signal, paramsIndex);
- if (slotCount)
- generateMethods(out, mo, QMetaMethod::Slot, paramsIndex);
-
- // Method parameter arrays
- if (signalCount)
- generateMethodParameters(out, mo, QMetaMethod::Signal);
- if (slotCount)
- generateMethodParameters(out, mo, QMetaMethod::Slot);
-
- if (thisPropertyCount) {
- out << " // properties: name, type, flags" << Qt::endl;
- for (int i = mo->propertyOffset(); i < allPropertyCount; ++i) {
- QMetaProperty property = mo->property(i);
- out << " ";
- addStringIdx(property.name());
- generateTypeInfo(out, property.typeName());
- out << ", ";
-
- uint flags = 0;
- const auto vartype = property.type();
- if (vartype != QVariant::Invalid && vartype != QVariant::UserType)
- flags = uint(vartype) << 24;
-
- if (property.isReadable())
- flags |= Readable;
- if (property.isWritable())
- flags |= Writable;
- if (property.isEnumType())
- flags |= EnumOrFlag;
- if (property.isDesignable())
- flags |= Designable;
- if (property.isScriptable())
- flags |= Scriptable;
- if (property.isStored())
- flags |= Stored;
- if (property.isEditable())
- flags |= Editable;
-
- out << "0x" << QString::number(flags, 16).rightJustified(8, QLatin1Char('0'))
- << ", \t\t // " << property.typeName() << ' ' << property.name()
- << Qt::endl;
- }
- out << Qt::endl;
- }
-
- if (thisEnumCount) {
- out << " // enums: name, flags, count, data" << Qt::endl;
- enumStart += thisEnumCount * 4;
- for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) {
- QMetaEnum enumerator = mo->enumerator(i);
- out << " ";
- addStringIdx(enumerator.name());
- out << (enumerator.isFlag() ? "0x1" : "0x0") << ", " << enumerator.keyCount() << ", " << enumStart << ", " << Qt::endl;
- enumStart += enumerator.keyCount() * 2;
- }
- out << Qt::endl;
- out << " // enum data: key, value" << Qt::endl;
- for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) {
- QMetaEnum enumerator = mo->enumerator(i);
- for (int j = 0; j < enumerator.keyCount(); ++j) {
- out << " ";
- addStringIdx(enumerator.key(j));
- out << "uint(";
- if (nameSpace.isEmpty())
- out << className << "::";
- else
- out << nameSpace << "::";
- out << enumerator.key(j) << ")," << Qt::endl;
- }
- }
+ const QString moCode = mocCode(mo, QLatin1String(qualifiedClassName),
+ category.testFlag(ActiveX) ? QLatin1String("QWidget") : QLatin1String("QObject"),
+ errorString);
+ if (moCode.isEmpty()) {
+ out << "#error moc error\n";
+ return false;
}
- out << " 0 // eod" << Qt::endl;
- out << "};" << Qt::endl;
- out << Qt::endl;
- formatConstructorBody(out, className, controlID, category);
+ out << moCode << "\n\n";
- out << "const QMetaObject " << className << "::staticMetaObject = {" << Qt::endl;
- if (category & ActiveX)
- out << "{ &QWidget::staticMetaObject," << Qt::endl;
- else
- out << "{ &QObject::staticMetaObject," << Qt::endl;
- out << "qt_meta_stringdata_all.data," << Qt::endl;
- out << "qt_meta_data_" << qualifiedClassNameIdentifier << ", nullptr, nullptr, nullptr }" << Qt::endl;
- out << "};" << Qt::endl;
- out << Qt::endl;
+ formatConstructorBody(out, nameSpace, className, controlID, category);
- out << "void *" << className << "::qt_metacast(const char *_clname)" << Qt::endl;
- out << '{' << Qt::endl;
- out << " if (!_clname) return nullptr;" << Qt::endl;
- out << " if (!strcmp(_clname, \"" << qualifiedClassName << "\"))" << Qt::endl;
- out << " return static_cast<void*>(const_cast<" << className << "*>(this));" << Qt::endl;
- if (category & ActiveX)
- out << " return QAxWidget::qt_metacast(_clname);" << Qt::endl;
- else
- out << " return QAxObject::qt_metacast(_clname);" << Qt::endl;
- out << '}' << Qt::endl;
+ return true;
}
static void formatCommentBlockFooter(const QString &typeLibFile, QTextStream &str)
@@ -1020,12 +657,8 @@ bool generateTypeLibrary(QString typeLibFile, QString outname,
QMetaObject *namespaceObject = qax_readEnumInfo(typelib, nullptr);
- QTemporaryFile classImplFile;
- if (!classImplFile.open()) {
- qWarning("dumpcpp: Cannot open temporary file.");
- return false;
- }
- QTextStream classImplOut(&classImplFile);
+ QString classImpl;
+ QTextStream classImplOut(&classImpl);
QFile implFile(outname + QLatin1String(".cpp"));
QTextStream implOut(&implFile);
if (!(category & (NoMetaObject|NoImplementation))) {
@@ -1043,8 +676,6 @@ bool generateTypeLibrary(QString typeLibFile, QString outname,
implOut << "#include \"" << outname << ".h\"" << Qt::endl;
implOut << "#include <OAIdl.h>" << Qt::endl; // For IDispatch
implOut << Qt::endl;
- implOut << "using namespace " << libName << ';' << Qt::endl;
- implOut << Qt::endl;
}
QFile declFile(outname + QLatin1String(".h"));
@@ -1129,7 +760,6 @@ bool generateTypeLibrary(QString typeLibFile, QString outname,
default:
break;
}
-
qax_deleteMetaObject(metaObject);
typeinfo->ReleaseTypeAttr(typeattr);
typeinfo->Release();
@@ -1282,9 +912,14 @@ bool generateTypeLibrary(QString typeLibFile, QString outname,
object_category | OnlyInlines);
inlinesOut << Qt::endl;
}
- if (implFile.isOpen())
- generateClassImpl(classImplOut, metaObject, className, guid.toString(), libNameBa,
- object_category);
+ if (implFile.isOpen()) {
+ QString errorString;
+ if (!generateClassImpl(classImplOut, metaObject, className, guid.toString(), libNameBa,
+ object_category, &errorString)) {
+ qWarning("%s", qPrintable(errorString));
+ return false;
+ }
+ }
}
currentTypeInfo = nullptr;
}
@@ -1297,93 +932,9 @@ bool generateTypeLibrary(QString typeLibFile, QString outname,
// String table generation logic was ported from moc generator, with some modifications
// required to split large stringdata arrays.
- if (!strings.isEmpty() && implFile.isOpen()) {
- //
- // Build stringdata struct
- //
- implOut << "struct qt_meta_stringdata_all_t {" << Qt::endl;
- implOut << " uint data[" << strings.size() * 2 << "];" << Qt::endl;
-
- QVector<QByteArrayList> listVector;
- QByteArrayList currentList;
-
- int currentTableLen = 0;
- for (const auto &s : strings) {
- currentTableLen += s.length() + 1;
- currentList.append(s);
- // Split strings into chunks less than 64k to work around compiler limits.
- if (currentTableLen > 60000) {
- implOut << " char stringdata" << listVector.size() << '[' << currentTableLen + 1 << "];" << Qt::endl;
- listVector.append(currentList);
- currentList.clear();
- currentTableLen = 0;
- }
- }
- implOut << " char stringdata" << listVector.size() << '[' << currentTableLen + 1 << "];" << Qt::endl;
- implOut << "};" << Qt::endl;
- listVector.append(currentList);
-
- implOut << "#define QT_MOC_LITERAL(ofs, len, table) \\" << Qt::endl
- << " uint(offsetof(qt_meta_stringdata_all_t, stringdata##table) + ofs), len," << Qt::endl;
-
- implOut << "static const qt_meta_stringdata_all_t qt_meta_stringdata_all = {" << Qt::endl;
- implOut << " {" << Qt::endl;
-
- int totalStringCount = 0;
- for (int i = 0; i < listVector.size(); ++i) {
- int idx = 0;
- for (int j = 0; j < listVector[i].size(); j++) {
- if (totalStringCount)
- implOut << ',' << Qt::endl;
- const QByteArray &str = listVector[i].at(j);
- implOut << "QT_MOC_LITERAL(" << idx << ", " << str.length() << ", " << i << ')';
- idx += str.length() + 1;
- }
- }
- implOut << Qt::endl << " }";
-
- //
- // Build stringdata arrays
- //
- for (const auto &l : listVector) {
- int col = 0;
- int len = 0;
- implOut << ',' << Qt::endl;
- implOut << " \"";
- for (const auto &s : l) {
- len = s.length();
- if (col && col + len >= 150) {
- implOut << '"' << Qt::endl << " \"";
- col = 0;
- } else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
- implOut << "\"\"";
- len += 2;
- }
- int idx = 0;
- while (idx < s.length()) {
- if (idx > 0) {
- col = 0;
- implOut << '"' << Qt::endl << " \"";
- }
- int spanLen = qMin(150, s.length() - idx);
- implOut << s.mid(idx, spanLen);
- idx += spanLen;
- col += spanLen;
- }
-
- implOut << "\\0";
- col += len + 2;
- }
- implOut << '"';
- }
- // Terminate stringdata struct
- implOut << Qt::endl << "};" << Qt::endl;
-
- implOut << "#undef QT_MOC_LITERAL" << Qt::endl << Qt::endl;
-
+ if (implFile.isOpen()) {
classImplOut.flush();
- copyFileToStream(&classImplFile, &implOut);
- implOut << Qt::endl;
+ implOut << classImpl << Qt::endl;
}
qax_deleteMetaObject(namespaceObject);
diff --git a/tools/dumpcpp/moc.cpp b/tools/dumpcpp/moc.cpp
new file mode 100644
index 0000000..e405b0a
--- /dev/null
+++ b/tools/dumpcpp/moc.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#include "moc.h"
+
+#include <QDir>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QProcess>
+#include <QTemporaryFile>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+QByteArray setterName(const QByteArray &propertyName)
+{
+ QByteArray setter(propertyName);
+ if (isupper(setter.at(0))) {
+ setter = "Set" + setter;
+ } else {
+ setter[0] = char(toupper(setter[0]));
+ setter = "set" + setter;
+ }
+ return setter;
+}
+
+void formatCppEnum(QTextStream &str, const QMetaEnum &metaEnum)
+{
+ str << " enum " << metaEnum.name() << " {" << Qt::endl;
+ for (int k = 0, last = metaEnum.keyCount() - 1; k <= last; ++k) {
+ QByteArray key(metaEnum.key(k));
+ str << " " << key.leftJustified(24) << "= " << metaEnum.value(k);
+ if (k < last)
+ str << ',';
+ str << Qt::endl;
+ }
+ str << " };" << Qt::endl;
+}
+
+void formatCppEnums(QTextStream &str, const QMetaObject *mo,
+ const char *qEnumDecl = nullptr /* Q_ENUM, Q_ENUM_NS */)
+{
+ const int offset = mo->enumeratorOffset();
+ const int count = mo->enumeratorCount();
+ for (int e = offset; e < count; ++e) {
+ const auto me = mo->enumerator(e);
+ formatCppEnum(str, me);
+ if (qEnumDecl)
+ str << " " << qEnumDecl << '(' << me.name() << ")\n";
+ str << '\n';
+ }
+ if (offset < count)
+ str << '\n';
+}
+
+static void formatCppMethods(QTextStream &str, const QMetaObject *mo,
+ QMetaMethod::MethodType filter)
+{
+ for (int m = mo->methodOffset(), count = mo->methodCount(); m < count; ++m) {
+ const auto &mt = mo->method(m);
+ if (mt.methodType() == filter)
+ str << " " << mt.typeName() << ' ' << mt.methodSignature() << ";\n";
+ }
+}
+
+static void formatCppProperty(QTextStream &str, const QMetaProperty &p)
+{
+ str << " Q_PROPERTY(" << p.typeName() << ' ' << p.name()
+ << " READ " << p.name();
+ if (p.isWritable())
+ str << " WRITE " << setterName(p.name());
+ if (p.hasNotifySignal())
+ str << " NOTIFY " << p.notifySignal().name();
+ if (p.isUser())
+ str << " USER true";
+ if (!p.isDesignable())
+ str << " DESIGNABLE false";
+ if (!p.isStored())
+ str << " STORED false";
+ if (p.isFinal())
+ str << " FINAL";
+ str << ")\n";
+}
+
+static void formatCppQuotedString(QTextStream &str, const char *s)
+{
+ str << '"';
+ for ( ; *s ; ++s) {
+ const char c = *s;
+ if (c == '\\' || c == '\"')
+ str << '\\';
+ str << c;
+ }
+ str << '"';
+}
+
+// Generate C++ code from an ActiveQt QMetaObject to be parsed by moc
+static QString mocHeader(const QMetaObject *mo, const QStringList &name,
+ const QString &baseClass)
+{
+ QString result;
+ QTextStream str(&result);
+
+ str << "#pragma once\n\n";
+ if (!baseClass.isEmpty())
+ str << "#include <" << baseClass << ">\n";
+ str << "#include <qt_windows.h>\n\n";
+
+ for (int n = 0, count = name.size() - 1; n < count; ++n)
+ str << "namespace " << name.at(n) << " {\n";
+
+ str << "\nclass " << name.constLast();
+ if (!baseClass.isEmpty())
+ str << " : public " << baseClass;
+ str<< "\n{\n Q_OBJECT\n";
+
+ for (int i = mo->classInfoOffset(), count = mo->classInfoCount(); i < count; ++i) {
+ const auto &info = mo->classInfo(i);
+ str << " Q_CLASSINFO(";
+ formatCppQuotedString(str, info.name());
+ str << ", ";
+ formatCppQuotedString(str, info.value());
+ str << ")\n";
+ }
+
+ for (int p = mo->propertyOffset(), count = mo-> propertyCount(); p < count; ++p)
+ formatCppProperty(str, mo->property(p));
+
+ str << "public:\n";
+
+ formatCppEnums(str, mo, "Q_ENUM");
+
+ formatCppMethods(str, mo, QMetaMethod::Constructor);
+ str << "\nQ_SIGNALS:\n";
+ formatCppMethods(str, mo, QMetaMethod::Signal);
+ str << "\npublic Q_SLOTS:\n";
+ formatCppMethods(str, mo, QMetaMethod::Slot);
+ str << "};\n";
+
+ for (int n = name.size() - 1; n >= 0 ; --n)
+ str << "} // namespace " << name.at(n) << '\n';
+
+ return result;
+}
+
+static QString processOutput(QByteArray output)
+{
+ for (int c = output.size() - 1; c >= 0; --c) {
+ if (output.at(c) == '\r')
+ output.remove(c, 1);
+ }
+ return QString::fromUtf8(output);
+}
+
+static QString runProcess(const QString &binary, const QStringList &args,
+ QString *errorString)
+{
+ QProcess process;
+ process.start(binary, args);
+ if (!process.waitForStarted()) {
+ *errorString = QLatin1String("Cannot start ") + binary + QLatin1String(": ") + process.errorString();
+ return QString();
+ }
+ if (!process.waitForFinished()) {
+ *errorString = binary + QLatin1String(" timed out: ") + process.errorString();
+ return QString();
+ }
+ if (process.exitStatus() != QProcess::NormalExit) {
+ *errorString = binary + QLatin1String(" crashed: ") + process.errorString();
+ return QString();
+ }
+ if (process.exitCode() != 0) {
+ *errorString = binary + QLatin1String(" failed: ") + processOutput(process.readAllStandardError());
+ return QString();
+ }
+ return processOutput(process.readAllStandardOutput());
+}
+
+static int lineStart(int pos, const QString *s)
+{
+ const int lineStart = s->lastIndexOf(QLatin1Char('\n'), pos);
+ return lineStart >= 0 ? lineStart + 1 : 0;
+}
+
+static int nextLineFeed(int pos, const QString *s)
+{
+ const int nextLineStart = s->indexOf(QLatin1Char('\n'), pos);
+ return nextLineStart >= 0 ? nextLineStart : s->size();
+}
+
+static void removeLines(const QString &start, const QString &end,
+ QString *s, bool keepEnd = false)
+{
+ int startPos = s->indexOf(start);
+ if (startPos < 0)
+ return;
+ int endPos = s->indexOf(end, startPos + start.size());
+ if (endPos < 0)
+ return;
+
+ startPos = lineStart(startPos, s);
+ endPos = keepEnd
+ ? lineStart(endPos, s)
+ : nextLineFeed(endPos + end.size(), s);
+ s->remove(startPos, endPos - startPos);
+}
+
+static QString cleanCode(QString code, const QString &className, const QString &headerFileName)
+{
+ // remove include of temp file
+ code.remove(QLatin1String("#include \"") + headerFileName + QLatin1String("\"\n"));
+
+ const char *removeFunctions[] = {"metaObject", "qt_metacall", "qt_static_metacall"};
+
+ const QString funcStart = className + QLatin1String("::");
+ const QString nextFuncStart = QLatin1String("\n}");
+ for (auto function : removeFunctions)
+ removeLines(funcStart + QLatin1String(function) + QLatin1Char('('), nextFuncStart, &code);
+
+ // qt_static_metacall is not implemented, cannot access private function of QAxObject
+ code.replace(QLatin1String(" qt_static_metacall,"), QLatin1String(" nullptr,"));
+
+ // Remove internal signals
+ removeLines(QLatin1String("// SIGNAL 0"), QLatin1String("QT_WARNING_POP"), &code, true);
+
+ // Fix enum uint(Namespace::Class::Value) -> uint(Namespace::Value) (dumpcpp convention)
+ const QString enumPrefix = QLatin1String("uint(");
+ QString parentName = className;
+ const int lastSep = parentName.lastIndexOf(QLatin1String("::"));
+ if (lastSep >= 0)
+ parentName.truncate(lastSep);
+ else
+ parentName.clear();
+ code.replace(enumPrefix + className + QLatin1String("::"),
+ enumPrefix + parentName + QLatin1String("::"));
+ return code;
+}
+
+QString mocCode(const QMetaObject *mo, const QString &qualifiedClassName,
+ QString baseClass, QString *errorString)
+{
+ QStringList name = qualifiedClassName.split(QLatin1String("::"));
+ if (name.isEmpty())
+ name.append(QLatin1String(mo->className()));
+
+ if (baseClass.isEmpty()) {
+ if (const auto sc = mo->superClass())
+ baseClass = QLatin1String(sc->className());
+ }
+
+ const QString tempPattern = QDir::tempPath() + QLatin1Char('/')
+ + name.constLast().toLower() + QLatin1String("_XXXXXX.h");
+ QTemporaryFile header(tempPattern);
+ if (!header.open()) {
+ *errorString = QLatin1String("Cannot open temporary file: ") + header.errorString();
+ return QString();
+ }
+ const QString headerCode = mocHeader(mo, name, baseClass);
+ header.write(headerCode.toUtf8());
+ const QString headerFileName = header.fileName();
+ header.close();
+
+ const QString binary = QLatin1String("moc.exe");
+
+ QString result = runProcess(binary, {header.fileName()}, errorString);
+ if (result.isEmpty()) {
+ errorString->append(QLatin1String("\n\nOffending code:\n"));
+ errorString->append(headerCode);
+ return result;
+ }
+
+ return cleanCode(result, name.join(QLatin1String("::")), headerFileName);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/dumpcpp/moc.h b/tools/dumpcpp/moc.h
new file mode 100644
index 0000000..30a5030
--- /dev/null
+++ b/tools/dumpcpp/moc.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** 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 __MOC__
+#define __MOC__
+
+#include <QString>
+
+QT_FORWARD_DECLARE_CLASS(QMetaEnum);
+QT_FORWARD_DECLARE_CLASS(QTextStream);
+
+QT_BEGIN_NAMESPACE
+
+QByteArray setterName(const QByteArray &propertyName);
+
+void formatCppEnum(QTextStream &str, const QMetaEnum &metaEnum);
+
+QString mocCode(const QMetaObject *, const QString &qualifiedClassName,
+ QString baseClass, QString *errorString);
+
+QT_END_NAMESPACE
+
+#endif // __MOC__