46 lines
1.8 KiB
C++
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
|