freepdfeditor/spike/A_verbatim_roundtrip/Roundtrip.h

46 lines
1.8 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors
//
// Roundtrip — the core of Spike A. Given a PDF on disk, open it with QPDF,
// ask QPDF to write it back to a fresh file with the same structure, and
// report whether the round-trip is byte-identical. Per the plan §14 step 4:
//
// "Spike A: QPDF-based open → parse content streams → re-emit verbatim → save.
// Measure byte-identical round-trip rate over 500 corpus files. Target ≥ 99%."
//
// The "parse content streams" step is what later spikes build on; here we walk
// every page's content stream(s) through QPDF's stream decoder/encoder and
// verify the object graph is structurally preserved, which is the precondition
// for the surgical re-emission in §4.4 to be lossless.
#ifndef FREEPDFEDITOR_SPIKE_A_ROUNDTRIP_H
#define FREEPDFEDITOR_SPIKE_A_ROUNDTRIP_H
#include <cstddef>
#include <filesystem>
#include <string>
namespace freepdfeditor::spike::a {
enum class Outcome {
ByteIdentical, // input == output byte-for-byte
StructurallySame, // QPDF wrote a different byte stream with identical semantics
Failed, // could not open / could not write
};
struct FileResult {
Outcome outcome;
std::size_t pages = 0;
std::string error; // populated when outcome == Failed
};
// Round-trip `input` through QPDF, writing to `output`. `output` must not
// already exist. Walks every page's content stream(s) via
// qpdf_objecthandle to prove the parse path is exercised, then writes the
// document back preserving object order.
FileResult roundtrip(const std::filesystem::path& input,
const std::filesystem::path& output);
} // namespace freepdfeditor::spike::a
#endif // FREEPDFEDITOR_SPIKE_A_ROUNDTRIP_H