blob: 47a03a1c2e2fb44453aa4e0f35ca92dba0785f75 [file] [log] [blame]
Zack Rusinc6247dd2011-04-17 22:56:58 -04001#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
12static Trace::FunctionSig *
13createFunctionSig(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
30static void
31deleteFunctionSig(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
41static Trace::StructSig *
42createStructSig(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
58static void
59deleteStructSig(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
69static Trace::EnumSig *
70createEnumSig(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
81static void
82deleteEnumSig(Trace::EnumSig *sig)
83{
84 delete [] sig->name;
85 delete sig;
86}
87
88static Trace::BitmaskSig *
89createBitmaskSig(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
110static void
111deleteBitmaskSig(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
120static void
121writeArgument(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 switch(type) {
131 case QVariant::Bool:
132 case QVariant::ByteArray:
133 case QVariant::Double:
134 case QVariant::Int:
135 case QVariant::LongLong:
136 case QVariant::String:
137 case QVariant::UInt:
138 case QVariant::ULongLong:
139 default:
140 if (type == arrayType) {
141 ApiArray array = var.value<ApiArray>();
142 QList<QVariant> vals = array.values();
143 Trace::BeginArray(vals.count());
144 foreach(QVariant el, vals) {
145 Trace::BeginElement();
146 writeArgument(el, ++id);
147 Trace::EndElement();
148 }
149 Trace::EndArray();
150 } else if (type == bitmaskType) {
151 ApiBitmask bm = var.value<ApiBitmask>();
152 Trace::BitmaskSig *sig = createBitmaskSig(bm, ++id);
153 LiteralBitmask(*sig, bm.value());
154 deleteBitmaskSig(sig);
155 } else if (type == structType) {
156 ApiStruct apiStr = var.value<ApiStruct>();
157 QList<QVariant> vals = apiStr.values();
158 Trace::StructSig *str = createStructSig(apiStr, ++id);
159 Trace::BeginStruct(str);
160 foreach(QVariant val, vals) {
161 writeArgument(val, ++id);
162 }
163 Trace::EndStruct();
164 deleteStructSig(str);
165 } else if (type == pointerType) {
166 ApiPointer apiPtr = var.value<ApiPointer>();
167 Trace::BeginArray(1);
168 Trace::BeginElement();
169 Trace::LiteralOpaque((const void*)apiPtr.value());
170 Trace::EndElement();
171 Trace::EndArray();
172 } else if (type == enumType) {
173 ApiEnum apiEnum = var.value<ApiEnum>();
174 Trace::EnumSig *sig = createEnumSig(apiEnum, ++id);
175 Trace::LiteralEnum(sig);
176 deleteEnumSig(sig);
177 } else if (type == QVariant::ByteArray) {
Zack Rusinf4dd5792011-04-17 23:00:15 -0400178 QByteArray ba = var.toByteArray();
179 Trace::LiteralBlob((const void*)ba.constData(), ba.size());
Zack Rusinc6247dd2011-04-17 22:56:58 -0400180 } else {
181 qWarning()<<"Unsupported write variant : "
182 << QMetaType::typeName(type);
183 }
184 }
185
186}
187
188
189SaverThread::SaverThread(QObject *parent)
190 : QThread(parent)
191{
192}
193
194void SaverThread::saveFile(const QString &fileName,
195 const QList<ApiTraceCall*> &calls)
196{
197 m_fileName = fileName;
198 m_calls = calls;
199 start();
200}
201
202void SaverThread::run()
203{
204
205 Trace::Open();
206 unsigned id = 0;
207
208 for (int i = 0; i < m_calls.count(); ++i) {
209 ApiTraceCall *call = m_calls[i];
210 Trace::FunctionSig *funcSig = createFunctionSig(call, ++id);
211 unsigned callNo = BeginEnter(*funcSig);
212 {
213 //args
214 QVariantList vars = call->arguments();
215 foreach(QVariant var, vars) {
216 writeArgument(var, id);
217 }
218 }
219 Trace::EndEnter();
220 Trace::BeginLeave(callNo);
221 {
222 QVariant ret = call->returnValue();
223 if (!ret.isNull()) {
224 Trace::BeginReturn();
225 writeArgument(ret, id);
226 Trace::EndReturn();
227 }
228 }
229 Trace::EndLeave();
230
231 deleteFunctionSig(funcSig);
232 }
233
234 Trace::Close();
235
236 emit traceSaved(m_fileName);
237}
238
239#include "saverthread.moc"