docs/gaps.md, docs/parity-checklist.md, docs/whats-new.md: both sides kept; the PR's sentences added to main's rows and entries.
docs/xmp-interop.md: capture-time paragraph combines both sides.
The PR's test file crates/engine/src/tests_import.rs landed in crates/engine/src/tests/import.rs (moved on main).
crates/meta/src/xmp.rs: kept main's 'mod tests;'; the PR's two tests ported to xmp/tests.rs.
docs/gaps.md, docs/parity-checklist.md, docs/whats-new.md: both sides kept; newer date in headers; XMP row and header carry the PR's sentence.
- tag 0x0001 is CameraSettings (numeric LensType at index 22), not an ASCII name; real EOS 5D files never carry a lens name there
- read the lens name from 0x0095 (LensModel) and yield none when only the numeric LensType exists
- fixture now builds a representative maker note (CameraSettings table + LensType 178) and covers both byte orders plus the nameless case
LightCraft already fills a missing lens_model from the Panasonic and Nikon maker notes in try_read_exif, but never from the Canon maker note, so Canon bodies such as the EOS 5D that omit EXIF LensModel cannot match any lens profile even when the maker note records the lens.
Add a canon_maker_note_lens fallback in try_read_exif, parsed with lightcraft_tiff::makernote::parse_makernote (Canon notes are the Plain kind), mirroring panasonic_maker_note_lens; add a unit test in exif.rs that feeds an Exif block with a Canon maker note but no LensModel and asserts lens_model is populated.
Test: canon_maker_note_lens_fills_lens_model failed before the change and passes after.
Resolve the conflict in the crates/meta/src/lib.rs doc comment: list
both PSD/PSB (from main) and HEIF/HEIC/AVIF (from this branch).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An oversized CR3 candidate is skipped without ending the search, repeated child IFD references count once toward the pending cap, deflated chunks lay their rows out as the unpacker reads them (16-bit words, 32-bit word alignment), the tile grid's nominal size is checked against the image before anything is decoded, chunk grouping saturates, and the XMP flattened-key budget is document-wide. The JPEG-header test now parses a real header.
XMP flattening, sparse-focus EXIF decode (plus the maker-note and TIFF value
budgets), lossy-DNG chunk staging, panorama stitch frames, the reference ONNX
executor's tensors and the denoise product reader all now reject or cap what a
malformed file can make them allocate: each result is checked before the
memory behind it is reserved, every regression carrying a test that fails
without its bound.
Found while testing crates/meta/src/iptc.rs:8 (decode)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/meta/src/xmp.rs:184 (entity); the same pattern is in crates/lensdb/src/xml.rs:45 and crates/engine/src/preset_luminar.rs:90
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Conflicts:
- apps/lightcraft/src/native_menu.rs: upstream's item swapping (macOS keys
given up for real, Help menu not swapped, Settings / Quit tracked) with
KEY-GRID's keymap-aware rows. `Item.label` stays the text the row shows
(native_item_presentation), so `Item::native_label` reuses it instead of
formatting it again; Settings / Quit store theirs through
display_item_label, as upstream's native_label did. No early return after
a rebuild (upstream).
- crates/ui-egui/src/i18n.rs: upstream's tests (#2729: one test per check
across languages, gaps reported, never a failure) plus the batch's two new
ones (dropped-photos notice, Polish counts); production code as merged.
- grid.rs, keyword_list.rs, masking.rs: the translation tests #2729 removed
stay removed; the batch's new keyword and segmenter tests stay.
- cmd/library.rs, ui-egui/src/lib.rs: both test modules, each with its
#[cfg(test)].
- xtask/src/main.rs: #2302's test_selected and upstream's translation_gaps.
- docs: tracker / gap rows take both sides' edits, headers list both sides'
changes, history rows of both sides newest-first. What's New: one section
per date, newest first (the batch had 10-22 above 10-23, and second 10-21
and 10-19 sections); no line lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tag panel writes a list as its first 16 values and a count (`list`), but RATIONAL and
SRATIONAL arrays were formatted and joined whole, so a tag holding millions of fractions
became a string as long. They now go through the same cap (`list_with`, which formats only
the values it shows). Item 7 of #2579.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DateTime deserializes with public fields, so its offset can arrive without passing
valid(). `i16::MIN.abs()` overflows: a panic in debug builds and a negative minute count
in release, which to_iso() then printed. valid() and to_iso() use unsigned_abs().
Item 4 of #2579.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/meta/src/exif.rs:462 (write_exif; compare the reader in from_tiff at crates/meta/src/exif.rs:96-107)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/meta/src/exif.rs:483 (write_exif, the `r` helper; via lightcraft_tiff::writer::rational at crates/tiff/src/writer.rs:261)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>