|
| 1 | +# FlatHost Mapping Contract |
| 2 | + |
| 3 | +`ExportNameStyle::FlatHost` is the stable v1 naming contract for host-owned |
| 4 | +metadata object models that prefer flat attribute names over OpenMeta's native |
| 5 | +key shapes. |
| 6 | + |
| 7 | +Contract constant: |
| 8 | + |
| 9 | +```cpp |
| 10 | +openmeta::kFlatHostExportContractVersion == 1 |
| 11 | +``` |
| 12 | + |
| 13 | +## Scope |
| 14 | + |
| 15 | +The contract covers names emitted by: |
| 16 | + |
| 17 | +```cpp |
| 18 | +openmeta::visit_metadata(store, options, sink) |
| 19 | +``` |
| 20 | +
|
| 21 | +with: |
| 22 | +
|
| 23 | +```cpp |
| 24 | +options.style = openmeta::ExportNameStyle::FlatHost; |
| 25 | +``` |
| 26 | + |
| 27 | +Python mirrors this name contract through: |
| 28 | + |
| 29 | +```python |
| 30 | +doc.export_names(style=openmeta.ExportNameStyle.FlatHost) |
| 31 | +``` |
| 32 | + |
| 33 | +The C++ traversal exposes `ExportItem::entry`, so C++ hosts can project values |
| 34 | +from the original `Entry::value`. Python `export_names(...)` is name-only. |
| 35 | + |
| 36 | +## Ordering And Duplicates |
| 37 | + |
| 38 | +- Entries are emitted in `MetaStore::entries()` order. |
| 39 | +- Deleted entries are skipped. |
| 40 | +- Duplicate names are preserved and emitted separately. |
| 41 | +- OpenMeta does not merge, reconcile, or suffix duplicate `FlatHost` names. |
| 42 | +- If a host requires unique keys, it must apply its own deterministic collision |
| 43 | + policy after traversal. |
| 44 | + |
| 45 | +## Value Projection |
| 46 | + |
| 47 | +`FlatHost` is a naming contract, not a value-conversion contract. |
| 48 | + |
| 49 | +- C++ receives the original `Entry` through `ExportItem::entry`. |
| 50 | +- `Entry::value.kind`, `elem_type`, `count`, and storage are unchanged. |
| 51 | +- Text encoding remains the original decoded `TextEncoding`. |
| 52 | +- Byte payloads remain byte payloads; unsafe text conversion is not performed |
| 53 | + by `visit_metadata(...)`. |
| 54 | +- Hosts that need a text-only export should use a safe formatting layer on top |
| 55 | + of `Entry::value`. |
| 56 | + |
| 57 | +## Namespace Behavior |
| 58 | + |
| 59 | +`FlatHost` intentionally keeps common camera-style names short while preserving |
| 60 | +namespace prefixes where ambiguity matters. |
| 61 | + |
| 62 | +| Source family | FlatHost rule | |
| 63 | +| --- | --- | |
| 64 | +| TIFF root and preview IFD tags | Use the known tag alias without a prefix, for example `Make`, `ModifyDate`, `ImageWidth`. | |
| 65 | +| EXIF and interoperability IFD tags | Prefix with `Exif:`, for example `Exif:ExposureTime`, `Exif:ISO`, `Exif:CreateDate`. | |
| 66 | +| GPS IFD tags | Prefix with `GPS:`, for example `GPS:GPSLatitude`. | |
| 67 | +| MakerNote IFDs | Emit only when `include_makernotes` is true, using `MakerNote:<ifd>:<tag-name-or-hex>`. | |
| 68 | +| XMP simple properties | Emit selected known namespaces as `XMP:`, `TIFF:`, `Exif:`, or `DC:` plus the simple property name. | |
| 69 | +| ICC header fields and tags | Emit `ICC:<field>` or `ICC:tag:<signature>`. | |
| 70 | +| EXR part 0 known aliases | Map selected standard attributes to common host names, for example `owner -> Copyright`, `capDate -> DateTime`, `expTime -> ExposureTime`. | |
| 71 | +| EXR part 0 unknown attributes | Emit `openexr:<name>`. | |
| 72 | +| EXR non-zero parts | Emit `openexr:part:<index>:<name>`. | |
| 73 | +| Unsupported key families | Fall back to the canonical OpenMeta name when one exists. | |
| 74 | + |
| 75 | +Complex XMP paths are not flattened. XMP properties are emitted only when the |
| 76 | +property path is a simple token containing letters, digits, `_`, or `-`; paths |
| 77 | +with `/`, `[`, `]`, or other punctuation are skipped by `FlatHost`. |
| 78 | + |
| 79 | +## Name Policy |
| 80 | + |
| 81 | +`ExportOptions::name_policy` controls tag aliasing: |
| 82 | + |
| 83 | +- `ExportNamePolicy::ExifToolAlias` is the default and uses OpenMeta's |
| 84 | + ExifTool-compatible aliases where OpenMeta has a clean-room mapping. |
| 85 | +- `ExportNamePolicy::Spec` preserves native/spec-style tag names where |
| 86 | + available and uses `Tag_0x....` for unknown EXIF tags. |
| 87 | + |
| 88 | +The policy does not change ordering, duplicate preservation, or value |
| 89 | +projection. |
| 90 | + |
| 91 | +## Filtering |
| 92 | + |
| 93 | +`FlatHost` skips: |
| 94 | + |
| 95 | +- deleted entries |
| 96 | +- EXIF pointer tags under the default alias policy |
| 97 | +- embedded metadata blob tags such as EXIF-stored XMP, ICC, IPTC, Photoshop |
| 98 | + IRB, and MakerNote blob tags under the default alias policy |
| 99 | +- MakerNote IFDs when `include_makernotes` is false |
| 100 | +- complex XMP paths and unknown XMP namespaces |
| 101 | +- selected structural EXR header attributes that are not useful as host |
| 102 | + metadata attributes, such as `channels`, `compression`, and data windows |
| 103 | + |
| 104 | +## Stability |
| 105 | + |
| 106 | +This is a stable v1 naming contract. Future OpenMeta releases may add mappings |
| 107 | +for newly decoded metadata families, but existing v1 names should not change |
| 108 | +without a new contract version or a documented compatibility path. |
0 commit comments