blob: ad8f48a67c3d4927c8bbcc390bb808ddf1134a98 [file] [log] [blame]
#include "saverthread.h"
#include "trace_writer.hpp"
#include "trace_model.hpp"
#include "trace_parser.hpp"
#include <QFile>
#include <QHash>
#include <QUrl>
#include <QDebug>
#if 0
static trace::FunctionSig *
createFunctionSig(ApiTraceCall *call, unsigned id)
{
trace::FunctionSig *sig = new trace::FunctionSig();
sig->id = id;
sig->name = qstrdup(call->name().toLocal8Bit());
QStringList args = call->argNames();
sig->num_args = args.count();
sig->arg_names = new const char*[args.count()];
for (int i = 0; i < args.count(); ++i) {
sig->arg_names[i] = qstrdup(args[i].toLocal8Bit());
}
return sig;
}
static void
deleteFunctionSig(trace::FunctionSig *sig)
{
for (int i = 0; i < sig->num_args; ++i) {
delete [] sig->arg_names[i];
}
delete [] sig->arg_names;
delete [] sig->name;
delete sig;
}
static trace::StructSig *
createStructSig(const ApiStruct &str, unsigned id)
{
ApiStruct::Signature aSig = str.signature();
trace::StructSig *sig = new trace::StructSig();
sig->id = id;
sig->name = qstrdup(aSig.name.toLocal8Bit());
sig->num_members = aSig.memberNames.count();
char **member_names = new char*[aSig.memberNames.count()];
sig->member_names = (const char **)member_names;
for (int i = 0; i < aSig.memberNames.count(); ++i) {
member_names[i] = qstrdup(aSig.memberNames[i].toLocal8Bit());
}
return sig;
}
static void
deleteStructSig(trace::StructSig *sig)
{
for (int i = 0; i < sig->num_members; ++i) {
delete [] sig->member_names[i];
}
delete [] sig->member_names;
delete [] sig->name;
delete sig;
}
static trace::EnumSig *
createEnumSig(const ApiEnum &en, unsigned id)
{
trace::EnumSig *sig = new trace::EnumSig();
sig->id = id;
sig->name = qstrdup(en.name().toLocal8Bit());
sig->value = en.value().toLongLong();
return sig;
}
static void
deleteEnumSig(trace::EnumSig *sig)
{
delete [] sig->name;
delete sig;
}
static trace::BitmaskSig *
createBitmaskSig(const ApiBitmask &bt, unsigned id)
{
ApiBitmask::Signature bsig = bt.signature();
ApiBitmask::Signature::const_iterator itr;
trace::BitmaskSig *sig = new trace::BitmaskSig();
trace::BitmaskFlag *flags = new trace::BitmaskFlag[bsig.count()];
sig->id = id;
sig->num_flags = bsig.count();
sig->flags = flags;
int i = 0;
for (itr = bsig.constBegin(); itr != bsig.constEnd(); ++itr, ++i) {
flags[i].name = qstrdup(itr->first.toLocal8Bit());
flags[i].value = itr->second;
}
return sig;
}
static void
deleteBitmaskSig(trace::BitmaskSig *sig)
{
for (int i = 0; i < sig->num_flags; ++i) {
delete [] sig->flags[i].name;
}
delete [] sig->flags;
delete sig;
}
static void
writeValue(trace::Writer &writer, const QVariant &var, unsigned &id)
{
int arrayType = QMetaType::type("ApiArray");
int bitmaskType = QMetaType::type("ApiBitmask");
int structType = QMetaType::type("ApiStruct");
int pointerType = QMetaType::type("ApiPointer");
int enumType = QMetaType::type("ApiEnum");
int type = var.userType();
switch(type) {
case QVariant::Bool:
writer.writeBool(var.toBool());
break;
case QVariant::ByteArray: {
QByteArray ba = var.toByteArray();
writer.writeBlob((const void*)ba.constData(), ba.size());
}
break;
case QVariant::Double:
writer.writeDouble(var.toDouble());
break;
case QMetaType::Float:
writer.writeFloat(var.toFloat());
break;
case QVariant::Int:
writer.writeSInt(var.toInt());
break;
case QVariant::LongLong:
writer.writeSInt(var.toLongLong());
break;
case QVariant::String: {
QString str = var.toString();
writer.writeString(str.toLocal8Bit().constData(), str.length());
}
break;
case QVariant::UInt:
writer.writeUInt(var.toInt());
break;
case QVariant::ULongLong:
writer.writeUInt(var.toLongLong());
break;
default:
if (type == arrayType) {
ApiArray array = var.value<ApiArray>();
QVector<QVariant> vals = array.values();
writer.beginArray(vals.count());
foreach(QVariant el, vals) {
writer.beginElement();
writeValue(writer, el, ++id);
writer.endElement();
}
writer.endArray();
} else if (type == bitmaskType) {
ApiBitmask bm = var.value<ApiBitmask>();
trace::BitmaskSig *sig = createBitmaskSig(bm, ++id);
writer.writeBitmask(sig, bm.value());
deleteBitmaskSig(sig);
} else if (type == structType) {
ApiStruct apiStr = var.value<ApiStruct>();
QList<QVariant> vals = apiStr.values();
trace::StructSig *str = createStructSig(apiStr, ++id);
writer.beginStruct(str);
foreach(QVariant val, vals) {
writeValue(writer, val, ++id);
}
writer.endStruct();
deleteStructSig(str);
} else if (type == pointerType) {
ApiPointer apiPtr = var.value<ApiPointer>();
writer.writePointer(apiPtr.value());
} else if (type == enumType) {
ApiEnum apiEnum = var.value<ApiEnum>();
trace::EnumSig *sig = createEnumSig(apiEnum, ++id);
writer.writeEnum(sig);
deleteEnumSig(sig);
} else {
qWarning()<<"Unsupported write variant : "
<< QMetaType::typeName(type);
}
}
}
#endif
class EditVisitor : public trace::Visitor
{
public:
EditVisitor(const QVariant &variant)
: m_variant(variant),
m_editedValue(0)
{}
virtual void visit(trace::Null *val) override
{
m_editedValue = val;
}
virtual void visit(trace::Bool *node) override
{
// Q_ASSERT(m_variant.userType() == QVariant::Bool);
bool var = m_variant.toBool();
m_editedValue = new trace::Bool(var);
}
virtual void visit(trace::SInt *node) override
{
// Q_ASSERT(m_variant.userType() == QVariant::Int);
m_editedValue = new trace::SInt(m_variant.toInt());
}
virtual void visit(trace::UInt *node) override
{
// Q_ASSERT(m_variant.userType() == QVariant::UInt);
m_editedValue = new trace::SInt(m_variant.toUInt());
}
virtual void visit(trace::Float *node) override
{
m_editedValue = new trace::Float(m_variant.toFloat());
}
virtual void visit(trace::Double *node) override
{
m_editedValue = new trace::Double(m_variant.toDouble());
}
virtual void visit(trace::String *node) override
{
QString str = m_variant.toString();
char *newString = new char[str.length() + 1];
QByteArray ba = str.toLocal8Bit();
strcpy(newString, ba.constData());
m_editedValue = new trace::String(newString);
}
virtual void visit(trace::WString *node) override
{
QString str = m_variant.toString();
size_t len = str.length();
wchar_t *newString = new wchar_t[len + 1];
str.toWCharArray(newString);
newString[len] = 0;
m_editedValue = new trace::WString(newString);
}
virtual void visit(trace::Enum *e) override
{
m_editedValue = e;
}
virtual void visit(trace::Bitmask *bitmask) override
{
m_editedValue = bitmask;
}
virtual void visit(trace::Struct *str) override
{
m_editedValue = str;
}
virtual void visit(trace::Array *array) override
{
ApiArray apiArray = m_variant.value<ApiArray>();
QVector<QVariant> vals = apiArray.values();
trace::Array *newArray = new trace::Array(vals.count());
for (int i = 0; i < vals.count(); ++i) {
EditVisitor visitor(vals[i]);
array->values[i]->visit(visitor);
if (array->values[i] == visitor.value()) {
//non-editabled
delete newArray;
m_editedValue = array;
return;
}
newArray->values[i] = visitor.value();
}
m_editedValue = newArray;
}
virtual void visit(trace::Blob *blob) override
{
m_editedValue = blob;
}
virtual void visit(trace::Pointer *ptr) override
{
m_editedValue = ptr;
}
trace::Value *value() const
{
return m_editedValue;
}
private:
QVariant m_variant;
trace::Value *m_editedValue;
};
static void
overwriteValue(trace::Call *call, const QVariant &val, int index)
{
EditVisitor visitor(val);
trace::Value *origValue = call->args[index].value;
origValue->visit(visitor);
if (visitor.value() && origValue != visitor.value()) {
delete origValue;
call->args[index].value = visitor.value();
}
}
SaverThread::SaverThread(QObject *parent)
: QThread(parent)
{
}
void SaverThread::saveFile(const QString &writeFileName,
const QString &readFileName,
const QSet<ApiTraceCall*> &editedCalls)
{
m_writeFileName = writeFileName;
m_readFileName = readFileName;
m_editedCalls = editedCalls;
start();
}
void SaverThread::run()
{
qDebug() << "Saving " << m_readFileName
<< ", to " << m_writeFileName;
QMap<int, ApiTraceCall*> callIndexMap;
foreach(ApiTraceCall *call, m_editedCalls) {
callIndexMap.insert(call->index(), call);
}
trace::Parser parser;
parser.open(m_readFileName.toLocal8Bit());
trace::Writer writer;
writer.open(m_writeFileName.toLocal8Bit(), parser.getVersion(), parser.getProperties());
trace::Call *call;
while ((call = parser.parse_call())) {
if (callIndexMap.contains(call->no)) {
QVector<QVariant> values = callIndexMap[call->no]->editedValues();
for (int i = 0; i < values.count(); ++i) {
const QVariant &val = values[i];
overwriteValue(call, val, i);
}
writer.writeCall(call);
} else {
writer.writeCall(call);
}
delete call;
}
writer.close();
emit traceSaved();
}
#include "saverthread.moc"