Skip to content

fix(makernotes): honour ExifTool's Priority, so a sub-directory copy stops overwriting the Main tag - #414

Merged
swackhamer merged 1 commit into
mainfrom
fix/tag-priority-subdirectory
Aug 2, 2026
Merged

fix(makernotes): honour ExifTool's Priority, so a sub-directory copy stops overwriting the Main tag#414
swackhamer merged 1 commit into
mainfrom
fix/tag-priority-subdirectory

Conversation

@swackhamer

Copy link
Copy Markdown
Collaborator

Five corpus files carry the same Pentax tag twice — once in %Pentax::Main, once inside a binary sub-directory — and oxidex printed the sub-directory copy. That is the worst shape a defect can take here: a real ExifTool tag name carrying the wrong value, with nothing downstream able to tell.

file tag before after (= ExifTool)
Pentax/PentaxK100D.jpg LensType M-42 or No Lens smc PENTAX-DA 21mm F3.2 AL Limited
Pentax/PentaxK-50.jpg LensType M-42 or No Lens Sigma
Pentax/PentaxK-5II.jpg LensType K or M Lens Sigma
Pentax/PentaxOptioSVi.jpg PentaxModelID Optio SV Optio SVi
Pentax/PentaxOptioL20.jpg PentaxModelID Optio S7 Optio L20

How ExifTool actually decides this

FoundTag (ExifTool.pm:9448) reads the tag's priority at :9469-9473 — the tag's own Priority, else the table's PRIORITY, else 0 when the tag is Avoid — and on a duplicate name compares it against the priority already recorded (:9564).

Two details make the rule. A 0-priority value records no entry in PRIORITY (:9589 stores it "only if exists and is non-zero"), and a missing entry is promoted to 1 (:9545-9551, whose comment reads "promote existing 0-priority tag so it takes precedence over a new 0-tag"). So:

first second winner
normal Priority => 0 first — 0 >= 1 is false
Priority => 0 normal second — old promoted to 1, 1 >= 1 holds
Priority => 0 Priority => 0 first — old promoted to 1, 0 >= 1 is false
normal normal second — 1 >= 1 holds

Which composes, for any number of instances in any order, to exactly two rules:

  • a Priority => 0 value never displaces a value already present;
  • a normal-priority value always displaces whatever is present.

The second is what a plain HashMap::insert already does, so only the first needed writing: shared::tag_priority::insert_low_priority.

Why the values looked like data

%Pentax::LensRec and %Pentax::LensInfo* are both Priority => 0 (Pentax.pm:4202, :4248), so the winner is decided by first-found, not by a priority difference — and 0 0 is a real lens id (M-42 or No Lens), not a null. %Pentax::CameraInfo carries ExifTool's own reason on the line: "(Optio SVi uses incorrect Optio SV ID here)" (Pentax.pm:4723).

General, not a special case

The generated sub-directory decoder carries the flag too, so this is fixed for every vendor's tables rather than for Pentax alone. codegen_subdirs.py listed Priority among the keys that "do not change what a reader produces" — which is how it went missing. It now reads Priority/Avoid, honours a table-level PRIORITY, and refuses any priority value it does not model rather than silently treating it as normal.

Regenerating the three affected table files from ExifTool 13.55 (the version they were generated from) reproduces them byte-for-byte apart from the added flag, and all 155 fields come out low_priority: false — no generated table is affected today, so that half is prevention, not behaviour change.

Measurement

1227 files (Pentax, Panasonic, FujiFilm, corpus root), 105,708 compared Group1:Name pairs, scored per file against ExifTool 13.59:

5 fixed, 0 regressed.

Mutation-tested three ways — reverting the helper to insert, reverting both Pentax call sites, and reverting only the CameraInfo site — each makes the new tests fail with the exact reported wrong values.

just test green (4,374 passed). cargo clippy clean on the touched files.

Exposure beyond this PR

Across the whole 4,238-file corpus, 856 (file, Group1:Name) pairs have duplicate instances whose values differ; 244 have a Priority => 0 loser. 39 of those have the loser in a table oxidex has transcribed — all in src/exiftool_tables/binary_tables.rs, which is reference data whose Field struct carries no priority. Those are latent, not live: oxidex has a single writer for each today (Nikon:ISO from Nikon::Main, Canon:Sharpness from Canon::CameraSettings), so they are correct now but would break the moment those tables get wired up.

🤖 Generated with Claude Code

@swackhamer
swackhamer enabled auto-merge (squash) August 2, 2026 04:20
…stops overwriting the Main tag

Five corpus files carry the same Pentax tag twice -- once in `%Pentax::Main`
and once inside a binary sub-directory -- and oxidex printed the sub-directory
copy. That is the worst shape a defect can take here: a real ExifTool tag name
carrying the wrong value, with nothing downstream able to tell.

  Pentax/PentaxK100D.jpg     LensType       M-42 or No Lens -> smc PENTAX-DA 21mm F3.2 AL Limited
  Pentax/PentaxK-50.jpg      LensType       M-42 or No Lens -> Sigma
  Pentax/PentaxK-5II.jpg     LensType       K or M Lens     -> Sigma
  Pentax/PentaxOptioSVi.jpg  PentaxModelID  Optio SV        -> Optio SVi
  Pentax/PentaxOptioL20.jpg  PentaxModelID  Optio S7        -> Optio L20

ExifTool decides this with `Priority`. `FoundTag` (ExifTool.pm:9448) reads it at
:9469-9473, and on a duplicate name compares against the priority already
recorded (:9564). Two details make the rule: a 0-priority value records no
entry in `PRIORITY` (:9589 stores it "only if exists and is non-zero"), and a
missing entry is promoted to 1 (:9545-9551, "promote existing 0-priority tag so
it takes precedence over a new 0-tag"). Those compose to exactly two rules --
a `Priority => 0` value never displaces a value already present, and a
normal-priority value always displaces whatever is present. The second is what
a plain `HashMap::insert` already does, so only the first needed writing:
`shared::tag_priority::insert_low_priority`.

`%Pentax::LensRec` and `%Pentax::LensInfo*` are BOTH `Priority => 0`
(Pentax.pm:4202, :4248), so the winner is decided by first-found, not by a
priority difference -- and `0 0` is a real lens id ("M-42 or No Lens"), not a
null, which is why the clobber looked like data. `%Pentax::CameraInfo` carries
ExifTool's own reason on the line: "(Optio SVi uses incorrect Optio SV ID
here)" (Pentax.pm:4723).

The generated sub-directory decoder now carries the flag too, so this is fixed
for every vendor's tables rather than for Pentax alone. `codegen_subdirs.py`
had `Priority` in the list of keys that "do not change what a reader produces",
which is how it went missing; it now reads `Priority`/`Avoid`, honours a
table-level `PRIORITY`, and refuses any priority value it does not model rather
than silently treating it as normal. Regenerating the three affected table
files from ExifTool 13.55 reproduces them byte-for-byte apart from the added
flag, and all 155 fields are `low_priority: false` -- no generated table is
affected today, so the codegen change is prevention, not behaviour.

Measured over 1227 files (Pentax, Panasonic, FujiFilm and the corpus root),
105708 compared Group1:Name pairs: 5 fixed, 0 regressed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@swackhamer
swackhamer force-pushed the fix/tag-priority-subdirectory branch from 05b0354 to 9d981d4 Compare August 2, 2026 09:07
@swackhamer
swackhamer merged commit df90b9b into main Aug 2, 2026
6 of 7 checks passed
@swackhamer
swackhamer deleted the fix/tag-priority-subdirectory branch August 2, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant