]> git.cworth.org Git - apitrace/blob - gui/saverthread.cpp
Don't buffer all stdout from retrace when generating thumbnails.
[apitrace] / gui / saverthread.cpp
1 #include "saverthread.h"
2
3 #include "trace_writer.hpp"
4 #include "trace_model.hpp"
5 #include "trace_parser.hpp"
6
7 #include <QFile>
8 #include <QHash>
9 #include <QUrl>
10
11 #include <QDebug>
12
13 #if 0
14 static trace::FunctionSig *
15 createFunctionSig(ApiTraceCall *call, unsigned id)
16 {
17     trace::FunctionSig *sig = new trace::FunctionSig();
18
19     sig->id = id;
20     sig->name = qstrdup(call->name().toLocal8Bit());
21
22     QStringList args = call->argNames();
23     sig->num_args = args.count();
24     sig->arg_names = new const char*[args.count()];
25     for (int i = 0; i < args.count(); ++i) {
26         sig->arg_names[i] = qstrdup(args[i].toLocal8Bit());
27     }
28
29     return sig;
30 }
31
32 static void
33 deleteFunctionSig(trace::FunctionSig *sig)
34 {
35     for (int i = 0; i < sig->num_args; ++i) {
36         delete [] sig->arg_names[i];
37     }
38     delete [] sig->arg_names;
39     delete [] sig->name;
40     delete sig;
41 }
42
43 static trace::StructSig *
44 createStructSig(const ApiStruct &str, unsigned id)
45 {
46     ApiStruct::Signature aSig = str.signature();
47
48     trace::StructSig *sig = new trace::StructSig();
49     sig->id = id;
50     sig->name = qstrdup(aSig.name.toLocal8Bit());
51     sig->num_members = aSig.memberNames.count();
52     char **member_names = new char*[aSig.memberNames.count()];
53     sig->member_names = (const char **)member_names;
54     for (int i = 0; i < aSig.memberNames.count(); ++i) {
55         member_names[i] = qstrdup(aSig.memberNames[i].toLocal8Bit());
56     }
57     return sig;
58 }
59
60 static void
61 deleteStructSig(trace::StructSig *sig)
62 {
63     for (int i = 0; i < sig->num_members; ++i) {
64         delete [] sig->member_names[i];
65     }
66     delete [] sig->member_names;
67     delete [] sig->name;
68     delete sig;
69 }
70
71 static trace::EnumSig *
72 createEnumSig(const ApiEnum &en, unsigned id)
73 {
74     trace::EnumSig *sig = new trace::EnumSig();
75
76     sig->id = id;
77     sig->name = qstrdup(en.name().toLocal8Bit());
78     sig->value = en.value().toLongLong();
79
80     return sig;
81 }
82
83 static void
84 deleteEnumSig(trace::EnumSig *sig)
85 {
86     delete [] sig->name;
87     delete sig;
88 }
89
90 static trace::BitmaskSig *
91 createBitmaskSig(const ApiBitmask &bt, unsigned id)
92 {
93     ApiBitmask::Signature bsig = bt.signature();
94     ApiBitmask::Signature::const_iterator itr;
95
96     trace::BitmaskSig *sig = new trace::BitmaskSig();
97     trace::BitmaskFlag *flags = new trace::BitmaskFlag[bsig.count()];
98
99     sig->id = id;
100     sig->num_flags = bsig.count();
101     sig->flags = flags;
102
103     int i = 0;
104     for (itr = bsig.constBegin(); itr != bsig.constEnd(); ++itr, ++i) {
105         flags[i].name = qstrdup(itr->first.toLocal8Bit());
106         flags[i].value = itr->second;
107     }
108
109     return sig;
110 }
111
112 static void
113 deleteBitmaskSig(trace::BitmaskSig *sig)
114 {
115     for (int i = 0; i < sig->num_flags; ++i) {
116         delete [] sig->flags[i].name;
117     }
118     delete [] sig->flags;
119     delete sig;
120 }
121
122 static void
123 writeValue(trace::Writer &writer, const QVariant &var, unsigned &id)
124 {
125     int arrayType   = QMetaType::type("ApiArray");
126     int bitmaskType = QMetaType::type("ApiBitmask");
127     int structType  = QMetaType::type("ApiStruct");
128     int pointerType = QMetaType::type("ApiPointer");
129     int enumType    = QMetaType::type("ApiEnum");
130     int type = var.userType();
131
132     switch(type) {
133     case QVariant::Bool:
134         writer.writeBool(var.toBool());
135         break;
136     case QVariant::ByteArray: {
137         QByteArray ba = var.toByteArray();
138         writer.writeBlob((const void*)ba.constData(), ba.size());
139     }
140         break;
141     case QVariant::Double:
142         writer.writeDouble(var.toDouble());
143         break;
144     case QMetaType::Float:
145         writer.writeFloat(var.toFloat());
146         break;
147     case QVariant::Int:
148         writer.writeSInt(var.toInt());
149         break;
150     case QVariant::LongLong:
151         writer.writeSInt(var.toLongLong());
152         break;
153     case QVariant::String: {
154         QString str = var.toString();
155         writer.writeString(str.toLocal8Bit().constData(), str.length());
156     }
157         break;
158     case QVariant::UInt:
159         writer.writeUInt(var.toInt());
160         break;
161     case QVariant::ULongLong:
162         writer.writeUInt(var.toLongLong());
163         break;
164     default:
165         if (type == arrayType) {
166             ApiArray array = var.value<ApiArray>();
167             QVector<QVariant> vals = array.values();
168             writer.beginArray(vals.count());
169             foreach(QVariant el, vals) {
170                 writer.beginElement();
171                 writeValue(writer, el, ++id);
172                 writer.endElement();
173             }
174             writer.endArray();
175         } else if (type == bitmaskType) {
176             ApiBitmask bm = var.value<ApiBitmask>();
177             trace::BitmaskSig *sig = createBitmaskSig(bm, ++id);
178             writer.writeBitmask(sig, bm.value());
179             deleteBitmaskSig(sig);
180         } else if (type == structType) {
181             ApiStruct apiStr = var.value<ApiStruct>();
182             QList<QVariant> vals = apiStr.values();
183             trace::StructSig *str = createStructSig(apiStr, ++id);
184             writer.beginStruct(str);
185             foreach(QVariant val, vals) {
186                 writeValue(writer, val, ++id);
187             }
188             writer.endStruct();
189             deleteStructSig(str);
190         } else if (type == pointerType) {
191             ApiPointer apiPtr = var.value<ApiPointer>();
192             //writer.beginArray(1);
193             //writer.beginElement();
194             writer.writeOpaque((const void*)apiPtr.value());
195             //writer.endElement();
196             //writer.endArray();
197         } else if (type == enumType) {
198             ApiEnum apiEnum = var.value<ApiEnum>();
199             trace::EnumSig *sig = createEnumSig(apiEnum, ++id);
200             writer.writeEnum(sig);
201             deleteEnumSig(sig);
202         } else {
203             qWarning()<<"Unsupported write variant : "
204                       << QMetaType::typeName(type);
205         }
206     }
207 }
208 #endif
209
210 class EditVisitor : public trace::Visitor
211 {
212 public:
213     EditVisitor(const QVariant &variant)
214         : m_variant(variant),
215           m_editedValue(0)
216     {}
217     virtual void visit(trace::Null *val)
218     {
219         m_editedValue = val;
220     }
221
222     virtual void visit(trace::Bool *node)
223     {
224 //        Q_ASSERT(m_variant.userType() == QVariant::Bool);
225         bool var = m_variant.toBool();
226         m_editedValue = new trace::Bool(var);
227     }
228
229     virtual void visit(trace::SInt *node)
230     {
231 //        Q_ASSERT(m_variant.userType() == QVariant::Int);
232         m_editedValue = new trace::SInt(m_variant.toInt());
233     }
234
235     virtual void visit(trace::UInt *node)
236     {
237 //        Q_ASSERT(m_variant.userType() == QVariant::UInt);
238         m_editedValue = new trace::SInt(m_variant.toUInt());
239     }
240
241     virtual void visit(trace::Float *node)
242     {
243         m_editedValue = new trace::Float(m_variant.toFloat());
244     }
245
246     virtual void visit(trace::Double *node)
247     {
248         m_editedValue = new trace::Double(m_variant.toDouble());
249     }
250
251     virtual void visit(trace::String *node)
252     {
253         QString str = m_variant.toString();
254         m_editedValue = new trace::String(str.toLocal8Bit().constData());
255     }
256
257     virtual void visit(trace::Enum *e)
258     {
259         m_editedValue = e;
260     }
261
262     virtual void visit(trace::Bitmask *bitmask)
263     {
264         m_editedValue = bitmask;
265     }
266
267     virtual void visit(trace::Struct *str)
268     {
269         m_editedValue = str;
270     }
271
272     virtual void visit(trace::Array *array)
273     {
274         ApiArray apiArray = m_variant.value<ApiArray>();
275         QVector<QVariant> vals = apiArray.values();
276
277         trace::Array *newArray = new trace::Array(vals.count());
278         for (int i = 0; i < vals.count(); ++i) {
279             EditVisitor visitor(vals[i]);
280
281             array->values[i]->visit(visitor);
282             if (array->values[i] == visitor.value()) {
283                 //non-editabled
284                 delete newArray;
285                 m_editedValue = array;
286                 return;
287             }
288
289             newArray->values.push_back(visitor.value());
290         }
291         m_editedValue = newArray;
292     }
293
294     virtual void visit(trace::Blob *blob)
295     {
296         m_editedValue = blob;
297     }
298
299     virtual void visit(trace::Pointer *ptr)
300     {
301         m_editedValue = ptr;
302     }
303
304     trace::Value *value() const
305     {
306         return m_editedValue;
307     }
308 private:
309     QVariant m_variant;
310     trace::Value *m_editedValue;
311 };
312
313 static void
314 overwriteValue(trace::Call *call, const QVariant &val, int index)
315 {
316     EditVisitor visitor(val);
317     trace::Value *origValue = call->args[index].value;
318     origValue->visit(visitor);
319
320     if (visitor.value() && origValue != visitor.value()) {
321         delete origValue;
322         call->args[index].value = visitor.value();
323     }
324 }
325
326 SaverThread::SaverThread(QObject *parent)
327     : QThread(parent)
328 {
329 }
330
331 void SaverThread::saveFile(const QString &writeFileName,
332                            const QString &readFileName,
333                            const QSet<ApiTraceCall*> &editedCalls)
334 {
335     m_writeFileName = writeFileName;
336     m_readFileName = readFileName;
337     m_editedCalls = editedCalls;
338     start();
339 }
340
341 void SaverThread::run()
342 {
343     qDebug() << "Saving  " << m_readFileName
344              << ", to " << m_writeFileName;
345     QMap<int, ApiTraceCall*> callIndexMap;
346
347     foreach(ApiTraceCall *call, m_editedCalls) {
348         callIndexMap.insert(call->index(), call);
349     }
350
351     trace::Writer writer;
352     writer.open(m_writeFileName.toLocal8Bit());
353
354     trace::Parser parser;
355     parser.open(m_readFileName.toLocal8Bit());
356
357     trace::Call *call;
358     while ((call = parser.parse_call())) {
359         if (callIndexMap.contains(call->no)) {
360             QVector<QVariant> values = callIndexMap[call->no]->editedValues();
361             for (int i = 0; i < values.count(); ++i) {
362                 const QVariant &val = values[i];
363                 overwriteValue(call, val, i);
364             }
365             writer.writeCall(call);
366         } else {
367             writer.writeCall(call);
368         }
369     }
370
371     writer.close();
372
373     emit traceSaved();
374 }
375
376 #include "saverthread.moc"