#ifndef RECOMPILER_H #define RECOMPILER_H #include "operationjournal.h" #include "../compression/compression.h" #include #include #include #include #include /** * @brief The Recompiler class walks an operation journal and produces binary output. * * Given a journal (recorded during parsing) and a set of modified values, * the Recompiler produces a QByteArray representing the recompiled binary. * * For write-back to work, the journal must be "exportable" (no random access, * no unsupported compression, etc.). */ class Recompiler : public QObject { Q_OBJECT public: explicit Recompiler(QObject* parent = nullptr); /** * @brief Recompile a structure to bytes using journal and values. * @param journalId The journal ID from parsing * @param values The current values (may be modified from original) * @return The recompiled binary data * @throws std::runtime_error if recompilation fails or journal not exportable */ QByteArray recompile(int journalId, const QVariantMap& values); /** * @brief Check if a journal can be recompiled. * @param journalId The journal ID to check * @return true if recompilation is possible */ bool canRecompile(int journalId) const; /** * @brief Get human-readable reason why recompilation is not possible. * @param journalId The journal ID to check * @return Empty string if exportable, otherwise the reason */ QString whyNotRecompilable(int journalId) const; /** * @brief Recompile and return both the bytes and any errors/warnings. * @param journalId The journal ID * @param values The values to use * @param outErrors Output parameter for error messages * @return The recompiled bytes (empty if failed) */ QByteArray recompileWithErrors(int journalId, const QVariantMap& values, QStringList& outErrors); signals: /** * @brief Emitted during recompilation to report progress. * @param percent Progress percentage (0-100) * @param stage Description of current stage */ void progressChanged(int percent, const QString& stage); private: /** * @brief Write a scalar value to the output stream. * @param out Output stream * @param type Scalar type * @param order Byte order * @param value Value to write */ void writeScalar(QDataStream& out, ScalarType type, ByteOrder order, const QVariant& value); /** * @brief Write raw bytes to the output stream. * @param out Output stream * @param data Bytes to write */ void writeBytes(QDataStream& out, const QByteArray& data); /** * @brief Write a null-terminated C string. * @param out Output stream * @param str String to write */ void writeCString(QDataStream& out, const QString& str); /** * @brief Write a null-terminated wide string (UTF-16). * @param out Output stream * @param str String to write * @param order Byte order (LE or BE) */ void writeWString(QDataStream& out, const QString& str, ByteOrder order); /** * @brief Write padding/skip bytes. * @param out Output stream * @param count Number of bytes to skip (writes zeros) * @param originalBytes Original bytes to use (if available) */ void writeSkip(QDataStream& out, qint64 count, const QByteArray& originalBytes = QByteArray()); /** * @brief Get the value for a field, using modified value if present, otherwise original. * @param values Modified values map * @param entry Journal entry with original value * @return The value to use for recompilation */ QVariant getValueForField(const QVariantMap& values, const JournalEntry& entry) const; /** * @brief Recursively recompile a nested structure. * @param nestedJournalId The nested journal ID * @param parentValues Values from parent (may contain nested values) * @param fieldName The field name for the nested structure * @param outErrors Output for error messages * @return The recompiled bytes for the nested structure */ QByteArray recompileNested(int nestedJournalId, const QVariantMap& parentValues, const QString& fieldName, QStringList& outErrors); /** * @brief Extract nested values from parent values map. * @param parentValues The parent values map * @param fieldName The field name for the nested structure * @param nestedJournal The nested journal (to get original values) * @return Values map for the nested structure */ QVariantMap extractNestedValues(const QVariantMap& parentValues, const QString& fieldName, const OperationJournal* nestedJournal) const; /** * @brief Compress data using the specified compression type. * @param data The uncompressed data * @param compressionType The compression algorithm ("zlib", "deflate", "xmem", "oodle") * @param params Algorithm-specific parameters (e.g., compression level, window size) * @return The compressed data */ QByteArray compress(const QByteArray& data, const QString& compressionType, const QByteArray& params = QByteArray()) const; /** * @brief Check if a compression type is supported for write-back. * @param compressionType The compression type name * @return true if compression is supported */ bool isCompressionSupported(const QString& compressionType) const; // Track visited journals to prevent infinite recursion QSet m_visitedJournals; }; #endif // RECOMPILER_H