summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/bootstrap/bootstrap.pri1
-rw-r--r--src/tools/bootstrap/bootstrap.pro6
-rw-r--r--src/tools/moc/generator.cpp413
-rw-r--r--src/tools/moc/generator.h11
-rw-r--r--src/tools/moc/moc.cpp10
-rw-r--r--src/tools/moc/moc.h3
-rw-r--r--src/tools/moc/outputrevision.h2
-rw-r--r--src/tools/moc/preprocessor.cpp9
-rw-r--r--src/tools/moc/preprocessor.h2
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp457
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.pro34
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp1151
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.pro33
-rw-r--r--src/tools/tools.pro11
14 files changed, 2009 insertions, 134 deletions
diff --git a/src/tools/bootstrap/bootstrap.pri b/src/tools/bootstrap/bootstrap.pri
index 228fcaca0d..0942e5529e 100644
--- a/src/tools/bootstrap/bootstrap.pri
+++ b/src/tools/bootstrap/bootstrap.pri
@@ -14,7 +14,6 @@ DEFINES += \
QT_NO_CAST_TO_ASCII \
QT_NO_CODECS \
QT_NO_DATASTREAM \
- QT_NO_GEOM_VARIANT \
QT_NO_LIBRARY \
QT_NO_QOBJECT \
QT_NO_STL \
diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro
index 5b70a5af64..813882b6f6 100644
--- a/src/tools/bootstrap/bootstrap.pro
+++ b/src/tools/bootstrap/bootstrap.pro
@@ -17,7 +17,6 @@ DEFINES += \
QT_NO_CAST_TO_ASCII \
QT_NO_CODECS \
QT_NO_DATASTREAM \
- QT_NO_GEOM_VARIANT \
QT_NO_LIBRARY \
QT_NO_QOBJECT \
QT_NO_STL \
@@ -63,6 +62,7 @@ SOURCES += \
../../corelib/io/qfsfileengine.cpp \
../../corelib/io/qfsfileengine_iterator.cpp \
../../corelib/io/qiodevice.cpp \
+ ../../corelib/io/qfiledevice.cpp \
../../corelib/io/qtemporaryfile.cpp \
../../corelib/io/qtextstream.cpp \
../../corelib/io/qurl.cpp \
@@ -80,6 +80,10 @@ SOURCES += \
../../corelib/tools/qlocale_tools.cpp \
../../corelib/tools/qmap.cpp \
../../corelib/tools/qregexp.cpp \
+ ../../corelib/tools/qpoint.cpp \
+ ../../corelib/tools/qrect.cpp \
+ ../../corelib/tools/qsize.cpp \
+ ../../corelib/tools/qline.cpp \
../../corelib/tools/qstring.cpp \
../../corelib/tools/qstringlist.cpp \
../../corelib/tools/qvector.cpp \
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index ac602fd6e8..71df7e7579 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -54,30 +54,37 @@
QT_BEGIN_NAMESPACE
-uint qvariant_nameToType(const QByteArray &name)
+uint nameToBuiltinType(const QByteArray &name)
{
if (name.isEmpty())
return 0;
uint tp = QMetaType::type(name.constData());
- return tp < QMetaType::User ? tp : 0;
+ return tp < uint(QMetaType::User) ? tp : uint(QMetaType::UnknownType);
}
/*
- Returns true if the type is a QVariant types.
+ Returns true if the type is a built-in type.
*/
-bool isVariantType(const QByteArray &type)
-{
- return qvariant_nameToType(type) != 0;
+bool isBuiltinType(const QByteArray &type)
+ {
+ int id = QMetaType::type(type.constData());
+ if (id == QMetaType::UnknownType)
+ return false;
+ return (id < QMetaType::User);
}
-/*!
- Returns true if the type is qreal.
-*/
-static bool isQRealType(const QByteArray &type)
-{
- return (type == "qreal");
-}
+static 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 0;
+ }
Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile)
: out(outfile), cdef(classDef), metaTypes(metaTypes)
@@ -109,24 +116,28 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos;
}
-int Generator::strreg(const QByteArray &s)
+void Generator::strreg(const QByteArray &s)
{
- int idx = 0;
- for (int i = 0; i < strings.size(); ++i) {
- const QByteArray &str = strings.at(i);
- if (str == s)
- return idx;
- idx += str.length() + 1;
- for (int i = 0; i < str.length(); ++i) {
- if (str.at(i) == '\\') {
- int cnt = lengthOfEscapeSequence(str, i) - 1;
- idx -= cnt;
- i += cnt;
- }
- }
- }
- strings.append(s);
- return idx;
+ if (!strings.contains(s))
+ strings.append(s);
+}
+
+int Generator::stridx(const QByteArray &s)
+{
+ int i = strings.indexOf(s);
+ Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
+ return i;
+}
+
+// Returns the sum of all parameters (including return type) for the given
+// \a list of methods. This is needed for calculating the size of the methods'
+// parameter type/name meta-data.
+static int aggregateParameterCount(const QList<FunctionDef> &list)
+{
+ int sum = 0;
+ for (int i = 0; i < list.count(); ++i)
+ sum += list.at(i).arguments.count() + 1; // +1 for return type
+ return sum;
}
void Generator::generateCode()
@@ -135,10 +146,6 @@ void Generator::generateCode()
bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty();
-//
-// build the data array
-//
-
// filter out undeclared enumerators and sets
{
QList<EnumDef> enumList;
@@ -156,15 +163,119 @@ void Generator::generateCode()
cdef->enumList = enumList;
}
+//
+// Register all strings used in data section
+//
+ strreg(cdef->qualified);
+ registerClassInfoStrings();
+ registerFunctionStrings(cdef->signalList);
+ registerFunctionStrings(cdef->slotList);
+ registerFunctionStrings(cdef->methodList);
+ registerFunctionStrings(cdef->constructorList);
+ registerPropertyStrings();
+ registerEnumStrings();
QByteArray qualifiedClassNameIdentifier = cdef->qualified;
qualifiedClassNameIdentifier.replace(':', '_');
+//
+// Build stringdata struct
+//
+ fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
+ fprintf(out, " QByteArrayData data[%d];\n", strings.size());
+ {
+ int len = 0;
+ for (int i = 0; i < strings.size(); ++i)
+ len += strings.at(i).length() + 1;
+ fprintf(out, " char stringdata[%d];\n", len + 1);
+ }
+ fprintf(out, "};\n");
+
+ // Macro that expands into a QByteArrayData. The offset member is
+ // calculated from 1) the offset of the actual characters in the
+ // stringdata.stringdata member, and 2) the stringdata.data index of the
+ // QByteArrayData being defined. This calculation relies on the
+ // QByteArrayData::data() implementation returning simply "this + offset".
+ fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) { \\\n"
+ " Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \\\n"
+ " offsetof(qt_meta_stringdata_%s_t, stringdata) + ofs \\\n"
+ " - idx * sizeof(QByteArrayData) \\\n"
+ " }\n",
+ qualifiedClassNameIdentifier.constData());
+
+ fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
+ qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
+ fprintf(out, " {\n");
+ {
+ int idx = 0;
+ for (int i = 0; i < strings.size(); ++i) {
+ if (i)
+ fprintf(out, ",\n");
+ const QByteArray &str = strings.at(i);
+ fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length());
+ idx += str.length() + 1;
+ for (int j = 0; j < str.length(); ++j) {
+ if (str.at(j) == '\\') {
+ int cnt = lengthOfEscapeSequence(str, j) - 1;
+ idx -= cnt;
+ j += cnt;
+ }
+ }
+ }
+ fprintf(out, "\n },\n");
+ }
+
+//
+// Build stringdata array
+//
+ fprintf(out, " \"");
+ int col = 0;
+ int len = 0;
+ for (int i = 0; i < strings.size(); ++i) {
+ QByteArray s = strings.at(i);
+ len = s.length();
+ if (col && col + len >= 72) {
+ fprintf(out, "\"\n \"");
+ col = 0;
+ } else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
+ fprintf(out, "\"\"");
+ len += 2;
+ }
+ int idx = 0;
+ while (idx < s.length()) {
+ if (idx > 0) {
+ col = 0;
+ fprintf(out, "\"\n \"");
+ }
+ int spanLen = qMin(70, s.length() - idx);
+ // don't cut escape sequences at the end of a line
+ int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
+ if (backSlashPos >= idx) {
+ int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
+ spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
+ }
+ fwrite(s.constData() + idx, 1, spanLen, out);
+ idx += spanLen;
+ col += spanLen;
+ }
+
+ fputs("\\0", out);
+ col += len + 2;
+ }
+
+// Terminate stringdata struct
+ fprintf(out, "\"\n};\n");
+ fprintf(out, "#undef QT_MOC_LITERAL\n\n");
+
+//
+// build the data array
+//
+
int index = MetaObjectPrivateFieldCount;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
- fprintf(out, " %4d, // classname\n", strreg(cdef->qualified));
+ fprintf(out, " %4d, // classname\n", stridx(cdef->qualified));
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
index += cdef->classInfoList.count() * 2;
@@ -173,6 +284,15 @@ void Generator::generateCode()
index += methodCount * 5;
if (cdef->revisionedMethods)
index += methodCount;
+ int paramsIndex = index;
+ int totalParameterCount = aggregateParameterCount(cdef->signalList)
+ + aggregateParameterCount(cdef->slotList)
+ + aggregateParameterCount(cdef->methodList)
+ + aggregateParameterCount(cdef->constructorList);
+ index += totalParameterCount * 2 // types and parameter names
+ - methodCount // return "parameters" don't have names
+ - cdef->constructorList.count(); // "this" parameters don't have names
+
fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
index += cdef->propertyList.count() * 3;
if(cdef->notifyableProperties)
@@ -199,17 +319,17 @@ void Generator::generateCode()
//
// Build signals array first, otherwise the signal indices would be wrong
//
- generateFunctions(cdef->signalList, "signal", MethodSignal);
+ generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex);
//
// Build slots array
//
- generateFunctions(cdef->slotList, "slot", MethodSlot);
+ generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex);
//
// Build method array
//
- generateFunctions(cdef->methodList, "method", MethodMethod);
+ generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex);
//
// Build method version arrays
@@ -221,6 +341,15 @@ void Generator::generateCode()
}
//
+// Build method parameters array
+//
+ generateFunctionParameters(cdef->signalList, "signal");
+ generateFunctionParameters(cdef->slotList, "slot");
+ generateFunctionParameters(cdef->methodList, "method");
+ if (isConstructible)
+ generateFunctionParameters(cdef->constructorList, "constructor");
+
+//
// Build property array
//
generateProperties();
@@ -234,7 +363,7 @@ void Generator::generateCode()
// Build constructors array
//
if (isConstructible)
- generateFunctions(cdef->constructorList, "constructor", MethodConstructor);
+ generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex);
//
// Terminate data array
@@ -242,46 +371,6 @@ void Generator::generateCode()
fprintf(out, "\n 0 // eod\n};\n\n");
//
-// Build stringdata array
-//
- fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData());
- fprintf(out, " \"");
- int col = 0;
- int len = 0;
- for (int i = 0; i < strings.size(); ++i) {
- QByteArray s = strings.at(i);
- len = s.length();
- if (col && col + len >= 72) {
- fprintf(out, "\"\n \"");
- col = 0;
- } else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
- fprintf(out, "\"\"");
- len += 2;
- }
- int idx = 0;
- while (idx < s.length()) {
- if (idx > 0) {
- col = 0;
- fprintf(out, "\"\n \"");
- }
- int spanLen = qMin(70, s.length() - idx);
- // don't cut escape sequences at the end of a line
- int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
- if (backSlashPos >= idx) {
- int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
- spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
- }
- fwrite(s.constData() + idx, 1, spanLen, out);
- idx += spanLen;
- col += spanLen;
- }
-
- fputs("\\0", out);
- col += len + 2;
- }
- fprintf(out, "\"\n};\n\n");
-
-//
// Generate internal qt_static_metacall() function
//
if (cdef->hasQObject && !isQt)
@@ -293,7 +382,7 @@ void Generator::generateCode()
QList<QByteArray> extraList;
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
- if (!isVariantType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') &&
+ if (!isBuiltinType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') &&
!p.type.contains('<') && !p.type.contains('>')) {
int s = p.type.lastIndexOf("::");
if (s > 0) {
@@ -356,8 +445,9 @@ void Generator::generateCode()
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
else
fprintf(out, " { 0, ");
- fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ",
- qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
+ fprintf(out, "qt_meta_stringdata_%s.data,\n"
+ " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
+ qualifiedClassNameIdentifier.constData());
if (!hasExtraData)
fprintf(out, "0 }\n");
else
@@ -379,7 +469,7 @@ void Generator::generateCode()
//
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
fprintf(out, " if (!_clname) return 0;\n");
- fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n"
+ fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata))\n"
" return static_cast<void*>(const_cast< %s*>(this));\n",
qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
@@ -430,6 +520,15 @@ void Generator::generateCode()
}
+void Generator::registerClassInfoStrings()
+{
+ for (int i = 0; i < cdef->classInfoList.size(); ++i) {
+ const ClassInfoDef &c = cdef->classInfoList.at(i);
+ strreg(c.name);
+ strreg(c.value);
+ }
+}
+
void Generator::generateClassInfos()
{
if (cdef->classInfoList.isEmpty())
@@ -439,32 +538,37 @@ void Generator::generateClassInfos()
for (int i = 0; i < cdef->classInfoList.size(); ++i) {
const ClassInfoDef &c = cdef->classInfoList.at(i);
- fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value));
+ fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
}
}
-void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type)
+void Generator::registerFunctionStrings(const QList<FunctionDef>& list)
{
- if (list.isEmpty())
- return;
- fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype);
-
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
- QByteArray sig = f.name + '(';
- QByteArray arguments;
+ strreg(f.name);
+ if (!isBuiltinType(f.normalizedType))
+ strreg(f.normalizedType);
+ strreg(f.tag);
for (int j = 0; j < f.arguments.count(); ++j) {
const ArgumentDef &a = f.arguments.at(j);
- if (j) {
- sig += ",";
- arguments += ",";
- }
- sig += a.normalizedType;
- arguments += a.name;
+ if (!isBuiltinType(a.normalizedType))
+ strreg(a.normalizedType);
+ strreg(a.name);
}
- sig += ')';
+ }
+}
+
+void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type, int &paramsIndex)
+{
+ if (list.isEmpty())
+ return;
+ fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype);
+
+ for (int i = 0; i < list.count(); ++i) {
+ const FunctionDef &f = list.at(i);
unsigned char flags = type;
if (f.access == FunctionDef::Private)
@@ -487,8 +591,12 @@ void Generator::generateFunctions(const QList<FunctionDef>& list, const char *fu
flags |= MethodScriptable;
if (f.revision > 0)
flags |= MethodRevisioned;
- fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig),
- strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags);
+
+ int argc = f.arguments.count();
+ fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n",
+ stridx(f.name), argc, paramsIndex, stridx(f.tag), flags);
+
+ paramsIndex += 1 + argc * 2;
}
}
@@ -502,6 +610,69 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef>& list, const
}
}
+void Generator::generateFunctionParameters(const QList<FunctionDef>& list, const char *functype)
+{
+ if (list.isEmpty())
+ return;
+ fprintf(out, "\n // %ss: parameters\n", functype);
+ for (int i = 0; i < list.count(); ++i) {
+ const FunctionDef &f = list.at(i);
+ fprintf(out, " ");
+
+ // Types
+ for (int j = -1; j < f.arguments.count(); ++j) {
+ if (j > -1)
+ fputc(' ', out);
+ const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
+ generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor);
+ fputc(',', out);
+ }
+
+ // Parameter names
+ for (int j = 0; j < f.arguments.count(); ++j) {
+ const ArgumentDef &arg = f.arguments.at(j);
+ fprintf(out, " %4d,", stridx(arg.name));
+ }
+
+ fprintf(out, "\n");
+ }
+}
+
+void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName)
+{
+ Q_UNUSED(allowEmptyName);
+ if (isBuiltinType(typeName)) {
+ int type;
+ const char *valueString;
+ if (typeName == "qreal") {
+ type = QMetaType::UnknownType;
+ valueString = "QReal";
+ } else {
+ type = nameToBuiltinType(typeName);
+ valueString = metaTypeEnumValueString(type);
+ }
+ if (valueString) {
+ fprintf(out, "QMetaType::%s", valueString);
+ } else {
+ Q_ASSERT(type != QMetaType::UnknownType);
+ fprintf(out, "%4d", type);
+ }
+ } else {
+ Q_ASSERT(!typeName.isEmpty() || allowEmptyName);
+ fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(typeName));
+ }
+}
+
+void Generator::registerPropertyStrings()
+{
+ for (int i = 0; i < cdef->propertyList.count(); ++i) {
+ const PropertyDef &p = cdef->propertyList.at(i);
+ strreg(p.name);
+ if (!isBuiltinType(p.type))
+ strreg(p.type);
+ }
+}
+
void Generator::generateProperties()
{
//
@@ -513,11 +684,8 @@ void Generator::generateProperties()
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
uint flags = Invalid;
- if (!isVariantType(p.type)) {
+ if (!isBuiltinType(p.type))
flags |= EnumOrFlag;
- } else if (!isQRealType(p.type)) {
- flags |= qvariant_nameToType(p.type) << 24;
- }
if (!p.read.isEmpty())
flags |= Readable;
if (!p.write.isEmpty()) {
@@ -567,12 +735,9 @@ void Generator::generateProperties()
if (p.final)
flags |= Final;
- fprintf(out, " %4d, %4d, ",
- strreg(p.name),
- strreg(p.type));
- if (!(flags >> 24) && isQRealType(p.type))
- fprintf(out, "(QMetaType::QReal << 24) | ");
- fprintf(out, "0x%.8x,\n", flags);
+ fprintf(out, " %4d, ", stridx(p.name));
+ generateTypeInfo(p.type);
+ fprintf(out, ", 0x%.8x,\n", flags);
}
if(cdef->notifyableProperties) {
@@ -596,6 +761,16 @@ void Generator::generateProperties()
}
}
+void Generator::registerEnumStrings()
+{
+ for (int i = 0; i < cdef->enumList.count(); ++i) {
+ const EnumDef &e = cdef->enumList.at(i);
+ strreg(e.name);
+ for (int j = 0; j < e.values.count(); ++j)
+ strreg(e.values.at(j));
+ }
+}
+
void Generator::generateEnums(int index)
{
if (cdef->enumDeclarations.isEmpty())
@@ -607,7 +782,7 @@ void Generator::generateEnums(int index)
for (i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
- strreg(e.name),
+ stridx(e.name),
cdef->enumDeclarations.value(e.name) ? 1 : 0,
e.values.count(),
index);
@@ -624,7 +799,7 @@ void Generator::generateEnums(int index)
code += "::" + e.name;
code += "::" + val;
fprintf(out, " %4d, uint(%s),\n",
- strreg(val), code.constData());
+ stridx(val), code.constData());
}
}
}
@@ -926,8 +1101,9 @@ void Generator::generateStaticMetacall()
fprintf(out, " switch (_id) {\n");
for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
const FunctionDef &f = methodList.at(methodindex);
+ Q_ASSERT(!f.normalizedType.isEmpty());
fprintf(out, " case %d: ", methodindex);
- if (f.normalizedType.size())
+ if (f.normalizedType != "void")
fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
fprintf(out, "_t->");
if (f.inPrivateClass.size())
@@ -942,7 +1118,7 @@ void Generator::generateStaticMetacall()
isUsed_a = true;
}
fprintf(out, ");");
- if (f.normalizedType.size()) {
+ if (f.normalizedType != "void") {
fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
noRef(f.normalizedType).constData());
isUsed_a = true;
@@ -1021,7 +1197,8 @@ void Generator::generateSignal(FunctionDef *def,int index)
constQualifier = "const";
}
- if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) {
+ Q_ASSERT(!def->normalizedType.isEmpty());
+ if (def->arguments.isEmpty() && def->normalizedType == "void") {
fprintf(out, ")%s\n{\n"
" QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n"
"}\n", constQualifier, thisPtr.constData(), index);
@@ -1036,11 +1213,11 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
}
fprintf(out, ")%s\n{\n", constQualifier);
- if (def->type.name.size() && def->normalizedType.size())
+ if (def->type.name.size() && def->normalizedType != "void")
fprintf(out, " %s _t0 = %s();\n", noRef(def->normalizedType).constData(), noRef(def->normalizedType).constData());
fprintf(out, " void *_a[] = { ");
- if (def->normalizedType.isEmpty()) {
+ if (def->normalizedType == "void") {
fprintf(out, "0");
} else {
if (def->returnTypeIsVolatile)
@@ -1056,7 +1233,7 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
fprintf(out, " };\n");
fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
- if (def->normalizedType.size())
+ if (def->normalizedType != "void")
fprintf(out, " return _t0;\n");
fprintf(out, "}\n");
}
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index 46eee4ca06..8ebc00b100 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -55,17 +55,24 @@ public:
Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile = 0);
void generateCode();
private:
+ void registerClassInfoStrings();
void generateClassInfos();
- void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type);
+ void registerFunctionStrings(const QList<FunctionDef> &list);
+ void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type, int &paramsIndex);
void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype);
+ void generateFunctionParameters(const QList<FunctionDef> &list, const char *functype);
+ void generateTypeInfo(const QByteArray &typeName, bool allowEmptyName = false);
+ void registerEnumStrings();
void generateEnums(int index);
+ void registerPropertyStrings();
void generateProperties();
void generateMetacall();
void generateStaticMetacall();
void generateSignal(FunctionDef *def, int index);
void generatePluginMetaData();
- int strreg(const QByteArray &); // registers a string and returns its id
+ void strreg(const QByteArray &); // registers a string
+ int stridx(const QByteArray &); // returns a string's id
QList<QByteArray> strings;
QByteArray purestSuperClass;
QList<QByteArray> metaTypes;
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 4189c29de1..e85aadbba7 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -75,9 +75,7 @@ static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false)
}
}
*d = '\0';
- QByteArray result;
- if (strncmp("void", buf, d - buf) != 0)
- result = normalizeTypeInternal(buf, d, fixScope);
+ QByteArray result = normalizeTypeInternal(buf, d, fixScope);
if (buf != stackbuf)
delete [] buf;
return result;
@@ -822,8 +820,8 @@ void Moc::generate(FILE *out)
if (classList.size() && classList.first().classname == "Qt")
fprintf(out, "#include <QtCore/qobject.h>\n");
- if (mustIncludeQMetaTypeH)
- fprintf(out, "#include <QtCore/qmetatype.h>\n");
+ fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
+ fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
if (mustIncludeQPluginH)
fprintf(out, "#include <QtCore/qplugin.h>\n");
@@ -981,8 +979,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
type = "qlonglong";
else if (type == "ULongLong")
type = "qulonglong";
- else if (type == "qreal")
- mustIncludeQMetaTypeH = true;
propDef.type = type;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 9e9225da0a..b12ec492ff 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -200,7 +200,7 @@ class Moc : public Parser
public:
Moc(Preprocessor &p)
: preprocessor(p), noInclude(false), generatedCode(false),
- mustIncludeQMetaTypeH(false), mustIncludeQPluginH(false)
+ mustIncludeQPluginH(false)
{}
QByteArray filename;
@@ -208,7 +208,6 @@ public:
Preprocessor &preprocessor;
bool noInclude;
bool generatedCode;
- bool mustIncludeQMetaTypeH;
bool mustIncludeQPluginH;
QByteArray includePath;
QList<QByteArray> includeFiles;
diff --git a/src/tools/moc/outputrevision.h b/src/tools/moc/outputrevision.h
index 2ce5b9b765..cff0f98fca 100644
--- a/src/tools/moc/outputrevision.h
+++ b/src/tools/moc/outputrevision.h
@@ -43,6 +43,6 @@
#define OUTPUTREVISION_H
// if the output revision changes, you MUST change it in qobjectdefs.h too
-enum { mocOutputRevision = 64 }; // moc format output revision
+enum { mocOutputRevision = 65 }; // moc format output revision
#endif // OUTPUTREVISION_H
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 07986a71e6..696b32c728 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -937,10 +937,15 @@ Symbols Preprocessor::preprocessed(const QByteArray &filename, FILE *file)
{
QFile qfile;
qfile.open(file, QFile::ReadOnly);
- QByteArray input = qfile.readAll();
+ return preprocessed(filename, &qfile);
+}
+
+Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file)
+{
+ QByteArray input = file->readAll();
if (input.isEmpty())
return symbols;
-
+
// phase 1: get rid of backslash-newlines
input = cleaned(input);
diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h
index e0707da4ee..4e0bd6343d 100644
--- a/src/tools/moc/preprocessor.h
+++ b/src/tools/moc/preprocessor.h
@@ -62,6 +62,7 @@ typedef SubArray MacroName;
typedef QHash<MacroName, Macro> Macros;
typedef QVector<MacroName> MacroSafeSet;
+class QIODevice;
class Preprocessor : public Parser
{
@@ -80,6 +81,7 @@ public:
QSet<QByteArray> preprocessedIncludes;
Macros macros;
Symbols preprocessed(const QByteArray &filename, FILE *file);
+ Symbols preprocessed(const QByteArray &filename, QIODevice *device);
void skipUntilEndif();
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
new file mode 100644
index 0000000000..2029147ecf
--- /dev/null
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QByteArray>
+#include <QString>
+#include <QVarLengthArray>
+#include <QFile>
+#include <QList>
+#include <QBuffer>
+#include <QRegExp>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "qdbusconnection.h" // for the Export* flags
+#include "qdbusconnection_p.h" // for the qDBusCheckAsyncTag
+
+// copied from dbus-protocol.h:
+static const char docTypeHeader[] =
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
+
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface"
+#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection"
+
+#include "qdbusmetatype_p.h"
+#include "qdbusmetatype.h"
+#include "qdbusutil_p.h"
+
+#include "moc.h"
+#include "generator.h"
+
+#define PROGRAMNAME "qdbuscpp2xml"
+#define PROGRAMVERSION "0.2"
+#define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)."
+
+static QString outputFile;
+static int flags;
+
+static const char help[] =
+ "Usage: " PROGRAMNAME " [options...] [files...]\n"
+ "Parses the C++ source or header file containing a QObject-derived class and\n"
+ "produces the D-Bus Introspection XML."
+ "\n"
+ "Options:\n"
+ " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
+ " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
+ " -a Output all scriptable contents (equivalent to -psm)\n"
+ " -A Output all contents (equivalent to -PSM)\n"
+ " -o <filename> Write the output to file <filename>\n"
+ " -h Show this information\n"
+ " -V Show the program version and quit.\n"
+ "\n";
+
+
+int qDBusParametersForMethod(const FunctionDef &mm, QList<int>& metaTypes)
+{
+ QList<QByteArray> parameterTypes;
+
+ foreach (const ArgumentDef &arg, mm.arguments)
+ parameterTypes.append(arg.normalizedType);
+
+ return qDBusParametersForMethod(parameterTypes, metaTypes);
+}
+
+
+static inline QString typeNameToXml(const char *typeName)
+{
+ QString plain = QLatin1String(typeName);
+ return plain.toHtmlEscaped();
+}
+
+static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
+
+ QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
+ .arg(QLatin1String(mm.name));
+
+ // check the return type first
+ int typeId = QMetaType::type(mm.normalizedType.constData());
+ if (typeId != QMetaType::Void) {
+ if (typeId) {
+ const char *typeName = QDBusMetaType::typeToSignature(typeId);
+ if (typeName) {
+ xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n")
+ .arg(typeNameToXml(typeName));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid)
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n")
+ .arg(typeNameToXml(mm.normalizedType.constData()));
+ } else {
+ return QString();
+ }
+ } else if (!mm.normalizedType.isEmpty()) {
+ return QString(); // wasn't a valid type
+ }
+ }
+ QList<ArgumentDef> names = mm.arguments;
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ return QString(); // invalid form
+ if (isSignal && inputCount + 1 != types.count())
+ return QString(); // signal with output arguments?
+ if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message)
+ return QString(); // signal with QDBusMessage argument?
+
+ bool isScriptable = mm.isScriptable;
+ for (int j = 1; j < types.count(); ++j) {
+ // input parameter for a slot or output for a signal
+ if (types.at(j) == QDBusMetaTypeId::message) {
+ isScriptable = true;
+ continue;
+ }
+
+ QString name;
+ if (!names.at(j - 1).name.isEmpty())
+ name = QString::fromLatin1("name=\"%1\" ").arg(QString::fromLatin1(names.at(j - 1).name));
+
+ bool isOutput = isSignal || j > inputCount;
+
+ const char *signature = QDBusMetaType::typeToSignature(types.at(j));
+ xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
+ .arg(name)
+ .arg(QLatin1String(signature))
+ .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ const char *typeName = QMetaType::typeName(types.at(j));
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
+ .arg(isOutput ? QLatin1String("Out") : QLatin1String("In"))
+ .arg(isOutput && !isSignal ? j - inputCount : j - 1)
+ .arg(typeNameToXml(typeName));
+ }
+ }
+
+ int wantedMask;
+ if (isScriptable)
+ wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals
+ : QDBusConnection::ExportScriptableSlots;
+ else
+ wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals
+ : QDBusConnection::ExportNonScriptableSlots;
+ if ((flags & wantedMask) != wantedMask)
+ return QString();
+
+ if (qDBusCheckAsyncTag(mm.tag.constData()))
+ // add the no-reply annotation
+ xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
+ " value=\"true\"/>\n");
+
+ QString retval = xml;
+ retval += QString::fromLatin1(" </%1>\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+
+ return retval;
+}
+
+
+static QString generateInterfaceXml(const ClassDef *mo)
+{
+ QString retval;
+
+ // start with properties:
+ if (flags & (QDBusConnection::ExportScriptableProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
+ static const char *accessvalues[] = {0, "read", "write", "readwrite"};
+ foreach (const PropertyDef &mp, mo->propertyList) {
+ if (!((!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportNonScriptableProperties))))
+ continue;
+
+ int access = 0;
+ if (!mp.read.isEmpty())
+ access |= 1;
+ if (!mp.write.isEmpty())
+ access |= 2;
+
+ int typeId = QMetaType::type(mp.type.constData());
+ if (!typeId)
+ continue;
+ const char *signature = QDBusMetaType::typeToSignature(typeId);
+ if (!signature)
+ continue;
+
+ retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
+ .arg(QLatin1String(mp.name))
+ .arg(QLatin1String(signature))
+ .arg(QLatin1String(accessvalues[access]));
+
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ retval += QString::fromLatin1(">\n <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
+ .arg(typeNameToXml(mp.type.constData()));
+ } else {
+ retval += QLatin1String("/>\n");
+ }
+ }
+ }
+
+ // now add methods:
+
+ if (flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) {
+ foreach (const FunctionDef &mm, mo->signalList) {
+ if (mm.wasCloned)
+ continue;
+
+ retval += addFunction(mm, true);
+ }
+ }
+
+ if (flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) {
+ foreach (const FunctionDef &slot, mo->slotList) {
+ if (slot.access == FunctionDef::Public)
+ retval += addFunction(slot);
+ }
+ foreach (const FunctionDef &method, mo->methodList) {
+ if (method.access == FunctionDef::Public)
+ retval += addFunction(method);
+ }
+ }
+ return retval;
+}
+
+QString qDBusInterfaceFromClassDef(const ClassDef *mo)
+{
+ QString interface;
+
+ foreach (ClassInfoDef cid, mo->classInfoList) {
+ if (cid.name == QCLASSINFO_DBUS_INTERFACE)
+ return QString::fromUtf8(cid.value);
+ }
+ interface = QLatin1String(mo->classname);
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("local.com.trolltech.Qt."));
+ } else {
+ interface.prepend(QLatin1String("local."));
+ }
+
+ return interface;
+}
+
+
+QString qDBusGenerateClassDefXml(const ClassDef *cdef)
+{
+ foreach (const ClassInfoDef &cid, cdef->classInfoList) {
+ if (cid.name == QCLASSINFO_DBUS_INTROSPECTION)
+ return QString::fromUtf8(cid.value);
+ }
+
+ // generate the interface name from the meta object
+ QString interface = qDBusInterfaceFromClassDef(cdef);
+
+ QString xml = generateInterfaceXml(cdef);
+
+ if (xml.isEmpty())
+ return QString(); // don't add an empty interface
+ return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
+ .arg(interface, xml);
+}
+
+static void showHelp()
+{
+ printf("%s", help);
+ exit(0);
+}
+
+static void showVersion()
+{
+ printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
+ printf("D-Bus QObject-to-XML converter\n");
+ exit(0);
+}
+
+static void parseCmdLine(QStringList &arguments)
+{
+ flags = 0;
+ for (int i = 0; i < arguments.count(); ++i) {
+ const QString arg = arguments.at(i);
+
+ if (arg == QLatin1String("--help"))
+ showHelp();
+
+ if (!arg.startsWith(QLatin1Char('-')))
+ continue;
+
+ char c = arg.count() == 2 ? arg.at(1).toLatin1() : char(0);
+ switch (c) {
+ case 'P':
+ flags |= QDBusConnection::ExportNonScriptableProperties;
+ // fall through
+ case 'p':
+ flags |= QDBusConnection::ExportScriptableProperties;
+ break;
+
+ case 'S':
+ flags |= QDBusConnection::ExportNonScriptableSignals;
+ // fall through
+ case 's':
+ flags |= QDBusConnection::ExportScriptableSignals;
+ break;
+
+ case 'M':
+ flags |= QDBusConnection::ExportNonScriptableSlots;
+ // fall through
+ case 'm':
+ flags |= QDBusConnection::ExportScriptableSlots;
+ break;
+
+ case 'A':
+ flags |= QDBusConnection::ExportNonScriptableContents;
+ // fall through
+ case 'a':
+ flags |= QDBusConnection::ExportScriptableContents;
+ break;
+
+ case 'o':
+ if (arguments.count() < i + 2 || arguments.at(i + 1).startsWith(QLatin1Char('-'))) {
+ printf("-o expects a filename\n");
+ exit(1);
+ }
+ outputFile = arguments.takeAt(i + 1);
+ break;
+
+ case 'h':
+ case '?':
+ showHelp();
+ break;
+
+ case 'V':
+ showVersion();
+ break;
+
+ default:
+ printf("unknown option: \"%s\"\n", qPrintable(arg));
+ exit(1);
+ }
+ }
+
+ if (flags == 0)
+ flags = QDBusConnection::ExportScriptableContents
+ | QDBusConnection::ExportNonScriptableContents;
+}
+
+int main(int argc, char **argv)
+{
+ QStringList args;
+ for (int n = 1; n < argc; ++n)
+ args.append(QString::fromLocal8Bit(argv[n]));
+ parseCmdLine(args);
+
+ QList<ClassDef> classes;
+
+ for (int i = 0; i < args.count(); ++i) {
+ const QString arg = args.at(i);
+
+ if (arg.startsWith(QLatin1Char('-')))
+ continue;
+
+ QFile f(arg);
+ if (!f.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
+ qPrintable(arg), qPrintable(f.errorString()));
+ return 1;
+ }
+
+ Preprocessor pp;
+ Moc moc(pp);
+ pp.macros["Q_MOC_RUN"];
+ pp.macros["__cplusplus"];
+
+ const QByteArray filename = QFile::decodeName(argv[i]).toLatin1();
+
+ moc.filename = filename;
+ moc.currentFilenames.push(filename);
+
+ moc.symbols = pp.preprocessed(moc.filename, &f);
+ moc.parse();
+
+ if (moc.classList.isEmpty())
+ return 0;
+ classes = moc.classList;
+
+ f.close();
+ }
+
+ QFile output;
+ if (outputFile.isEmpty()) {
+ output.open(stdout, QIODevice::WriteOnly);
+ } else {
+ output.setFileName(outputFile);
+ if (!output.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
+ qPrintable(outputFile), qPrintable(output.errorString()));
+ return 1;
+ }
+ }
+
+ output.write(docTypeHeader);
+ output.write("<node>\n");
+ foreach (const ClassDef &cdef, classes) {
+ QString xml = qDBusGenerateClassDefXml(&cdef);
+ output.write(xml.toLocal8Bit());
+ }
+ output.write("</node>\n");
+
+ return 0;
+}
+
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro
new file mode 100644
index 0000000000..33f7937c5b
--- /dev/null
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro
@@ -0,0 +1,34 @@
+
+TEMPLATE = app
+TARGET = qdbuscpp2xml
+
+DESTDIR = ../../../bin
+
+include(../moc/moc.pri)
+
+INCLUDEPATH += .
+DEPENDPATH += .
+
+INCLUDEPATH += $$QT_BUILD_TREE/include \
+ $$QT_BUILD_TREE/include/QtDBus \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \
+ $$QT_SOURCE_TREE/src/dbus
+
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
+
+SOURCES += qdbuscpp2xml.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmisc.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp
+
+include(../bootstrap/bootstrap.pri)
+
+target.path = $$[QT_HOST_BINS]
+INSTALLS += target
+load(qt_targets)
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
new file mode 100644
index 0000000000..cc30567543
--- /dev/null
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -0,0 +1,1151 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qset.h>
+
+#include "qdbusmetatype.h"
+#include "private/qdbusintrospection_p.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define PROGRAMNAME "qdbusxml2cpp"
+#define PROGRAMVERSION "0.8"
+#define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)."
+
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+
+static QString globalClassName;
+static QString parentClassName;
+static QString proxyFile;
+static QString adaptorFile;
+static QString inputFile;
+static bool skipNamespaces;
+static bool verbose;
+static bool includeMocs;
+static QString commandLine;
+static QStringList includes;
+static QStringList wantedInterfaces;
+
+static const char help[] =
+ "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n"
+ "Produces the C++ code to implement the interfaces defined in the input file.\n"
+ "\n"
+ "Options:\n"
+ " -a <filename> Write the adaptor code to <filename>\n"
+ " -c <classname> Use <classname> as the class name for the generated classes\n"
+ " -h Show this information\n"
+ " -i <filename> Add #include to the output\n"
+ " -l <classname> When generating an adaptor, use <classname> as the parent class\n"
+ " -m Generate #include \"filename.moc\" statements in the .cpp files\n"
+ " -N Don't use namespaces\n"
+ " -p <filename> Write the proxy code to <filename>\n"
+ " -v Be verbose.\n"
+ " -V Show the program version and quit.\n"
+ "\n"
+ "If the file name given to the options -a and -p does not end in .cpp or .h, the\n"
+ "program will automatically append the suffixes and produce both files.\n"
+ "You can also use a colon (:) to separate the header name from the source file\n"
+ "name, as in '-a filename_p.h:filename.cpp'.\n"
+ "\n"
+ "If you pass a dash (-) as the argument to either -p or -a, the output is written\n"
+ "to the standard output\n";
+
+static const char includeList[] =
+ "#include <QtCore/QByteArray>\n"
+ "#include <QtCore/QList>\n"
+ "#include <QtCore/QMap>\n"
+ "#include <QtCore/QString>\n"
+ "#include <QtCore/QStringList>\n"
+ "#include <QtCore/QVariant>\n";
+
+static const char forwardDeclarations[] =
+ "QT_BEGIN_NAMESPACE\n"
+ "class QByteArray;\n"
+ "template<class T> class QList;\n"
+ "template<class Key, class Value> class QMap;\n"
+ "class QString;\n"
+ "class QStringList;\n"
+ "class QVariant;\n"
+ "QT_END_NAMESPACE\n";
+
+static void showHelp()
+{
+ printf("%s", help);
+ exit(0);
+}
+
+static void showVersion()
+{
+ printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
+ printf("D-Bus binding tool for Qt\n");
+ exit(0);
+}
+
+static QString nextArg(QStringList &args, int i, char opt)
+{
+ QString arg = args.value(i);
+ if (arg.isEmpty()) {
+ printf("-%c needs at least one argument\n", opt);
+ exit(1);
+ }
+ return args.takeAt(i);
+}
+
+static void parseCmdLine(QStringList args)
+{
+ args.takeFirst();
+
+ commandLine = QLatin1String(PROGRAMNAME " ");
+ commandLine += args.join(QLatin1String(" "));
+
+ int i = 0;
+ while (i < args.count()) {
+
+ if (!args.at(i).startsWith(QLatin1Char('-'))) {
+ ++i;
+ continue;
+ }
+ QString arg = args.takeAt(i);
+
+ char c = '\0';
+ if (arg.length() == 2)
+ c = arg.at(1).toLatin1();
+ else if (arg == QLatin1String("--help"))
+ c = 'h';
+
+ switch (c) {
+ case 'a':
+ adaptorFile = nextArg(args, i, 'a');
+ break;
+
+ case 'c':
+ globalClassName = nextArg(args, i, 'c');
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'i':
+ includes << nextArg(args, i, 'i');
+ break;
+
+ case 'l':
+ parentClassName = nextArg(args, i, 'l');
+ break;
+
+ case 'm':
+ includeMocs = true;
+ break;
+
+ case 'N':
+ skipNamespaces = true;
+ break;
+
+ case '?':
+ case 'h':
+ showHelp();
+ break;
+
+ case 'V':
+ showVersion();
+ break;
+
+ case 'p':
+ proxyFile = nextArg(args, i, 'p');
+ break;
+
+ default:
+ printf("unknown option: '%s'\n", qPrintable(arg));
+ exit(1);
+ }
+ }
+
+ if (!args.isEmpty())
+ inputFile = args.takeFirst();
+
+ wantedInterfaces << args;
+}
+
+static QDBusIntrospection::Interfaces readInput()
+{
+ QFile input(inputFile);
+ if (inputFile.isEmpty() || inputFile == QLatin1String("-"))
+ input.open(stdin, QIODevice::ReadOnly);
+ else
+ input.open(QIODevice::ReadOnly);
+
+ QByteArray data = input.readAll();
+
+ // check if the input is already XML
+ data = data.trimmed();
+ if (data.startsWith("<!DOCTYPE ") || data.startsWith("<?xml") ||
+ data.startsWith("<node") || data.startsWith("<interface"))
+ // already XML
+ return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data));
+
+ fprintf(stderr, "Cannot process input: '%s'. Stop.\n", qPrintable(inputFile));
+ exit(1);
+}
+
+static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces)
+{
+ if (!wantedInterfaces.isEmpty()) {
+ QDBusIntrospection::Interfaces::Iterator it = interfaces.begin();
+ while (it != interfaces.end())
+ if (!wantedInterfaces.contains(it.key()))
+ it = interfaces.erase(it);
+ else
+ ++it;
+ }
+}
+
+// produce a header name from the file name
+static QString header(const QString &name)
+{
+ QStringList parts = name.split(QLatin1Char(':'));
+ QString retval = parts.first();
+
+ if (retval.isEmpty() || retval == QLatin1String("-"))
+ return retval;
+
+ if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) &&
+ !retval.endsWith(QLatin1String(".cc")))
+ retval.append(QLatin1String(".h"));
+
+ return retval;
+}
+
+// produce a cpp name from the file name
+static QString cpp(const QString &name)
+{
+ QStringList parts = name.split(QLatin1Char(':'));
+ QString retval = parts.last();
+
+ if (retval.isEmpty() || retval == QLatin1String("-"))
+ return retval;
+
+ if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) &&
+ !retval.endsWith(QLatin1String(".cc")))
+ retval.append(QLatin1String(".cpp"));
+
+ return retval;
+}
+
+// produce a moc name from the file name
+static QString moc(const QString &name)
+{
+ QString retval = header(name);
+ if (retval.isEmpty())
+ return retval;
+
+ retval.truncate(retval.length() - 1); // drop the h in .h
+ retval += QLatin1String("moc");
+ return retval;
+}
+
+static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost)
+{
+ ts << "/*" << endl
+ << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << endl
+ << " * Command line was: " << commandLine << endl
+ << " *" << endl
+ << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << endl
+ << " *" << endl
+ << " * This is an auto-generated file." << endl;
+
+ if (changesWillBeLost)
+ ts << " * Do not edit! All changes made to it will be lost." << endl;
+ else
+ ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << endl
+ << " * before re-generating it." << endl;
+
+ ts << " */" << endl
+ << endl;
+
+ return ts;
+}
+
+enum ClassType { Proxy, Adaptor };
+static QString classNameForInterface(const QString &interface, ClassType classType)
+{
+ if (!globalClassName.isEmpty())
+ return globalClassName;
+
+ QStringList parts = interface.split(QLatin1Char('.'));
+
+ QString retval;
+ if (classType == Proxy)
+ foreach (QString part, parts) {
+ part[0] = part[0].toUpper();
+ retval += part;
+ }
+ else {
+ retval = parts.last();
+ retval[0] = retval[0].toUpper();
+ }
+
+ if (classType == Proxy)
+ retval += QLatin1String("Interface");
+ else
+ retval += QLatin1String("Adaptor");
+
+ return retval;
+}
+
+static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection::Annotations &annotations, int paramId = -1, const char *direction = "Out")
+{
+ int type = QDBusMetaType::signatureToType(signature.toLatin1());
+ if (type == QVariant::Invalid) {
+ QString annotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
+ if (paramId >= 0)
+ annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId);
+ QString qttype = annotations.value(annotationName);
+ if (!qttype.isEmpty())
+ return qttype.toLatin1();
+
+ fprintf(stderr, "Got unknown type `%s'\n", qPrintable(signature));
+ fprintf(stderr, "You should add <annotation name=\"%s\" value=\"<type>\"/> to the XML description\n",
+ qPrintable(annotationName));
+ exit(1);
+ }
+
+ return QVariant::typeToName(QVariant::Type(type));
+}
+
+static QString nonConstRefArg(const QByteArray &arg)
+{
+ return QLatin1String(arg + " &");
+}
+
+static QString templateArg(const QByteArray &arg)
+{
+ if (!arg.endsWith('>'))
+ return QLatin1String(arg);
+
+ return QLatin1String(arg + ' ');
+}
+
+static QString constRefArg(const QByteArray &arg)
+{
+ if (!arg.startsWith('Q'))
+ return QLatin1String(arg + ' ');
+ else
+ return QString( QLatin1String("const %1 &") ).arg( QLatin1String(arg) );
+}
+
+static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs =
+ QDBusIntrospection::Arguments())
+{
+ QStringList retval;
+ for (int i = 0; i < inputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = inputArgs.at(i);
+ QString name = arg.name;
+ if (name.isEmpty())
+ name = QString( QLatin1String("in%1") ).arg(i);
+ while (retval.contains(name))
+ name += QLatin1String("_");
+ retval << name;
+ }
+ for (int i = 0; i < outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = outputArgs.at(i);
+ QString name = arg.name;
+ if (name.isEmpty())
+ name = QString( QLatin1String("out%1") ).arg(i);
+ while (retval.contains(name))
+ name += QLatin1String("_");
+ retval << name;
+ }
+ return retval;
+}
+
+static void writeArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Annotations &annotations,
+ const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments())
+{
+ // input args:
+ bool first = true;
+ int argPos = 0;
+ for (int i = 0; i < inputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = inputArgs.at(i);
+ QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In"));
+
+ if (!first)
+ ts << ", ";
+ ts << type << argNames.at(argPos++);
+ first = false;
+ }
+
+ argPos++;
+
+ // output args
+ // yes, starting from 1
+ for (int i = 1; i < outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = outputArgs.at(i);
+ QString name = arg.name;
+
+ if (!first)
+ ts << ", ";
+ ts << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out"))
+ << argNames.at(argPos++);
+ first = false;
+ }
+}
+
+static QString propertyGetter(const QDBusIntrospection::Property &property)
+{
+ QString getter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertyGetter"));
+ if (getter.isEmpty()) {
+ getter = property.name;
+ getter[0] = getter[0].toLower();
+ }
+ return getter;
+}
+
+static QString propertySetter(const QDBusIntrospection::Property &property)
+{
+ QString setter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertySetter"));
+ if (setter.isEmpty()) {
+ setter = QLatin1String("set") + property.name;
+ setter[3] = setter[3].toUpper();
+ }
+ return setter;
+}
+
+static QString stringify(const QString &data)
+{
+ QString retval;
+ int i;
+ for (i = 0; i < data.length(); ++i) {
+ retval += QLatin1Char('\"');
+ for ( ; i < data.length() && data[i] != QLatin1Char('\n') && data[i] != QLatin1Char('\r'); ++i)
+ if (data[i] == QLatin1Char('\"'))
+ retval += QLatin1String("\\\"");
+ else
+ retval += data[i];
+ if (data[i] == QLatin1Char('\r') && data[i+1] == QLatin1Char('\n'))
+ i++;
+ retval += QLatin1String("\\n\"\n");
+ }
+ return retval;
+}
+
+static void openFile(const QString &fileName, QFile &file)
+{
+ if (fileName.isEmpty())
+ return;
+
+ bool isOk = false;
+ if (fileName == QLatin1String("-")) {
+ isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
+ } else {
+ file.setFileName(fileName);
+ isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ }
+
+ if (!isOk)
+ fprintf(stderr, "Unable to open '%s': %s\n", qPrintable(fileName),
+ qPrintable(file.errorString()));
+}
+
+static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
+{
+ // open the file
+ QString headerName = header(filename);
+ QByteArray headerData;
+ QTextStream hs(&headerData);
+
+ QString cppName = cpp(filename);
+ QByteArray cppData;
+ QTextStream cs(&cppData);
+
+ // write the header:
+ writeHeader(hs, true);
+ if (cppName != headerName)
+ writeHeader(cs, false);
+
+ // include guards:
+ QString includeGuard;
+ if (!headerName.isEmpty() && headerName != QLatin1String("-")) {
+ includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_'));
+ int pos = includeGuard.lastIndexOf(QLatin1Char('/'));
+ if (pos != -1)
+ includeGuard = includeGuard.mid(pos + 1);
+ } else {
+ includeGuard = QLatin1String("QDBUSXML2CPP_PROXY");
+ }
+ includeGuard = QString(QLatin1String("%1_%2"))
+ .arg(includeGuard)
+ .arg(QDateTime::currentDateTime().toTime_t());
+ hs << "#ifndef " << includeGuard << endl
+ << "#define " << includeGuard << endl
+ << endl;
+
+ // include our stuff:
+ hs << "#include <QtCore/QObject>" << endl
+ << includeList
+ << "#include <QtDBus/QtDBus>" << endl;
+
+ foreach (QString include, includes) {
+ hs << "#include \"" << include << "\"" << endl;
+ if (headerName.isEmpty())
+ cs << "#include \"" << include << "\"" << endl;
+ }
+
+ hs << endl;
+
+ if (cppName != headerName) {
+ if (!headerName.isEmpty() && headerName != QLatin1String("-"))
+ cs << "#include \"" << headerName << "\"" << endl << endl;
+ }
+
+ foreach (const QDBusIntrospection::Interface *interface, interfaces) {
+ QString className = classNameForInterface(interface->name, Proxy);
+
+ // comment:
+ hs << "/*" << endl
+ << " * Proxy class for interface " << interface->name << endl
+ << " */" << endl;
+ cs << "/*" << endl
+ << " * Implementation of interface class " << className << endl
+ << " */" << endl
+ << endl;
+
+ // class header:
+ hs << "class " << className << ": public QDBusAbstractInterface" << endl
+ << "{" << endl
+ << " Q_OBJECT" << endl;
+
+ // the interface name
+ hs << "public:" << endl
+ << " static inline const char *staticInterfaceName()" << endl
+ << " { return \"" << interface->name << "\"; }" << endl
+ << endl;
+
+ // constructors/destructors:
+ hs << "public:" << endl
+ << " " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);" << endl
+ << endl
+ << " ~" << className << "();" << endl
+ << endl;
+ cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << endl
+ << " : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << endl
+ << "{" << endl
+ << "}" << endl
+ << endl
+ << className << "::~" << className << "()" << endl
+ << "{" << endl
+ << "}" << endl
+ << endl;
+
+ // properties:
+ foreach (const QDBusIntrospection::Property &property, interface->properties) {
+ QByteArray type = qtTypeName(property.type, property.annotations);
+ QString templateType = templateArg(type);
+ QString constRefType = constRefArg(type);
+ QString getter = propertyGetter(property);
+ QString setter = propertySetter(property);
+
+ hs << " Q_PROPERTY(" << type << " " << property.name;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write)
+ // it's readble
+ hs << " READ " << getter;
+
+ // setter
+ if (property.access != QDBusIntrospection::Property::Read)
+ // it's writeable
+ hs << " WRITE " << setter;
+
+ hs << ")" << endl;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write) {
+ hs << " inline " << type << " " << getter << "() const" << endl
+ << " { return qvariant_cast< " << type << " >(property(\""
+ << property.name << "\")); }" << endl;
+ }
+
+ // setter:
+ if (property.access != QDBusIntrospection::Property::Read) {
+ hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl
+ << " { setProperty(\"" << property.name
+ << "\", QVariant::fromValue(value)); }" << endl;
+ }
+
+ hs << endl;
+ }
+
+ // methods:
+ hs << "public Q_SLOTS: // METHODS" << endl;
+ foreach (const QDBusIntrospection::Method &method, interface->methods) {
+ bool isDeprecated = method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true");
+ bool isNoReply =
+ method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true");
+ if (isNoReply && !method.outputArgs.isEmpty()) {
+ fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
+ continue;
+ }
+
+ hs << " inline "
+ << (isDeprecated ? "Q_DECL_DEPRECATED " : "");
+
+ if (isNoReply) {
+ hs << "Q_NOREPLY void ";
+ } else {
+ hs << "QDBusPendingReply<";
+ for (int i = 0; i < method.outputArgs.count(); ++i)
+ hs << (i > 0 ? ", " : "")
+ << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out"));
+ hs << "> ";
+ }
+
+ hs << method.name << "(";
+
+ QStringList argNames = makeArgNames(method.inputArgs);
+ writeArgList(hs, argNames, method.annotations, method.inputArgs);
+
+ hs << ")" << endl
+ << " {" << endl
+ << " QList<QVariant> argumentList;" << endl;
+
+ if (!method.inputArgs.isEmpty()) {
+ hs << " argumentList";
+ for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos)
+ hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')';
+ hs << ";" << endl;
+ }
+
+ if (isNoReply)
+ hs << " callWithArgumentList(QDBus::NoBlock, "
+ << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
+ else
+ hs << " return asyncCallWithArgumentList(QLatin1String(\""
+ << method.name << "\"), argumentList);" << endl;
+
+ // close the function:
+ hs << " }" << endl;
+
+ if (method.outputArgs.count() > 1) {
+ // generate the old-form QDBusReply methods with multiple incoming parameters
+ hs << " inline "
+ << (isDeprecated ? "Q_DECL_DEPRECATED " : "")
+ << "QDBusReply<"
+ << templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out")) << "> ";
+ hs << method.name << "(";
+
+ QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
+ writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
+
+ hs << ")" << endl
+ << " {" << endl
+ << " QList<QVariant> argumentList;" << endl;
+
+ int argPos = 0;
+ if (!method.inputArgs.isEmpty()) {
+ hs << " argumentList";
+ for (argPos = 0; argPos < method.inputArgs.count(); ++argPos)
+ hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')';
+ hs << ";" << endl;
+ }
+
+ hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, "
+ << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
+
+ argPos++;
+ hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == "
+ << method.outputArgs.count() << ") {" << endl;
+
+ // yes, starting from 1
+ for (int i = 1; i < method.outputArgs.count(); ++i)
+ hs << " " << argNames.at(argPos++) << " = qdbus_cast<"
+ << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out"))
+ << ">(reply.arguments().at(" << i << "));" << endl;
+ hs << " }" << endl
+ << " return reply;" << endl
+ << " }" << endl;
+ }
+
+ hs << endl;
+ }
+
+ hs << "Q_SIGNALS: // SIGNALS" << endl;
+ foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
+ hs << " ";
+ if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
+ QLatin1String("true"))
+ hs << "Q_DECL_DEPRECATED ";
+
+ hs << "void " << signal.name << "(";
+
+ QStringList argNames = makeArgNames(signal.outputArgs);
+ writeArgList(hs, argNames, signal.annotations, signal.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ }
+
+ // close the class:
+ hs << "};" << endl
+ << endl;
+ }
+
+ if (!skipNamespaces) {
+ QStringList last;
+ QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin();
+ do
+ {
+ QStringList current;
+ QString name;
+ if (it != interfaces.constEnd()) {
+ current = it->constData()->name.split(QLatin1Char('.'));
+ name = current.takeLast();
+ }
+
+ int i = 0;
+ while (i < current.count() && i < last.count() && current.at(i) == last.at(i))
+ ++i;
+
+ // i parts matched
+ // close last.arguments().count() - i namespaces:
+ for (int j = i; j < last.count(); ++j)
+ hs << QString((last.count() - j - 1 + i) * 2, QLatin1Char(' ')) << "}" << endl;
+
+ // open current.arguments().count() - i namespaces
+ for (int j = i; j < current.count(); ++j)
+ hs << QString(j * 2, QLatin1Char(' ')) << "namespace " << current.at(j) << " {" << endl;
+
+ // add this class:
+ if (!name.isEmpty()) {
+ hs << QString(current.count() * 2, QLatin1Char(' '))
+ << "typedef ::" << classNameForInterface(it->constData()->name, Proxy)
+ << " " << name << ";" << endl;
+ }
+
+ if (it == interfaces.constEnd())
+ break;
+ ++it;
+ last = current;
+ } while (true);
+ }
+
+ // close the include guard
+ hs << "#endif" << endl;
+
+ QString mocName = moc(filename);
+ if (includeMocs && !mocName.isEmpty())
+ cs << endl
+ << "#include \"" << mocName << "\"" << endl;
+
+ cs.flush();
+ hs.flush();
+
+ QFile file;
+ openFile(headerName, file);
+ file.write(headerData);
+
+ if (headerName == cppName) {
+ file.write(cppData);
+ } else {
+ QFile cppFile;
+ openFile(cppName, cppFile);
+ cppFile.write(cppData);
+ }
+}
+
+static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
+{
+ // open the file
+ QString headerName = header(filename);
+ QByteArray headerData;
+ QTextStream hs(&headerData);
+
+ QString cppName = cpp(filename);
+ QByteArray cppData;
+ QTextStream cs(&cppData);
+
+ // write the headers
+ writeHeader(hs, false);
+ if (cppName != headerName)
+ writeHeader(cs, true);
+
+ // include guards:
+ QString includeGuard;
+ if (!headerName.isEmpty() && headerName != QLatin1String("-")) {
+ includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_'));
+ int pos = includeGuard.lastIndexOf(QLatin1Char('/'));
+ if (pos != -1)
+ includeGuard = includeGuard.mid(pos + 1);
+ } else {
+ includeGuard = QLatin1String("QDBUSXML2CPP_ADAPTOR");
+ }
+ includeGuard = QString(QLatin1String("%1_%2"))
+ .arg(includeGuard)
+ .arg(QDateTime::currentDateTime().toTime_t());
+ hs << "#ifndef " << includeGuard << endl
+ << "#define " << includeGuard << endl
+ << endl;
+
+ // include our stuff:
+ hs << "#include <QtCore/QObject>" << endl;
+ if (cppName == headerName)
+ hs << "#include <QtCore/QMetaObject>" << endl
+ << "#include <QtCore/QVariant>" << endl;
+ hs << "#include <QtDBus/QtDBus>" << endl;
+
+ foreach (QString include, includes) {
+ hs << "#include \"" << include << "\"" << endl;
+ if (headerName.isEmpty())
+ cs << "#include \"" << include << "\"" << endl;
+ }
+
+ if (cppName != headerName) {
+ if (!headerName.isEmpty() && headerName != QLatin1String("-"))
+ cs << "#include \"" << headerName << "\"" << endl;
+
+ cs << "#include <QtCore/QMetaObject>" << endl
+ << includeList
+ << endl;
+ hs << forwardDeclarations;
+ } else {
+ hs << includeList;
+ }
+
+ hs << endl;
+
+ QString parent = parentClassName;
+ if (parentClassName.isEmpty())
+ parent = QLatin1String("QObject");
+
+ foreach (const QDBusIntrospection::Interface *interface, interfaces) {
+ QString className = classNameForInterface(interface->name, Adaptor);
+
+ // comment:
+ hs << "/*" << endl
+ << " * Adaptor class for interface " << interface->name << endl
+ << " */" << endl;
+ cs << "/*" << endl
+ << " * Implementation of adaptor class " << className << endl
+ << " */" << endl
+ << endl;
+
+ // class header:
+ hs << "class " << className << ": public QDBusAbstractAdaptor" << endl
+ << "{" << endl
+ << " Q_OBJECT" << endl
+ << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << endl
+ << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << endl
+ << stringify(interface->introspection)
+ << " \"\")" << endl
+ << "public:" << endl
+ << " " << className << "(" << parent << " *parent);" << endl
+ << " virtual ~" << className << "();" << endl
+ << endl;
+
+ if (!parentClassName.isEmpty())
+ hs << " inline " << parent << " *parent() const" << endl
+ << " { return static_cast<" << parent << " *>(QObject::parent()); }" << endl
+ << endl;
+
+ // constructor/destructor
+ cs << className << "::" << className << "(" << parent << " *parent)" << endl
+ << " : QDBusAbstractAdaptor(parent)" << endl
+ << "{" << endl
+ << " // constructor" << endl
+ << " setAutoRelaySignals(true);" << endl
+ << "}" << endl
+ << endl
+ << className << "::~" << className << "()" << endl
+ << "{" << endl
+ << " // destructor" << endl
+ << "}" << endl
+ << endl;
+
+ hs << "public: // PROPERTIES" << endl;
+ foreach (const QDBusIntrospection::Property &property, interface->properties) {
+ QByteArray type = qtTypeName(property.type, property.annotations);
+ QString constRefType = constRefArg(type);
+ QString getter = propertyGetter(property);
+ QString setter = propertySetter(property);
+
+ hs << " Q_PROPERTY(" << type << " " << property.name;
+ if (property.access != QDBusIntrospection::Property::Write)
+ hs << " READ " << getter;
+ if (property.access != QDBusIntrospection::Property::Read)
+ hs << " WRITE " << setter;
+ hs << ")" << endl;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write) {
+ hs << " " << type << " " << getter << "() const;" << endl;
+ cs << type << " "
+ << className << "::" << getter << "() const" << endl
+ << "{" << endl
+ << " // get the value of property " << property.name << endl
+ << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << endl
+ << "}" << endl
+ << endl;
+ }
+
+ // setter
+ if (property.access != QDBusIntrospection::Property::Read) {
+ hs << " void " << setter << "(" << constRefType << "value);" << endl;
+ cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << endl
+ << "{" << endl
+ << " // set the value of property " << property.name << endl
+ << " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value";
+ if (constRefType.contains(QLatin1String("QDBusVariant")))
+ cs << ".variant()";
+ cs << "));" << endl
+ << "}" << endl
+ << endl;
+ }
+
+ hs << endl;
+ }
+
+ hs << "public Q_SLOTS: // METHODS" << endl;
+ foreach (const QDBusIntrospection::Method &method, interface->methods) {
+ bool isNoReply =
+ method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true");
+ if (isNoReply && !method.outputArgs.isEmpty()) {
+ fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
+ continue;
+ }
+
+ hs << " ";
+ if (method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
+ QLatin1String("true"))
+ hs << "Q_DECL_DEPRECATED ";
+
+ QByteArray returnType;
+ if (isNoReply) {
+ hs << "Q_NOREPLY void ";
+ cs << "void ";
+ } else if (method.outputArgs.isEmpty()) {
+ hs << "void ";
+ cs << "void ";
+ } else {
+ returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out");
+ hs << returnType << " ";
+ cs << returnType << " ";
+ }
+
+ QString name = method.name;
+ hs << name << "(";
+ cs << className << "::" << name << "(";
+
+ QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
+ writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
+ writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ cs << ")" << endl
+ << "{" << endl
+ << " // handle method call " << interface->name << "." << method.name << endl;
+
+ // make the call
+ bool usingInvokeMethod = false;
+ if (parentClassName.isEmpty() && method.inputArgs.count() <= 10
+ && method.outputArgs.count() <= 1)
+ usingInvokeMethod = true;
+
+ if (usingInvokeMethod) {
+ // we are using QMetaObject::invokeMethod
+ if (!returnType.isEmpty())
+ cs << " " << returnType << " " << argNames.at(method.inputArgs.count())
+ << ";" << endl;
+
+ static const char invoke[] = " QMetaObject::invokeMethod(parent(), \"";
+ cs << invoke << name << "\"";
+
+ if (!method.outputArgs.isEmpty())
+ cs << ", Q_RETURN_ARG("
+ << qtTypeName(method.outputArgs.at(0).type, method.annotations,
+ 0, "Out")
+ << ", "
+ << argNames.at(method.inputArgs.count())
+ << ")";
+
+ for (int i = 0; i < method.inputArgs.count(); ++i)
+ cs << ", Q_ARG("
+ << qtTypeName(method.inputArgs.at(i).type, method.annotations,
+ i, "In")
+ << ", "
+ << argNames.at(i)
+ << ")";
+
+ cs << ");" << endl;
+
+ if (!returnType.isEmpty())
+ cs << " return " << argNames.at(method.inputArgs.count()) << ";" << endl;
+ } else {
+ if (parentClassName.isEmpty())
+ cs << " //";
+ else
+ cs << " ";
+
+ if (!method.outputArgs.isEmpty())
+ cs << "return ";
+
+ if (parentClassName.isEmpty())
+ cs << "static_cast<YourObjectType *>(parent())->";
+ else
+ cs << "parent()->";
+ cs << name << "(";
+
+ int argPos = 0;
+ bool first = true;
+ for (int i = 0; i < method.inputArgs.count(); ++i) {
+ cs << (first ? "" : ", ") << argNames.at(argPos++);
+ first = false;
+ }
+ ++argPos; // skip retval, if any
+ for (int i = 1; i < method.outputArgs.count(); ++i) {
+ cs << (first ? "" : ", ") << argNames.at(argPos++);
+ first = false;
+ }
+
+ cs << ");" << endl;
+ }
+ cs << "}" << endl
+ << endl;
+ }
+
+ hs << "Q_SIGNALS: // SIGNALS" << endl;
+ foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
+ hs << " ";
+ if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
+ QLatin1String("true"))
+ hs << "Q_DECL_DEPRECATED ";
+
+ hs << "void " << signal.name << "(";
+
+ QStringList argNames = makeArgNames(signal.outputArgs);
+ writeArgList(hs, argNames, signal.annotations, signal.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ }
+
+ // close the class:
+ hs << "};" << endl
+ << endl;
+ }
+
+ // close the include guard
+ hs << "#endif" << endl;
+
+ QString mocName = moc(filename);
+ if (includeMocs && !mocName.isEmpty())
+ cs << endl
+ << "#include \"" << mocName << "\"" << endl;
+
+ cs.flush();
+ hs.flush();
+
+ QFile file;
+ openFile(headerName, file);
+ file.write(headerData);
+
+ if (headerName == cppName) {
+ file.write(cppData);
+ } else {
+ QFile cppFile;
+ openFile(cppName, cppFile);
+ cppFile.write(cppData);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QStringList arguments;
+
+ for (int i = 0; i < argc; ++i) {
+ arguments.append(QString::fromLocal8Bit(argv[i]));
+ }
+
+ parseCmdLine(arguments);
+
+ QDBusIntrospection::Interfaces interfaces = readInput();
+ cleanInterfaces(interfaces);
+
+ if (!proxyFile.isEmpty() || adaptorFile.isEmpty())
+ writeProxy(proxyFile, interfaces);
+
+ if (!adaptorFile.isEmpty())
+ writeAdaptor(adaptorFile, interfaces);
+
+ return 0;
+}
+
+/*!
+ \page qdbusxml2cpp.html
+ \title QtDBus XML compiler (qdbusxml2cpp)
+ \keyword qdbusxml2cpp
+
+ The QtDBus XML compiler is a tool that can be used to parse interface descriptions and produce
+ static code representing those interfaces, which can then be used to make calls to remote
+ objects or implement said interfaces.
+
+ \c qdbusxml2cpp has two modes of operation, that correspond to the two possible outputs it can
+ produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++
+ header and a source file, which are meant to be edited and adapted to your needs.
+
+ The \c qdbusxml2cpp tool is not meant to be run every time you compile your
+ application. Instead, it's meant to be used when developing the code or when the interface
+ changes.
+
+ The adaptor classes generated by \c qdbusxml2cpp are just a skeleton that must be completed. It
+ generates, by default, calls to slots with the same name on the object the adaptor is attached
+ to. However, you may modify those slots or the property accessor functions to suit your needs.
+*/
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro b/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro
new file mode 100644
index 0000000000..5c430fdfb1
--- /dev/null
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro
@@ -0,0 +1,33 @@
+TEMPLATE = app
+TARGET = qdbusxml2cpp
+
+DESTDIR = ../../../bin
+
+INCLUDEPATH += .
+DEPENDPATH += .
+
+include(../bootstrap/bootstrap.pri)
+
+INCLUDEPATH += $$QT_BUILD_TREE/include \
+ $$QT_BUILD_TREE/include/QtDBus \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \
+ $$QT_SOURCE_TREE/src/dbus
+
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
+
+SOURCES = qdbusxml2cpp.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusintrospection.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusxmlparser.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbuserror.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp
+
+target.path = $$[QT_HOST_BINS]
+INSTALLS += target
+load(qt_targets)
diff --git a/src/tools/tools.pro b/src/tools/tools.pro
index 8c2739a381..8ad30a998d 100644
--- a/src/tools/tools.pro
+++ b/src/tools/tools.pro
@@ -1,6 +1,7 @@
TEMPLATE = subdirs
TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qdoc
+contains(QT_CONFIG, dbus): TOOLS_SUBDIRS += src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml
!contains(QT_CONFIG, no-gui): TOOLS_SUBDIRS += src_tools_uic
# Set subdir and respective target name
src_tools_bootstrap.subdir = $$PWD/bootstrap
@@ -13,6 +14,12 @@ src_tools_uic.subdir = $$PWD/uic
src_tools_uic.target = sub-uic
src_tools_qdoc.subdir = $$QT_SOURCE_TREE/src/tools/qdoc
src_tools_qdoc.target = sub-qdoc
+contains(QT_CONFIG, dbus) {
+ src_tools_qdbusxml2cpp.subdir = $$QT_SOURCE_TREE/src/tools/qdbusxml2cpp
+ src_tools_qdbusxml2cpp.target = sub-qdbusxml2cpp
+ src_tools_qdbuscpp2xml.subdir = $$QT_SOURCE_TREE/src/tools/qdbuscpp2xml
+ src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml
+}
!wince*:!ordered {
# Set dependencies for each subdir
@@ -20,6 +27,10 @@ src_tools_qdoc.target = sub-qdoc
src_tools_rcc.depends = src_tools_bootstrap
src_tools_uic.depends = src_tools_bootstrap
src_tools_qdoc.depends = src_tools_bootstrap
+ contains(QT_CONFIG, dbus) {
+ src_tools_qdbusxml2cpp.depends = src_tools_bootstrap
+ src_tools_qdbuscpp2xml.depends = src_tools_bootstrap
+ }
}
# Special handling, depending on type of project, if it used debug/release or only has one configuration