]> git.cworth.org Git - apitrace/blob - gui/saverthread.cpp
b8b1bfb4bf5d2a4d9ee1c081c4281fe7d4f2bb90
[apitrace] / gui / saverthread.cpp
1 #include "saverthread.h"
2
3 #include "trace_write.hpp"
4
5 #include <QFile>
6 #include <QHash>
7 #include <QUrl>
8
9 #include <QDebug>
10
11
12 static Trace::FunctionSig *
13 createFunctionSig(ApiTraceCall *call, unsigned id)
14 {
15     Trace::FunctionSig *sig = new Trace::FunctionSig();
16
17     sig->id = id;
18     sig->name = qstrdup(call->name().toLocal8Bit());
19
20     QStringList args = call->argNames();
21     sig->num_args = args.count();
22     sig->args = new const char*[args.count()];
23     for (int i = 0; i < args.count(); ++i) {
24         sig->args[i] = qstrdup(args[i].toLocal8Bit());
25     }
26
27     return sig;
28 }
29
30 static void
31 deleteFunctionSig(Trace::FunctionSig *sig)
32 {
33     for (int i = 0; i < sig->num_args; ++i) {
34         delete [] sig->args[i];
35     }
36     delete [] sig->args;
37     delete [] sig->name;
38     delete sig;
39 }
40
41 static Trace::StructSig *
42 createStructSig(const ApiStruct &str, unsigned id)
43 {
44     ApiStruct::Signature aSig = str.signature();
45
46     Trace::StructSig *sig = new Trace::StructSig();
47     sig->id = id;
48     sig->name = qstrdup(aSig.name.toLocal8Bit());
49     sig->num_members = aSig.memberNames.count();
50     char **members = new char*[aSig.memberNames.count()];
51     sig->members = (const char **)members;
52     for (int i = 0; i < aSig.memberNames.count(); ++i) {
53         members[i] = qstrdup(aSig.memberNames[i].toLocal8Bit());
54     }
55     return sig;
56 }
57
58 static void
59 deleteStructSig(Trace::StructSig *sig)
60 {
61     for (int i = 0; i < sig->num_members; ++i) {
62         delete [] sig->members[i];
63     }
64     delete [] sig->members;
65     delete [] sig->name;
66     delete sig;
67 }
68
69 static Trace::EnumSig *
70 createEnumSig(const ApiEnum &en, unsigned id)
71 {
72     Trace::EnumSig *sig = new Trace::EnumSig();
73
74     sig->id = id;
75     sig->name = qstrdup(en.name().toLocal8Bit());
76     sig->value = en.value().toLongLong();
77
78     return sig;
79 }
80
81 static void
82 deleteEnumSig(Trace::EnumSig *sig)
83 {
84     delete [] sig->name;
85     delete sig;
86 }
87
88 static Trace::BitmaskSig *
89 createBitmaskSig(const ApiBitmask &bt, unsigned id)
90 {
91     ApiBitmask::Signature bsig = bt.signature();
92     ApiBitmask::Signature::const_iterator itr;
93
94     Trace::BitmaskSig *sig = new Trace::BitmaskSig();
95     Trace::BitmaskVal *values = new Trace::BitmaskVal[bsig.count()];
96
97     sig->id = id;
98     sig->count = bsig.count();
99     sig->values = values;
100
101     int i = 0;
102     for (itr = bsig.constBegin(); itr != bsig.constEnd(); ++itr, ++i) {
103         values[i].name = qstrdup(itr->first.toLocal8Bit());
104         values[i].value = itr->second;
105     }
106
107     return sig;
108 }
109
110 static void
111 deleteBitmaskSig(Trace::BitmaskSig *sig)
112 {
113     for (int i = 0; i < sig->count; ++i) {
114         delete [] sig->values[i].name;
115     }
116     delete [] sig->values;
117     delete sig;
118 }
119
120 static void
121 writeArgument(const QVariant &var, unsigned &id)
122 {
123     int arrayType   = QMetaType::type("ApiArray");
124     int bitmaskType = QMetaType::type("ApiBitmask");
125     int structType  = QMetaType::type("ApiStruct");
126     int pointerType = QMetaType::type("ApiPointer");
127     int enumType    = QMetaType::type("ApiEnum");
128     int type = var.userType();
129
130     Trace::BeginArg(++id);
131     switch(type) {
132     case QVariant::Bool:
133         Trace::LiteralBool(var.toBool());
134         break;
135     case QVariant::ByteArray: {
136         QByteArray ba = var.toByteArray();
137         Trace::LiteralBlob((const void*)ba.constData(), ba.size());
138     }
139         break;
140     case QVariant::Double:
141         Trace::LiteralFloat(var.toDouble());
142         break;
143     case QMetaType::Float:
144         Trace::LiteralFloat(var.toFloat());
145         break;
146     case QVariant::Int:
147         Trace::LiteralSInt(var.toInt());
148         break;
149     case QVariant::LongLong:
150         Trace::LiteralSInt(var.toLongLong());
151         break;
152     case QVariant::String: {
153         QString str = var.toString();
154         Trace::LiteralString(str.toLocal8Bit().constData(), str.length());
155     }
156         break;
157     case QVariant::UInt:
158         Trace::LiteralUInt(var.toInt());
159         break;
160     case QVariant::ULongLong:
161         Trace::LiteralUInt(var.toLongLong());
162         break;
163     default:
164         if (type == arrayType) {
165             ApiArray array = var.value<ApiArray>();
166             QList<QVariant> vals = array.values();
167             Trace::BeginArray(vals.count());
168             foreach(QVariant el, vals) {
169                 Trace::BeginElement();
170                 writeArgument(el, ++id);
171                 Trace::EndElement();
172             }
173             Trace::EndArray();
174         } else if (type == bitmaskType) {
175             ApiBitmask bm = var.value<ApiBitmask>();
176             Trace::BitmaskSig *sig = createBitmaskSig(bm, ++id);
177             LiteralBitmask(*sig, bm.value());
178             deleteBitmaskSig(sig);
179         } else if (type == structType) {
180             ApiStruct apiStr = var.value<ApiStruct>();
181             QList<QVariant> vals = apiStr.values();
182             Trace::StructSig *str = createStructSig(apiStr, ++id);
183             Trace::BeginStruct(str);
184             foreach(QVariant val, vals) {
185                 writeArgument(val, ++id);
186             }
187             Trace::EndStruct();
188             deleteStructSig(str);
189         } else if (type == pointerType) {
190             ApiPointer apiPtr = var.value<ApiPointer>();
191             Trace::BeginArray(1);
192             Trace::BeginElement();
193             Trace::LiteralOpaque((const void*)apiPtr.value());
194             Trace::EndElement();
195             Trace::EndArray();
196         } else if (type == enumType) {
197             ApiEnum apiEnum = var.value<ApiEnum>();
198             Trace::EnumSig *sig = createEnumSig(apiEnum, ++id);
199             Trace::LiteralEnum(sig);
200             deleteEnumSig(sig);
201         } else {
202             qWarning()<<"Unsupported write variant : "
203                       << QMetaType::typeName(type);
204         }
205     }
206
207     Trace::EndArg();
208 }
209
210
211 SaverThread::SaverThread(QObject *parent)
212     : QThread(parent)
213 {
214 }
215
216 void SaverThread::saveFile(const QString &fileName,
217                            const QList<ApiTraceCall*> &calls)
218 {
219     m_fileName = fileName;
220     m_calls = calls;
221     start();
222 }
223
224 void SaverThread::run()
225 {
226     qputenv("TRACE_PATH", m_fileName.toLocal8Bit());
227     unsigned id = 0;
228
229     Trace::Open();
230     for (int i = 0; i < m_calls.count(); ++i) {
231         ApiTraceCall *call = m_calls[i];
232         Trace::FunctionSig *funcSig = createFunctionSig(call, ++id);
233         unsigned callNo = BeginEnter(*funcSig);
234         {
235             //args
236             QVariantList vars = call->arguments();
237             foreach(QVariant var, vars) {
238                 writeArgument(var, ++id);
239             }
240         }
241         Trace::EndEnter();
242         Trace::BeginLeave(callNo);
243         {
244             QVariant ret = call->returnValue();
245             if (!ret.isNull()) {
246                 Trace::BeginReturn();
247                 writeArgument(ret, ++id);
248                 Trace::EndReturn();
249             }
250         }
251         Trace::EndLeave();
252
253         deleteFunctionSig(funcSig);
254     }
255     Trace::Close();
256
257     emit traceSaved(m_fileName);
258 }
259
260 #include "saverthread.moc"