Repository navigation
feat: Add a PDF asset_io hander - #7
Merged
Merged
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Decode compact xref streams and resolve compressed objects on demand - Lazily retrieve Flate-compressed XMP and C2PA payloads - Enforce input, output, and cumulative decompression limits - Support PNG predictors and narrowly scoped legacy xref termination - Add malformed-input, decompression-limit, and large-file tests - Document supported features and report absent metadata in inspect Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ners
This commit combines two related changes:
1. Refactor SegmentMetadata into opaque, cloneable typed attachments
- Keep container-specific metadata types in their own handlers.
- Preserve JPEG extended XMP and thumbnail behavior.
- Provide safe typed access without new dependencies or payload copies.
2. Add bounded incremental PDF XMP and C2PA updates
- Stream the original bytes unchanged and append metadata revisions.
- Preserve unrelated catalog values and attachments.
- Support exact-length, uncompressed payload finalization.
- Allow unsigned AcroForms while rejecting populated signature fields,
certification restrictions, XFA, and unsupported attachment trees.
- Preflight edits and safely replace destination paths on success.
Add regression tests and PDF write fuzz assertions, and document supported
behavior, resource limits, and logical-removal semantics in PDF.md.
main replaced the 0.1 API (Asset, per-format *_io modules, MediaType) that this branch was built on. Every conflict is resolved to main's side. The old PDF reader, writer, tests and benchmark are removed from the tree because they cannot compile against the new API; they remain in history (c296806) and are being ported to a ContainerHandler on the new architecture. Kept: PDF.md (design notes, to be updated), the pdf_metadata.pdf fixture, and Error::UnsupportedFeature. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ecode hooks Structure::attachment / StructureBuilder::attach / PlanBuilder::attach keep one opaque value with a structure, for what a container needs later that is not geometry (how a stream is encoded, what a write must know). A write's output structure can carry one too. decode_entity and encode_entity now receive the structure and the entity, so a handler can look up how that entity is stored. SVG is updated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ports the bounded PDF reader from the 0.1 API onto ContainerHandler and Io. A synchronous lexer works on a window of bytes and asks for a larger one when it runs short, so the syntax code has no I/O and no async recursion; the async layer follows the cross-reference chain (classic tables, cross-reference streams, /Prev), resolves objects (including compressed object streams) and finds the current catalog's /Metadata and document-level /AF C2PA store. Streams are segments holding their payload as it is in the file. A Flate compressed store is an entity whose bytes are the encoded ones; Structure::xmp and Structure::store decode it through the handler's decode_entity, using the encoding recorded in the structure's attachment. All limits and refusals from the old reader are kept. The 0.1 read tests are ported (43 tests over synthetic documents, including the exact-limit cases and bounded-I/O checks) and pass unchanged in what they assert. Writing is not ported yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ports the incremental writer. Parsing records what a revision needs (catalog, EmbeddedFiles name tree, trailer, remaining parse budgets, and whether the document can be edited at all) in the structure's attachment; planning is then a pure function of that and the update. A write is the whole source followed by an appended revision, so the plan is a Copy of the source and a handful of Puts. Segments that parsing the output would merge (a superseded metadata stream is just bytes) are merged in the plan, so the output reparses to exactly the planned structure, and the planned structure carries the new editing context so it can be written again without parsing. In-place finalization of an exact-length store uses Structure::patch_exact; a new check_patch hook lets the handler refuse (compressed streams, signed or certified documents, wrong length) before anything is written, and patch_exact now asks it before it complains about the length. Behaviour that differs from the 0.1 writer: a zero-length metadata stream is not exposed (a segment cannot be empty), the temp-file replacement helper and chunk processing options are gone (callers write to any Write; a Sink replaces the processor), and the form/permission/name-tree refusals are unchanged. Tests: the 0.1 write suite is ported (16 tests: combinations, multiple revisions, compressed catalogs, forms and signatures, exact-length patching, exact budget limits, refusals that leave the output untouched), the shared document builders moved into tests/pdf_support, and the conformance kit runs over editable, blocked, compressed, cross-reference-stream, form and multi-revision documents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Io::read_vec panicked for a zero-length read after an earlier read_vec had taken the window. The SVG scan offered a <metadata> inside an xpacket as the place to write a new packet; a packet written there changes where the outer one ends, so the output did not parse to the planned structure. Nothing inside an xpacket is a place to write now. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Handlers now use only the core's public API (crate-root items plus the plan, jumbf and testing modules) and the external crates they own. - Move jumbf from containers/ into the core as asset_io::jumbf. - Make bmff a module directory with its private heif_items helper. - Register built-in handlers through containers::register_builtin, the single place the core reaches into the handlers. - Export MAX_SEGMENT_SIZE and make Structure::entity_list public; handlers read Updates through its accessors instead of pub(crate) fields. - Add tests/container_isolation.rs to enforce these boundaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows the zero copy, near zero dependencies and secure fuzzed model of the other drivers.
This can read and write PDF files with some limitations, such as no support for encrypted PDFs.