Introduce operation journaling to track how values are read from the binary stream, enabling future write-back of edited fields. New components: - OperationJournal: Records read operations with stream offsets, sizes, byte order, and original values during parsing - ReverseEval: Analyzes expressions for invertibility (e.g., x+5 can be reversed to compute the source field when editing the result) - Recompiler: Infrastructure for recompiling modified values back to binary format Interpreter enhancements: - Add runTypeInternalWithJournal() for journaled parsing - Journal scalar reads, byte reads, strings, skip/seek operations - Add deadrising_lzx() built-in for Dead Rising 2 LZX decompression - Support _deadrising_lzx_stem context variable for nested archives Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
94 lines
3.4 KiB
C++
94 lines
3.4 KiB
C++
#ifndef INTERPRETER_H
|
|
#define INTERPRETER_H
|
|
|
|
#include "ast.h"
|
|
|
|
#include <QDataStream>
|
|
#include <QVariantMap>
|
|
#include <QIODevice>
|
|
#include <functional>
|
|
|
|
struct Runtime {
|
|
QDataStream* in = nullptr;
|
|
Module* module = nullptr; // Non-const to allow modifying globals
|
|
|
|
ByteOrder order = ByteOrder::LE;
|
|
QVariantMap vars;
|
|
|
|
QString filePath;
|
|
|
|
// Error context tracking
|
|
QStringList typeStack; // Stack of types being parsed
|
|
QString currentType() const { return typeStack.isEmpty() ? QString() : typeStack.last(); }
|
|
void pushType(const QString& t) { typeStack.append(t); }
|
|
void popType() { if (!typeStack.isEmpty()) typeStack.removeLast(); }
|
|
QString typeStackString() const { return typeStack.join(" -> "); }
|
|
|
|
// Write-back journal tracking
|
|
int journalId = -1; // Current journal being built (-1 = disabled)
|
|
bool journalEnabled = true; // Can disable for criteria checks
|
|
};
|
|
|
|
using ProgressCallback = std::function<void(qint64 pos, qint64 size)>;
|
|
using StatusCallback = std::function<void(const QString& status)>;
|
|
|
|
class Interpreter {
|
|
public:
|
|
explicit Interpreter(Module mod);
|
|
|
|
// Parse a given type name from a device/stream
|
|
QVariantMap runType(const QString& typeName, QIODevice* dev, const QString& filePath = QString()) const;
|
|
|
|
// Run from existing QDataStream (for nested parse)
|
|
QVariantMap runType(const QString& typeName, QDataStream& stream, const QString &filePath = QString()) const;
|
|
|
|
// Check if the criteria for a certain filetype matches
|
|
bool checkCriteria(const QString& typeName, QIODevice* dev, const QString filePath) const;
|
|
|
|
QVariantMap runTypeInternal(const QString& typeName,
|
|
QDataStream& stream,
|
|
const QString& filePath,
|
|
std::optional<ByteOrder> inheritedOrder) const;
|
|
|
|
// Version that accepts a journal ID for nested parsing
|
|
QVariantMap runTypeInternalWithJournal(const QString& typeName,
|
|
QDataStream& stream,
|
|
const QString& filePath,
|
|
std::optional<ByteOrder> inheritedOrder,
|
|
int journalId) const;
|
|
|
|
static void seedFileVars(Runtime &rt, const QString &filePath);
|
|
|
|
// Progress reporting
|
|
void setProgressCallback(ProgressCallback cb);
|
|
void setStatusCallback(StatusCallback cb);
|
|
void setFileSize(qint64 size);
|
|
|
|
private:
|
|
QVariant evalExpr(Runtime& rt, const Expr& e) const;
|
|
QVariant evalCall(Runtime& rt, const Expr::Call& c) const;
|
|
QVariant evalPipe(Runtime& rt, const Expr::Pipe& p) const;
|
|
|
|
void execStmt(Runtime& rt, const Stmt& s) const;
|
|
void execBlock(Runtime& rt, const QVector<StmtPtr>& body) const;
|
|
|
|
// helpers
|
|
void applyByteOrder(Runtime& rt) const;
|
|
QVariant readScalar(Runtime& rt, ScalarType t) const;
|
|
QByteArray readBytes(Runtime& rt, qint64 n) const;
|
|
QByteArray readEOF(Runtime& rt) const;
|
|
|
|
qint64 toInt(const QVariant& v) const;
|
|
bool toBool(const QVariant& v) const;
|
|
void reportProgress(Runtime& rt) const;
|
|
void reportStatus(const QString& status) const;
|
|
|
|
private:
|
|
mutable Module m_mod;
|
|
mutable ProgressCallback m_progressCallback;
|
|
mutable StatusCallback m_statusCallback;
|
|
mutable qint64 m_fileSize = 0; // Mutable to allow modifying globals from const methods
|
|
};
|
|
|
|
#endif // INTERPRETER_H
|