Skip to content

Commit 71befc3

Browse files
committed
Add RAW query, test runtime path, and EXIF recovery
Adds conservative RAW-processing queries and plumbing, a CTest runtime-library path option, improved EXIF/TIFF recovery, and C2PA trusted-chain enforcement. Details: - API: metadata_query.h: new MetadataQueryKind::RawProcessing, several Raw-related semantic kinds and match terms, and query_raw_processing_metadata(). - Validation: validate.h adds verify_require_trusted_chain to opt-in trusted certificate-chain enforcement for draft C2PA verification; CLI/docs updated to document the option. - Build/tests: CMake adds OPENMETA_TEST_RUNTIME_LIBRARY_PATH and openmeta_apply_test_runtime_environment() to prepend LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATH for CTest-launched external tools; README and docs updated. - Container scan: implement scan_exif_preamble_tiff and use it in scan_auto to recover standalone EXIF/TIFF when a short non-TIFF or malformed-JPEG prefix precedes an Exif preamble. - JUMBF/C2PA: jumbf_decode enhancements to collect detached-payload candidates from nested/numeric claim references and better handle malformed COSE/claim shapes. - Cleanup: removed several unused Nikon MakerNote helper functions and minor formatting fixes across sources and many documentation updates to reflect the new behaviors and transfer-safety refinements. Purpose: enable safer RAW-processing inspection, let tests run external tools with non-default C++ runtimes, improve robustness recovering EXIF payloads in weird inputs, and provide opt-in stricter C2PA verification semantics.
1 parent 792e436 commit 71befc3

33 files changed

Lines changed: 1558 additions & 414 deletions

CHANGES.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,19 @@ Changes compared with `0.4.8`.
4747
reduction/forward matrix sets, DNG white-balance vector sets, and
4848
lens-correction table groups. Candidate value-shape labels now include
4949
`vector_set`, `matrix_set`, and `table`.
50+
- Added `query_raw_processing_metadata(...)` plus Python wrappers for
51+
conservative RAW-processing queries covering black/white levels,
52+
linearization tables, CFA/sensor layout, source geometry, and raw-storage
53+
identifiers.
5054
- Python `Document` and `TransferSourceSnapshot` now expose thin wrappers for
5155
the experimental semantic metadata query API, including generic
5256
`metadata_query(kind)` and focused query helpers.
5357

5458
### Changed
5559

60+
- Added `OPENMETA_TEST_RUNTIME_LIBRARY_PATH` so CTest-launched external
61+
validation tools can run with a matching non-default C++ runtime lookup path,
62+
and documented the `libc++` test-prefix workflow.
5663
- Phase One-family IIQ MakerNote detection now recognizes Leaf/Credo-style
5764
files as Phase One MakerNotes before the generic Kodak `IIII` fallback.
5865
- Rendered-image transfer safety now treats Phase One/Leaf RAW sensor geometry,
@@ -66,8 +73,16 @@ Changes compared with `0.4.8`.
6673
computational, thermal, color/WB, geometry/storage, raw-data, sensor,
6774
lens-correction, preview/face geometry, stitch/panorama geometry, or
6875
vendor-private table metadata.
76+
- Rendered-image transfer safety now uses the current DNG tag numbers for
77+
source-bound profile/gain tables, raw digests/storage identifiers,
78+
forward matrices, and opcode/correction lists.
6979
- `metaread` and `python -m openmeta.python.metaread` now print compact Phase
7080
One RAW geometry/processing summaries when those decoded fields are present.
81+
- Draft C2PA verification now exposes opt-in trusted certificate-chain
82+
enforcement through `ValidateOptions`, `metavalidate`, `metadump`, and Python
83+
`read()`/`validate()` wrappers. Without this option, signature status and
84+
chain-trust detail remain separate signals; with it, untrusted or missing
85+
chains fail verification instead of reporting a loose `verified` result.
7186
- `metaread` and `python -m openmeta.python.metaread` now print compact
7287
Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/
7388
Samsung/Ricoh/Apple/DJI/Google/FLIR/Casio/Sanyo/KyoceraRaw/Reconyx/HP/JVC/
@@ -92,6 +107,12 @@ Changes compared with `0.4.8`.
92107

93108
### Fixed
94109

110+
- Fixed standalone EXIF/TIFF recovery when a file has a short non-TIFF prefix
111+
or malformed JPEG prefix before the `Exif` preamble.
112+
- Fixed draft C2PA verification status handling for malformed COSE_Sign1 byte
113+
arrays, unresolved explicit detached-payload references, and nested numeric
114+
claim references with conflicting label/URI fields.
115+
95116
### Tests And Validation
96117

97118
- Added public synthetic coverage for Leaf/Credo IIQ MakerNote detection and
@@ -105,6 +126,8 @@ Changes compared with `0.4.8`.
105126
- Added public synthetic coverage for grouped semantic-query candidates:
106127
DNG color matrix sets, DNG white-balance vector sets, and vendor
107128
lens-correction table groups.
129+
- Added public synthetic coverage for standalone EXIF/TIFF recovery after
130+
unknown-prefix and malformed-JPEG-prefix inputs.
108131
- Added public synthetic coverage for
109132
Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/
110133
Samsung/Ricoh/Apple/DJI/Google/FLIR/Casio/Sanyo/KyoceraRaw/Reconyx/HP/JVC/
@@ -122,8 +145,9 @@ Changes compared with `0.4.8`.
122145
stitch/panorama table entries.
123146
- Added rendered-image writer-output coverage for JPEG, TIFF/DNG, PNG, WebP,
124147
JP2, JXL, HEIF, AVIF, and CR3 metadata rewrites to verify serialized outputs
125-
omit source RAW calibration, vendor private RAW tables, MakerNotes, camera
126-
raw settings XMP, and source JUMBF while preserving safe EXIF/XMP fields.
148+
omit source RAW calibration, raw digests/gain metadata, vendor private RAW
149+
tables, MakerNotes, camera raw settings XMP, and source JUMBF while
150+
preserving safe EXIF/XMP fields.
127151
- Added BMFF transfer coverage for merging metadata into a foreign top-level
128152
`meta` item table that uses `iinf` version 2.
129153
- Added BMFF transfer coverage that verifies multiple foreign top-level `meta`

CMakeLists.txt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ if(NOT OPENMETA_FFMPEG_EXECUTABLE)
9898
endif()
9999
endif()
100100

101+
set(OPENMETA_TEST_RUNTIME_LIBRARY_PATH "" CACHE STRING
102+
"Optional runtime library path prepended to CTest tests that launch external tools")
103+
101104
set(OPENMETA_BMFF_HEIF_TEST_TARGET "" CACHE FILEPATH "Optional existing HEIF/HEIC target image for external transfer usability checks")
102105
set(OPENMETA_BMFF_AVIF_TEST_TARGET "" CACHE FILEPATH "Optional existing AVIF target image for external transfer usability checks")
103106
set(OPENMETA_BMFF_CR3_TEST_TARGET "" CACHE FILEPATH "Optional existing CR3 target image for external transfer usability checks")
@@ -106,6 +109,34 @@ set(_openmeta_bmff_test_target_args
106109
"-DBMFF_AVIF_TEST_TARGET=${OPENMETA_BMFF_AVIF_TEST_TARGET}"
107110
"-DBMFF_CR3_TEST_TARGET=${OPENMETA_BMFF_CR3_TEST_TARGET}")
108111

112+
function(openmeta_apply_test_runtime_environment test_name)
113+
if(NOT OPENMETA_TEST_RUNTIME_LIBRARY_PATH)
114+
return()
115+
endif()
116+
117+
if(WIN32)
118+
set(_openmeta_runtime_var "PATH")
119+
set(_openmeta_runtime_sep ";")
120+
set(_openmeta_runtime_existing "$ENV{PATH}")
121+
elseif(APPLE)
122+
set(_openmeta_runtime_var "DYLD_LIBRARY_PATH")
123+
set(_openmeta_runtime_sep ":")
124+
set(_openmeta_runtime_existing "$ENV{DYLD_LIBRARY_PATH}")
125+
else()
126+
set(_openmeta_runtime_var "LD_LIBRARY_PATH")
127+
set(_openmeta_runtime_sep ":")
128+
set(_openmeta_runtime_existing "$ENV{LD_LIBRARY_PATH}")
129+
endif()
130+
131+
set(_openmeta_runtime_value "${OPENMETA_TEST_RUNTIME_LIBRARY_PATH}")
132+
if(_openmeta_runtime_existing)
133+
set(_openmeta_runtime_value
134+
"${_openmeta_runtime_value}${_openmeta_runtime_sep}${_openmeta_runtime_existing}")
135+
endif()
136+
set_tests_properties(${test_name} PROPERTIES
137+
ENVIRONMENT "${_openmeta_runtime_var}=${_openmeta_runtime_value}")
138+
endfunction()
139+
109140
# Optional path to local dependency repos (used for the FuzzTest wrapper).
110141
# Expected layout:
111142
# <root>/fuzztest
@@ -887,6 +918,13 @@ if(OPENMETA_BUILD_TESTS)
887918
-P "${CMAKE_CURRENT_SOURCE_DIR}/tests/python_metatransfer_edit_smoke_test.cmake"
888919
)
889920
endif()
921+
922+
if(OPENMETA_TEST_RUNTIME_LIBRARY_PATH)
923+
get_property(_openmeta_test_names DIRECTORY PROPERTY TESTS)
924+
foreach(_openmeta_test_name IN LISTS _openmeta_test_names)
925+
openmeta_apply_test_runtime_environment("${_openmeta_test_name}")
926+
endforeach()
927+
endif()
890928
endif()
891929

892930
if(OPENMETA_BUILD_FUZZERS)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ Useful options:
259259
- `-DOPENMETA_BUILD_FUZZERS=ON` for Clang + libFuzzer targets
260260
- `-DOPENMETA_USE_LIBCXX=ON` when linking against dependencies built with
261261
`libc++`
262+
- `-DOPENMETA_TEST_RUNTIME_LIBRARY_PATH=/path/to/runtime-libs` when CTest
263+
launches external tools that need a non-default C++ runtime lookup path
262264
- `-DOPENMETA_WITH_DNG_SDK_ADAPTER=ON` to enable the optional Adobe DNG SDK
263265
bridge (requires a discoverable `dng_sdk` package; intentionally excluded
264266
from public GitHub Actions CI)

docs/api_stability.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ different status.
2222
| Generic metadata traversal: `visit_metadata(...)`, `MetadataSink`, `ExportOptions`, `ExportItem` | `openmeta/interop_export.h` | Stable | v1 traversal contract. Borrowed names are valid only during `MetadataSink::on_item(...)`. |
2323
| `ExportNameStyle::Canonical` and `ExportNameStyle::XmpPortable` | `openmeta/interop_export.h` | Stable | Stable naming modes for key-space-aware and portable exports. |
2424
| `ExportNameStyle::FlatHost` | `openmeta/interop_export.h` | Stable | Stable v1 flat host naming contract. See [flat_host_mapping.md](flat_host_mapping.md). |
25-
| Semantic metadata query: `query_metadata(...)`, `query_crop_metadata(...)`, and focused query helpers | `openmeta/metadata_query.h` | Experimental | Query contract for inspection matches plus normalized candidates. Current coverage includes crop/active-area, exposure/gain, white balance, color, lens correction, and orientation metadata across standard tags, selected DNG tags, fuzzy XMP paths, and vendor RAW-processing classification, including grouped `matrix_set`, `vector_set`, and `table` candidates for related non-crop metadata. Python `Document` and `TransferSourceSnapshot` mirror this as thin dictionary-returning wrappers. |
25+
| Semantic metadata query: `query_metadata(...)`, `query_crop_metadata(...)`, and focused query helpers | `openmeta/metadata_query.h` | Experimental | Query contract for inspection matches plus normalized candidates. Current coverage includes crop/active-area, exposure/gain, white balance, color, lens correction, orientation, and RAW-processing metadata across standard tags, selected DNG tags, fuzzy XMP paths, and vendor RAW-processing classification. Grouped candidates include `matrix_set`, `vector_set`, and `table` shapes for related non-crop metadata, including RAW black/white levels, linearization, CFA/sensor layout, source geometry, and raw-storage identifiers. Python `Document` and `TransferSourceSnapshot` mirror this as thin dictionary-returning wrappers. |
2626
| Vendor RAW-processing summaries: `vendor_raw_processing_from_store(...)`, `classify_vendor_raw_processing_field(...)` | `openmeta/vendor_raw_processing.h` | Experimental | Conservative grouped source-RAW/source-processing field summaries for decoded Sony, Canon, Nikon, Fujifilm, Pentax, Panasonic, Olympus, Kodak, Minolta, Sigma, Samsung, Ricoh, Apple, DJI, Google, FLIR, Casio, Sanyo, KyoceraRaw, Reconyx, HP, JVC, GE, Motorola, Nintendo, and Microsoft MakerNotes, including vendor-private, computational, thermal, preview, face-geometry, and stitch/panorama buckets. Intended for audit/UI and rendered-transfer safety decisions, not for writing vendor RAW/source-processing values into rendered targets. |
2727
| Transfer safety audit: `transfer_safety_audit_from_store(...)` | `openmeta/metadata_transfer.h` | Experimental | Preflight summary of source entries and entries filtered or invalidated by `TransferSafetyMode`, including Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/Samsung/Ricoh/Apple/DJI/Google/FLIR/Casio/Sanyo/KyoceraRaw/Reconyx/HP/JVC/GE/Motorola/Nintendo/Microsoft RAW/source-processing buckets. Intended for diagnostics and host UI before preparing rendered-image transfers. |
2828
| Source snapshot type and read helpers: `TransferSourceSnapshot`, `read_transfer_source_snapshot_file(...)`, `read_transfer_source_snapshot_bytes(...)`, `build_transfer_source_snapshot(...)` | `openmeta/metadata_transfer.h` | Experimental | Current snapshots are decoded-store-backed and do not preserve raw source packets for passthrough. Const reuse is safe when callers do not mutate the snapshot and do not share returned result objects across writers. |

docs/development.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ model should stay compact:
1717
| --- | --- | --- |
1818
| Decoding | Find metadata carriers and decode EXIF, XMP, IPTC, ICC, Photoshop IRB, JUMBF/C2PA, EXR, and related blocks into `MetaStore` entries. | High, about 90-95% for the current target scope. |
1919
| Interpretation | Normalize names and values, group entries by meaning, and classify source-bound data such as RAW crop, color, lens-correction, sensor, and vendor-private fields. | Medium-high, about 75-85%. |
20-
| Query | Find entries by name, fuzzy term, or semantic group, for example crop/border/active-area fields or exposure/gain fields across standard and vendor metadata. | Low, about 15-20%. |
20+
| Query | Find entries by name, fuzzy term, or semantic group, for example crop/border/active-area, exposure/gain, color/WB, orientation, lens-correction, and RAW-processing fields across standard and vendor metadata. | Low, about 20-25%. |
2121
| Creation | Build fresh metadata entries from host-provided values. | Medium, about 55-65%. |
2222
| Editing | Modify existing logical metadata entries while preserving valid surrounding structure. | Medium, about 60-70%. |
2323
| Transfer | Move metadata between files using explicit compatible-file or rendered-image safety policies. | Medium-high, about 80-85%. |
@@ -35,15 +35,18 @@ rather than hiding ambiguity behind a single value.
3535

3636
The first experimental C++ query surface is `openmeta/metadata_query.h`.
3737
It returns both raw matches and normalized candidates for crop/active-area,
38-
exposure/gain, white balance, color, lens correction, and orientation queries.
38+
exposure/gain, white balance, color, lens correction, orientation, and
39+
RAW-processing queries.
3940
Crop queries include DNG crop tags, `ActiveArea`, Phase One/Leaf raw geometry,
4041
and fuzzy crop/border-style XMP property paths. The non-crop queries expose
4142
per-entry value candidates and reuse standard tag names, selected DNG tags,
4243
fuzzy XMP paths, and vendor RAW-processing classification where applicable.
4344
They also append grouped candidates for related DNG color matrix/calibration/
4445
reduction/forward matrix tags, DNG white-balance vector tags, and
45-
lens-correction table groups, using `matrix_set`, `vector_set`, and `table`
46-
value shapes.
46+
lens-correction table groups. RAW-processing queries add conservative groups
47+
for black/white levels, linearization tables, CFA/sensor layout, source
48+
geometry, and raw-storage identifiers. Grouped candidates use `matrix_set`,
49+
`vector_set`, and `table` value shapes.
4750
Python `Document` and `TransferSourceSnapshot` mirror this as thin wrappers
4851
returning the same match/candidate dictionary shape.
4952

@@ -75,7 +78,10 @@ dependencies let OpenMeta decode more content:
7578
`OPENMETA_C2PA_VERIFY_BACKEND`): enables backend selection/reporting fields
7679
(`none|auto|native|openssl`) and draft verification flow. Native backend
7780
availability is platform-based (Windows/macOS), while OpenSSL availability
78-
is discovered via `find_package(OpenSSL)` when needed.
81+
is discovered via `find_package(OpenSSL)` when needed. By default this
82+
reports cryptographic signature status and trust-chain detail separately;
83+
use `--c2pa-verify-require-trusted-chain` when validation must fail for an
84+
untrusted or missing certificate chain.
7985

8086
If you link against dependencies that were built with `libc++` (common when
8187
using Clang), configure OpenMeta with:
@@ -84,6 +90,15 @@ using Clang), configure OpenMeta with:
8490
-DOPENMETA_USE_LIBCXX=ON
8591
```
8692

93+
When CTest launches external validation tools from the same dependency prefix,
94+
those tools must also be able to find their matching C++ runtime libraries. If
95+
the runtime is not discoverable through the system loader, pass an explicit
96+
runtime directory:
97+
98+
```bash
99+
-DOPENMETA_TEST_RUNTIME_LIBRARY_PATH=/path/to/runtime-libs
100+
```
101+
87102
## Versioning
88103

89104
`VERSION` is the single source of truth for the project version:
@@ -106,6 +121,9 @@ using Clang), configure OpenMeta with:
106121

107122
#Validate with sidecar + MakerNotes + C2PA verify status
108123
./build/metavalidate --xmp-sidecar --makernotes --c2pa-verify input.jpg
124+
125+
#Require C2PA signature verification and a trusted certificate chain
126+
./build/metavalidate --c2pa-verify --c2pa-verify-require-trusted-chain input.jpg
109127
```
110128
`metavalidate` CLI is a thin wrapper over `openmeta::validate_file(...)`.
111129
Machine-readable JSON output includes issue codes suitable for gating, for
@@ -126,6 +144,9 @@ example `xmp/output_truncated` and `xmp/invalid_or_malformed_xml_text`.
126144
#Portable sidecar + draft C2PA verify scaffold status reporting
127145
./build/metadump --format portable --c2pa-verify --c2pa-verify-backend auto input.jpg output.xmp
128146

147+
#Portable sidecar with trusted-chain C2PA verification required
148+
./build/metadump --format portable --c2pa-verify --c2pa-verify-require-trusted-chain input.jpg output.xmp
149+
129150
#Explicit input / output form
130151
./build/metadump -i input.jpg -o output.xmp
131152

@@ -723,6 +744,11 @@ This policy surface is intentionally marked draft and may be refined.
723744
`verification_failed`) when a signature entry provides algorithm +
724745
signing input + public key material (`public_key_der`/`public_key_pem` or
725746
`certificate_der`).
747+
- opt-in trusted-chain enforcement via
748+
`verify_require_trusted_chain` /
749+
`--c2pa-verify-require-trusted-chain`; without this option, signature
750+
verification and certificate-chain trust are reported as separate
751+
signals.
726752
- COSE_Sign1 support (array or embedded CBOR byte-string forms): extracts
727753
`alg` from protected headers, reconstructs Sig_structure signing bytes
728754
when payload is present, extracts `x5chain` from unprotected headers, and
@@ -806,6 +832,11 @@ Note: if your GoogleTest was built against `libc++` (common with Clang),
806832
build OpenMeta against the same C++ standard library. Otherwise you may see
807833
link errors involving `std::__1` vs `std::__cxx11`.
808834

835+
If external test tools were built with `libc++` and need a custom runtime
836+
lookup path, set `OPENMETA_TEST_RUNTIME_LIBRARY_PATH` at configure time. This
837+
is applied to CTest-launched tests through `LD_LIBRARY_PATH` on Linux and
838+
`DYLD_LIBRARY_PATH` on macOS.
839+
809840
Build + run:
810841
```bash
811842
cmake -S . -B build-tests -G Ninja -DCMAKE_BUILD_TYPE=Debug \

docs/host_integration.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ Use the narrowest public API that matches your host:
3030
| Existing target file or template | `execute_prepared_transfer_file(...)` + `persist_prepared_transfer_file_result(...)` |
3131
| EXR writer | `build_exr_attribute_batch_from_file(...)` |
3232
| Host-owned metadata object model | `visit_metadata(...)` |
33+
| Host metadata inspection/search UI | `openmeta/metadata_query.h` focused query helpers |
3334
| JPEG/JXL/WebP/PNG/JP2/BMFF encoder path | `prepare_metadata_for_target_file(...)` + adapter view or backend emitter |
3435
| Adobe DNG SDK objects/files | `dng_sdk_adapter.h` |
3536

36-
There is no public fuzzy-search API yet. Query through exact keys and build
37-
your own display or search layer on top.
37+
For inspection/search UI, prefer the experimental semantic query helpers before
38+
building a separate fuzzy layer. They report source entries, confidence, value
39+
shape, and normalized candidates while preserving ambiguity.
3840

3941
## Adapter Classes
4042

@@ -430,7 +432,7 @@ Use `TransferProfile::safety` for the broad source/destination relationship:
430432
| Mode | Use when | Transfer policy |
431433
| --- | --- | --- |
432434
| `CompatibleFile` | Metadata is repackaged or recompressed into a compatible file/pixel representation | Preserve source camera, color, ICC, and camera-specific data except target-owned image-layout fields |
433-
| `RenderedImage` | Pixels may have changed, especially RAW-to-JPEG/PNG/WebP/JXL/HEIF/AVIF export | Keep general/time/GPS/IPTC/portable XMP; drop source raw color calibration, linearization/crop/correction metadata, vendor RAW/source-processing geometry/color/correction/thermal/computational/private/stitch fields, camera raw settings XMP, source ICC, opaque MakerNotes, and non-C2PA JUMBF |
435+
| `RenderedImage` | Pixels may have changed, especially RAW-to-JPEG/PNG/WebP/JXL/HEIF/AVIF export | Keep general/time/GPS/IPTC/portable XMP; drop source raw color calibration, profile/gain tables, raw digests/storage identifiers, linearization/crop/correction metadata, vendor RAW/source-processing geometry/color/correction/thermal/computational/private/stitch fields, camera raw settings XMP, source ICC, opaque MakerNotes, and non-C2PA JUMBF |
434436

435437
See [writer_target_contract.md](writer_target_contract.md#transfer-safety-matrix)
436438
for the detailed per-group transfer matrix.

0 commit comments

Comments
 (0)