Skip to content

Commit 815a493

Browse files
committed
Support 32-bit BMFF item IDs for iloc v2
Add bounded 32-bit item-id insertion for BMFF targets that use iloc v2 while preserving 16-bit behavior for iloc v0/1. Expand metadata_transfer to use 32-bit item_id storage/allocation, emit infe v3 when wider IDs are needed, and select iref version/id-widths appropriately (with safe failure when ID space is exhausted). Fix container scanning to read iinf version 1 entry counts as 32-bit. Update iloc/infe/iref read/write paths to honor input id-widths and avoid truncation, and adjust casts where needed. Add unit tests exercising iloc v2 targets with high item IDs and update multiple docs (CHANGES, development, metadata backend/plan, writer target contract) to document the new behavior and limits.
1 parent 5a1e605 commit 815a493

8 files changed

Lines changed: 244 additions & 39 deletions

docs/development.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,14 @@ Current v1 behavior is:
321321
merge, replace, or strip bounded Exif/XMP/JUMBF/C2PA items by extending
322322
`iinf`, `iloc`, `idat`, and `iref` with `cdsc` references to the primary
323323
item. This path requires a single parseable `iinf`, `iloc` version
324-
0/1/2, `pitm`, and at most one `idat`. Bounded ICC transfer removes
325-
prior ICC `colr/prof` and `colr/rICC` properties from `iprp/ipco`,
326-
compacts/remaps existing `ipma` associations, appends the transferred
327-
`colr/prof` property, and associates it with the primary item.
328-
Arbitrary BMFF scene/property graph rewrite remains unsupported.
324+
0/1/2, `pitm`, and at most one `idat`. Inserted item IDs follow the
325+
existing `iloc` item-id width: `iloc` version 0/1 stays 16-bit, while
326+
`iloc` version 2 can use 32-bit item IDs and emits wider `infe`/`iref`
327+
records when needed. Bounded ICC transfer removes prior ICC `colr/prof`
328+
and `colr/rICC` properties from `iprp/ipco`, compacts/remaps existing
329+
`ipma` associations, appends the transferred `colr/prof` property, and
330+
associates it with the primary item. Arbitrary BMFF scene/property graph
331+
rewrite remains unsupported.
329332
- CLI/Python `metatransfer` wrappers expose both BMFF summaries and this
330333
bounded edit path; `--target-heif`, `--target-avif`, and `--target-cr3`
331334
now accept `--source-meta PATH` plus `--output PATH` for metadata

docs/metadata_backend_matrix.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ For the public per-target preserve/replace guarantees, see
153153
Exif/XMP/JUMBF/C2PA metadata items by extending `iinf`, `iloc`, `idat`, and
154154
`iref` with `cdsc` references to the primary item. It requires a single
155155
parseable `iinf`, `iloc` version 0/1/2, `pitm`, and at most one `idat`.
156+
Inserted item IDs follow the existing `iloc` item-id width: `iloc` version 0/1
157+
remains a 16-bit insertion path, while `iloc` version 2 can use 32-bit item IDs
158+
and emits wider `infe`/`iref` records when needed.
156159
- Foreign-`meta` ICC property merge is bounded to
157160
`bmff:property-colr-icc`. OpenMeta removes prior ICC `colr/prof` and
158161
`colr/rICC` properties from `iprp/ipco`, compacts/remaps existing `ipma`

docs/metadata_transfer_plan.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ The first public write-side sync controls are also in place:
5555
| WebP | Bounded but real | Prepared bundle, compiled emit, bounded chunk rewrite/edit, file-helper roundtrip | Not a general WebP chunk editor |
5656
| JP2 | Bounded but real | Prepared bundle, compiled emit, bounded box rewrite/edit, file-helper roundtrip | `jp2h` synthesis is still out of scope |
5757
| JXL | Bounded but real | Prepared bundle, compiled emit, bounded box rewrite/edit, file-helper roundtrip | Still narrower than JPEG/TIFF |
58-
| HEIF / AVIF / CR3 | Bounded but real | Prepared bundle, compiled emit, OpenMeta-managed BMFF item/property edit, constrained foreign-`meta` item merge/replacement/strip plus bounded ICC property merge, file-helper roundtrip | Not broad BMFF writer parity; arbitrary foreign `meta` scene/property-graph rewrite is still unsupported |
58+
| HEIF / AVIF / CR3 | Bounded but real | Prepared bundle, compiled emit, OpenMeta-managed BMFF item/property edit, constrained foreign-`meta` item merge/replacement/strip plus bounded ICC property merge, file-helper roundtrip | Not broad BMFF writer parity; arbitrary foreign `meta` scene/property-graph rewrite is still unsupported; 32-bit inserted item IDs require existing `iloc` v2 |
5959
| EXR | Bounded but real | Prepared bundle, compiled emit, direct backend attribute emit, prepared-bundle to `ExrAdapterBatch` bridge, CLI/Python transfer surface | No file rewrite/edit path yet; current transfer payload is safe string attributes only |
6060

6161
## What Is Already Implemented
@@ -304,6 +304,9 @@ Implemented as a bounded BMFF target family:
304304
- constrained foreign top-level `meta` item merge for parseable `iinf`,
305305
`iloc` version 0/1/2, `pitm`, optional single `idat`, and primary-item `cdsc`
306306
references
307+
- bounded 32-bit item-id insertion for foreign item graphs that already use
308+
`iloc` version 2; `iloc` version 0/1 targets remain constrained to 16-bit
309+
inserted item IDs
307310
- bounded foreign top-level `meta` ICC property merge by replacing prior ICC
308311
`colr/prof` and `colr/rICC` properties, remapping `ipma`, and associating the
309312
transferred `colr/prof` property with the primary item
@@ -785,7 +788,13 @@ parity across every workflow.
785788
- [x] lock explicit unmanaged-metadata preservation rules for unrelated chunks, boxes, items, and tails per target family
786789
- [x] add compare-backed read-back gates for each first-class target instead of relying mainly on API-shape regression coverage
787790
- [x] make CLI and Python surfaces describe the same writeback behavior and path-derivation rules as the C++ helper
788-
- [ ] reduce remaining target differences to documented limits instead of accidental implementation details
791+
- [x] reduce remaining target differences to documented limits instead of accidental implementation details
792+
793+
Evidence: `docs/writer_target_contract.md` defines per-target preserve/replace
794+
rules and the remaining bounded limits. The BMFF section now makes the item-id
795+
width rule explicit: `iloc` version 0/1 insertion remains 16-bit, while `iloc`
796+
version 2 can use 32-bit item IDs and fails safely when the graph shape or ID
797+
space is outside that contract.
789798

790799
#### 2. Bounded EXIF / IPTC / XMP Sync Layer
791800

@@ -810,7 +819,13 @@ embedded/sidecar writeback across the primary writer target family.
810819
- [x] cover embedded-only, sidecar-only, and dual-write XMP flows in release-facing compare validation
811820
- [x] add compare-backed validation for explicit sidecar-base overrides and destination-sidecar cleanup behavior
812821
- [x] gate the primary writer family on deterministic read-back of managed metadata after edit/apply
813-
- [ ] keep public parity claims tied to compare-backed evidence instead of only unit or smoke coverage
822+
- [x] keep public parity claims tied to compare-backed evidence instead of only unit or smoke coverage
823+
824+
Evidence: this plan keeps parity language at the supported-lane level and ties
825+
release claims to `openmeta_gate_transfer_release`, compatibility-dump
826+
read-back, and image-usability gates. BMFF high-item-ID insertion is covered by
827+
a release-gated API roundtrip that writes into an `iloc` v2 graph and scans the
828+
result back as one Exif item and one XMP item.
814829

815830
#### 4. TIFF / DNG Deeper Rewrite Guarantees
816831

@@ -830,9 +845,9 @@ embedded-versus-sidecar precedence, and `DNGVersion` read-back.
830845

831846
#### Done-When Readout
832847

833-
- [ ] the first-class target family has one explicit public writer contract
834-
- [ ] the bounded sync-policy layer is documented and regression-gated
835-
- [ ] release-facing compare validation covers the main still-image writer set
848+
- [x] the first-class target family has one explicit public writer contract
849+
- [x] the bounded sync-policy layer is documented and regression-gated
850+
- [x] release-facing compare validation covers the main still-image writer set
836851
- [x] `TIFF/DNG` rewrite guarantees are strong enough to stop being a primary parity blocker
837852
- [x] the next work slice can move to bounded `BMFF` depth instead of still backfilling the writer baseline
838853

docs/sphinx/writer_target_contract.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ Target Summary
111111
in parseable foreign top-level ``meta`` graphs by extending
112112
``iinf``/``iloc``/``idat``/``iref``; replace prior ICC ``colr``
113113
properties and remap ``iprp``/``ipco``/``ipma`` for bounded ICC.
114-
- Does not rewrite arbitrary BMFF scene/property graphs.
114+
- Does not rewrite arbitrary BMFF scene/property graphs; 32-bit item-id
115+
insertion requires existing ``iloc`` v2.
115116
* - ``EXR``
116117
- safe string header attributes through the EXR transfer emitter or
117118
adapter batch
@@ -258,12 +259,18 @@ item graphs it merges, replaces, or strips bounded Exif/XMP/JUMBF/C2PA
258259
metadata items in the existing ``meta`` by extending ``iinf``, ``iloc``,
259260
``idat``, and ``iref`` with ``cdsc`` references to the primary item. This
260261
constrained merge requires a single parseable ``iinf``, ``iloc`` version
261-
0/1/2, ``pitm``, and at most one ``idat``. For bounded ICC transfer,
262-
OpenMeta removes prior ICC ``colr/prof`` and ``colr/rICC`` properties from
263-
``iprp/ipco``, compacts/remaps existing ``ipma`` associations, appends the
264-
transferred ``colr/prof`` property, and associates it with the primary item.
265-
Arbitrary non-ICC property replacement and broader BMFF scene/property graph
266-
rewriting remain out of scope.
262+
0/1/2, ``pitm``, and at most one ``idat``. For ``iloc`` version 0/1 targets,
263+
inserted item IDs remain in the 16-bit item-id space. For ``iloc`` version 2
264+
targets, OpenMeta can allocate 32-bit item IDs and uses ``infe`` version 3 plus
265+
``iref`` version 1 when a newly inserted item needs that wider ID space. If the
266+
existing graph has exhausted the usable item-id space or mixes item-table widths
267+
outside this shape, the edit fails instead of truncating IDs.
268+
269+
For bounded ICC transfer, OpenMeta removes prior ICC ``colr/prof`` and
270+
``colr/rICC`` properties from ``iprp/ipco``, compacts/remaps existing ``ipma``
271+
associations, appends the transferred ``colr/prof`` property, and associates it
272+
with the primary item. Arbitrary non-ICC property replacement and broader BMFF
273+
scene/property graph rewriting remain out of scope.
267274

268275
If sidecar-only writeback asks to strip embedded XMP, OpenMeta can remove XMP
269276
from its own OpenMeta-authored metadata ``meta`` box and from parseable

docs/writer_target_contract.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ integration checks.
5959
| `WebP` | `EXIF`, XMP RIFF chunk, `ICCP`, bounded `C2PA` | Replace matching managed RIFF chunks; preserve unrelated chunks; patch `VP8X` feature bits | EXIF/XMP/ICC edits require an existing `VP8X` chunk |
6060
| `JP2` | top-level `Exif`, top-level XMP `xml` box, `jp2h/colr` ICC | Replace matching top-level metadata boxes; rewrite `jp2h` only to replace/insert `colr`; preserve unrelated boxes and unrelated `jp2h` children | Does not synthesize `jp2h`; requires one existing `jp2h` for ICC |
6161
| `JXL` | top-level `Exif`, XMP `xml` box, `jumb`, `c2pa` | Replace matching top-level boxes; preserve signature and non-managed boxes; classify `jumb` as generic JUMBF or C2PA | ICC is encoder handoff only; file edit emits uncompressed prepared metadata boxes |
62-
| `HEIF` / `AVIF` / `CR3` | BMFF metadata items (`Exif`, XMP `mime`, JUMBF/C2PA), bounded `colr/prof` ICC properties, plus OpenMeta-authored metadata-only `meta` boxes | Preserve non-`meta` top-level boxes; replace prior OpenMeta-authored metadata `meta`; merge/replace/strip item metadata in parseable foreign top-level `meta` graphs by extending `iinf`/`iloc`/`idat`/`iref`; replace prior ICC `colr` properties and remap `iprp`/`ipco`/`ipma` for bounded ICC | Does not rewrite arbitrary BMFF scene/property graphs |
62+
| `HEIF` / `AVIF` / `CR3` | BMFF metadata items (`Exif`, XMP `mime`, JUMBF/C2PA), bounded `colr/prof` ICC properties, plus OpenMeta-authored metadata-only `meta` boxes | Preserve non-`meta` top-level boxes; replace prior OpenMeta-authored metadata `meta`; merge/replace/strip item metadata in parseable foreign top-level `meta` graphs by extending `iinf`/`iloc`/`idat`/`iref`; replace prior ICC `colr` properties and remap `iprp`/`ipco`/`ipma` for bounded ICC | Does not rewrite arbitrary BMFF scene/property graphs; 32-bit item-id insertion requires existing `iloc` v2 |
6363
| `EXR` | safe string header attributes through the EXR transfer emitter or adapter batch | No file rewrite contract today; host applies prepared attributes through its own EXR writer | Attribute-emitter target, not a file edit path |
6464

6565
## JPEG
@@ -192,6 +192,12 @@ graphs it merges, replaces, or strips bounded Exif/XMP/JUMBF/C2PA metadata
192192
items in the existing `meta` by extending `iinf`, `iloc`, `idat`, and `iref`
193193
with `cdsc` references to the primary item. This constrained merge requires a
194194
single parseable `iinf`, `iloc` version 0/1/2, `pitm`, and at most one `idat`.
195+
For `iloc` version 0/1 targets, inserted item IDs remain in the 16-bit item-id
196+
space. For `iloc` version 2 targets, OpenMeta can allocate 32-bit item IDs and
197+
uses `infe` version 3 plus `iref` version 1 when a newly inserted item needs
198+
that wider ID space. If the existing graph has exhausted the usable item-id
199+
space or mixes item-table widths outside this shape, the edit fails instead of
200+
truncating IDs.
195201
For bounded ICC transfer, OpenMeta removes prior ICC `colr/prof` and
196202
`colr/rICC` properties from `iprp/ipco`, compacts/remaps existing `ipma`
197203
associations, appends the transferred `colr/prof` property, and associates it

src/openmeta/container_scan.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,20 +2111,22 @@ namespace {
21112111
uint64_t p = payload_off + 4;
21122112

21132113
uint32_t entry_count = 0;
2114-
if (version < 2) {
2114+
if (version == 0) {
21152115
uint16_t ec16 = 0;
21162116
if (!read_u16be(bytes, p, &ec16)) {
21172117
return false;
21182118
}
21192119
entry_count = ec16;
21202120
p += 2;
2121-
} else {
2121+
} else if (version == 1 || version == 2) {
21222122
uint32_t ec32 = 0;
21232123
if (!read_u32be(bytes, p, &ec32)) {
21242124
return false;
21252125
}
21262126
entry_count = ec32;
21272127
p += 4;
2128+
} else {
2129+
return false;
21282130
}
21292131

21302132
const uint32_t kMaxEntries = 4096;

0 commit comments

Comments
 (0)