1// Copyright (C) 2024 Ford Motor Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qremoteobjectnode_p.h"
6#include "qremoteobjectrepparser_p.h"
7#include "qremoteobjectstructs_p.h"
8
9QT_BEGIN_NAMESPACE
10
11using namespace QRemoteObjectInternalTypes;
12
13// Make a central function to convert QStrings to QByteArrays in case we need
14// to change how this is done.
15auto toQBA = [](const QString &string) { return string.toUtf8(); };
16
17static QByteArray capName(const QString &name)
18{
19 /*
20 * Helper method to capitalize the first letter of a QString and return
21 * the result as a QByteArray
22 */
23 return toQBA(name.at(i: 0).toUpper() + name.mid(position: 1));
24}
25
26static QByteArrayList toByteArrayList(const QStringList &stringList)
27{
28 /*
29 * Helper method to convert a list of strings into a list of QByteArrays
30 */
31 QByteArrayList byteArrayList;
32 byteArrayList.reserve(asize: stringList.size());
33 for (const QString &str : stringList)
34 byteArrayList.append(t: toQBA(str));
35
36 return byteArrayList;
37};
38
39static EnumData enumToDefinition(const ASTEnum &astEnum)
40{
41 EnumData enumEntry;
42 enumEntry.name = toQBA(astEnum.name);
43 enumEntry.isFlag = false;
44 enumEntry.isScoped = astEnum.isScoped;
45 enumEntry.keyCount = astEnum.params.size();
46 enumEntry.size = sizeof(int);
47 if (!astEnum.type.isEmpty()) {
48 auto metaType = QMetaType::fromName(name: toQBA(astEnum.type));
49 if (metaType.isValid())
50 enumEntry.size = metaType.sizeOf();
51 }
52
53 for (const auto &param : astEnum.params) {
54 EnumPair pair;
55 pair.name = toQBA(param.name);
56 pair.value = param.value;
57 enumEntry.values.append(pair);
58 }
59
60 return enumEntry;
61}
62
63static GadgetData podToGadget(const POD &pod)
64{
65 // This class converts the AST for a POD into a GadgetData structure
66 GadgetData gadgetData;
67
68 for (const auto &attribute : pod.attributes) {
69 GadgetProperty property;
70 property.name = toQBA(attribute.name);
71 property.type = toQBA(attribute.type);
72 gadgetData.properties.append(property);
73 }
74
75 for (const auto &_enum : pod.enums)
76 gadgetData.enums.append(enumToDefinition(_enum));
77
78 // TODO: Fix support for Flags - don't think this currently works for dynamic gadgets
79 // Unclear what the TypeInfo would be for a Flag - it relies on a template type
80 // Should this error out with a warning?
81 /*
82 for (const auto &flag : pod.flags) {
83 EnumData enumEntry;
84 enumEntry.name = toQBA(flag.name);
85 enumEntry.isFlag = true;
86 auto it = std::find_if(gadgetData.enums.begin(), gadgetData.enums.end(),
87 [&flag](const EnumData &enumData) { return enumData.name == toQBA(flag._enum); });
88 if (it != gadgetData.enums.end()) {
89 it->isFlag = true;
90 }
91 gadgetData.enums.append(enumEntry);
92 }
93 */
94
95 return gadgetData;
96}
97
98QMetaObject *createAndRegisterMetaTypeFromPOD(const POD &pod, QObject *reference)
99{
100 auto gadget = podToGadget(pod);
101 return registerGadget(reference, gadget, toQBA(pod.name));
102}
103
104static std::tuple<bool, bool, bool> sourceModifiers(ASTProperty::Modifier modifier)
105{
106 /*
107 * Helper method to set several variables appropriately for a Source object type,
108 * based on the modifier set on the property in the .rep file.
109 */
110 bool isWritable = modifier == ASTProperty::ReadWrite || modifier == ASTProperty::ReadPush || modifier == ASTProperty::SourceOnlySetter;
111 bool hasNotify = modifier != ASTProperty::Constant;
112 bool hasPush = modifier == ASTProperty::ReadPush;
113 return std::make_tuple(args&: isWritable, args&: hasNotify, args&: hasPush);
114};
115
116static std::tuple<bool, bool, bool> replicaModifiers(ASTProperty::Modifier modifier)
117{
118 /*
119 * Helper method to set several variables appropriately for a Replica object type,
120 * based on the modifier set on the property in the .rep file.
121 */
122 bool isWritable = modifier == ASTProperty::ReadWrite;
123 bool hasNotify = true;
124 bool hasPush = modifier == ASTProperty::ReadPush;
125 return std::make_tuple(args&: isWritable, args&: hasNotify, args&: hasPush);
126};
127
128static ClassData classToDefinition(const ASTClass &astClass, bool isSource=false)
129{
130 std::function<std::tuple<bool, bool, bool>(ASTProperty::Modifier)> modifiers = isSource ? sourceModifiers : replicaModifiers;
131
132 // This class converts the AST for a Class into a ClassData structure
133 ClassData classData(isSource);
134 classData.type = toQBA(astClass.name);
135 for (const auto &prop : astClass.properties) {
136 auto [isWritable, hasNotify, hasPush] = modifiers(prop.modifier);
137 ClassProperty property;
138 property.name = toQBA(prop.name);
139 property.typeName = toQBA(prop.type);
140 property.isWritable = isWritable;
141 if (hasNotify) {
142 QByteArray signature = property.name + "Changed(" + property.typeName + ")";
143 classData._signals.append({signature, QByteArrayList() << property.name});
144 property.signalName = signature;
145 }
146 if (hasPush) {
147 ClassSlot classSlot;
148 classSlot.signature = QByteArray("push") + capName(prop.name) + '(' + toQBA(prop.type) + ')';
149 classSlot.parameterNames = QByteArrayList() << toQBA(prop.name);
150 classData._slots.append(classSlot);
151 }
152 classData.properties.append(property);
153 }
154 for (const auto &signal : astClass.signalsList) {
155 ClassSignal classSignal;
156 classSignal.signature = toQBA(signal.name) + '(' + toQBA(signal.paramsAsString(ASTFunction::Normalized)) + ')';
157 classSignal.parameterNames = toByteArrayList(signal.paramNames());
158 classData._signals.append(classSignal);
159 }
160 for (const auto &slot : astClass.slotsList) {
161 ClassSlot classSlot;
162 classSlot.signature = toQBA(slot.name) + '(' + toQBA(slot.paramsAsString(ASTFunction::Normalized)) + ')';
163 const bool isVoid = slot.returnType.isEmpty() || slot.returnType == QStringLiteral("void");
164 if (!isVoid) {
165 if (isSource)
166 classSlot.returnType = toQBA(slot.returnType);
167 else
168 classSlot.returnType = QByteArrayLiteral("QRemoteObjectPendingCall");
169 }
170 classSlot.parameterNames = toByteArrayList(slot.paramNames());
171 classData._slots.append(classSlot);
172 }
173 for (const auto &_enum : astClass.enums)
174 classData.enums.append(enumToDefinition(_enum));
175
176 // TODO: Fix support for Flags - don't think this currently works for dynamic gadgets
177 // Unclear what the TypeInfo would be for a Flag - it relies on a template type
178 // Should this error out with a warning?
179 /*
180 for (const auto &flag : pod.flags) {
181 EnumData enumEntry;
182 enumEntry.name = toQBA(flag.name);
183 enumEntry.isFlag = true;
184 auto it = std::find_if(gadgetData.enums.begin(), gadgetData.enums.end(),
185 [&flag](const EnumData &enumData) { return enumData.name == toQBA(flag._enum); });
186 if (it != gadgetData.enums.end()) {
187 it->isFlag = true;
188 }
189 gadgetData.enums.append(enumEntry);
190 }
191 */
192
193 return classData;
194}
195
196QMetaObject *createAndRegisterReplicaFromASTClass(const ASTClass &astClass, QObject *reference)
197{
198 auto classDef = classToDefinition(astClass);
199 return registerAndTrackDefinition(classDef, reference);
200}
201
202QMetaObject *createAndRegisterSourceFromASTClass(const ASTClass &astClass, QObject *reference)
203{
204 auto classDef = classToDefinition(astClass, true);
205 return registerAndTrackDefinition(classDef, reference);
206}
207
208bool addTracker(const QByteArray &typeName, QObject *reference)
209{
210 /*
211 * Helper method to add additional QObject pointers as a reference to a type.
212 * Memory will be freed when the last reference is destroyed.
213 */
214 return trackAdditionalReference(reference, typeName);
215}
216
217QT_END_NAMESPACE
218

source code of qtremoteobjects/src/remoteobjects/qremoteobjectrepparser.cpp