// 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 #include #include 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