Skip to content

Commit cecc682

Browse files
chore(release): v1.3.0
- Update CHANGELOG.md for v1.3.0 (promote [Unreleased] to [1.3.0] - 2026-07-07; add missing entries for the XMP array-property round-trip/allowlist fix (#272/#273) and the XMP forbidden-char-ref sanitisation fix (#274)) - Update BENCHMARKS.md and benchmarks/BENCHMARKS.md with a full -bench=. -benchmem -count=3 ./... sweep vs v1.2.0 - Add benchmark results (benchmarks/results/v1.3.0.txt) - Security clearance: R1-R5 CLEARED rounds (security-auditor) cover the v1.2.0..5e76f72 hardening wave; the remaining delta to HEAD (BigTIFF write, IPTC/XMP/EXIF bridging, XMP array-property fixes) was independently verified via code review plus fresh fuzz campaigns (FuzzTIFFInject 2.8M, FuzzTIFFExtract 332K, FuzzParseEXIF 3.3M, FuzzParseXMP 13.4M, FuzzParseIPTC 18.6M execs, 0 crashers) on 2026-07-07
1 parent 433e2e3 commit cecc682

3 files changed

Lines changed: 447 additions & 92 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Ver
66

77
## [Unreleased]
88

9+
## [1.3.0] - 2026-07-07
10+
911
### Added
1012

1113
- **BigTIFF write support, end to end** (`exif/write.go`, `format/tiff/relocate_bigtiff.go`, `write.go`, tasks #264/#270/#271): `exif.Encode` now natively encodes BigTIFF-sourced EXIF (`EXIF.BigTIFF == true`) with a 16-byte header, 20-byte IFD entries, and 64-bit offsets throughout (BigTIFF spec §2, Aware Systems/libtiff); `format/tiff`'s copy-and-relocate serialiser is now container-width-aware end to end (image-block enumeration, `SubIFDs` 0x014A relocation, and every raw-offset scan performed after encoding), so a standalone BigTIFF file relocates correctly on write; and the top-level `Write`/`WriteFile` no longer refuse BigTIFF sources with `ErrWriteNotSupported` — the root-package guard has been removed now that both layers are verified end-to-end against real BigTIFF corpus fixtures (LONG8/SLONG8/IFD8 strip/tile arrays, multi-level SubIFD chains, and the committed `BigTIFF_LE.tif`/`BigTIFF_BE.tif`/`big_cramps_{be,le}.tif` fixtures). Two new sentinel errors guard the encode path: `exif.ErrBigTIFFPointerOverflow` (a sub-IFD or thumbnail pointer — fixed by spec to a 4-byte EXIF LONG field regardless of container — would need an absolute offset that does not fit in 32 bits) and `exif.ErrBigTIFFEncodeSizeExceeded` (the encoded payload would exceed a documented, test-overridable 4 GiB sanity ceiling, since BigTIFF's 64-bit offsets have no implicit `MaxUint32` saturation the way classic TIFF's do). `exif.ErrBigTIFFEncodeNotSupported` is no longer returned by `Encode` under normal conditions and its doc comment now marks it **Deprecated**; it is retained only for API compatibility and may be removed in a future major release. `ErrWriteNotSupported` remains exported for any future format without a write path.
@@ -38,6 +40,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Ver
3840
- **`writeTIFFHeader`/`writeIFD` panicked on a non-standard `binary.ByteOrder`** (#247, PERF-201-LOW): a non-comma-ok type assertion to `binary.AppendByteOrder` (introduced by the byte-order refactor in v1.2.0) panicked for any `binary.ByteOrder` implementation other than the two standard-library singletons. The assertion is now comma-ok with a `PutUint16`/`PutUint32` fallback; the little-/big-endian fast path is unchanged and remains zero-allocation.
3941
- **IPTC `Encode` extended-length overflow**: a `Dataset.Value` longer than the 4-byte extended-length field can represent was silently truncated to its low 32 bits while every value byte was still written, desynchronising the encoded stream. `Encode` now rejects such values with `iptc.ErrDatasetValueTooLarge` (see Added) instead of emitting a wrapped length field.
4042
- **TIFF SubIFD type-13 (`IFD`) misparsed as UTF8** (part of #270): `format/tiff`'s relocator trusted `exif.Parse`'s type-13 decoding for tag `0x014A` (`SubIFDs`), but CIPA DC-008-2023's EXIF-3.0 assignment of `TypeUTF8` to the same numeric code as the legacy TIFF-extension `IFD` type meant a SubIFD pointer array declared as type 13 was silently corrupted or dropped on write. The relocator now re-scans the raw bytes for this tag directly instead of trusting the parsed struct.
43+
- **XMP array-typed property container-type round-trip fidelity, plus Dublin Core allowlist gaps** (#272/#273, `xmp/namespace.go`, `xmp/rdf.go`, `xmp/write.go`, `xmp/xmp.go`): `collectionType`/`isCollectionProperty` were two independently maintained switch statements that had already drifted out of sync, and recognised only 5 of the 11 array-typed `dc:` properties (`creator`, `subject`, `title`, `description`, `rights`); a single-value `Set(NSdc, "contributor", ...)` — and `date`/`language`/`publisher`/`relation`/`type` — previously emitted a bare scalar element instead of the `rdf:Bag`/`rdf:Seq` container required by ISO 16684-1 §7.5. Both switches are now consolidated into one spec-sourced `arrayProperties` table covering all 11 `dc:` properties plus every other array-typed property across `xmpMM`, `xmpRights`, `xmp`, `tiff`, `exif`, `photoshop`, `Iptc4xmpCore`, and `Iptc4xmpExt`. The same consolidation corrects `xmpMM:Ingredients`/`xmpMM:Pantry` — previously wrongly coded as ordered `Seq` — to the spec-correct unordered `Bag` (Adobe XMP Specification Part 2 §1.2.8), and adds the previously-missing `xmpMM:Versions` (`Seq`). More fundamentally, a plain `Parse` → (unrelated field write) → `Encode` round trip previously downgraded *any* array-typed property outside this table's namespace/name coverage to a bare scalar, because the spec table was the sole authority `Encode` consulted — violating this project's "existing metadata is preserved exactly" mandate for every namespace the table does not (and, being finite, never can) enumerate. `XMP` now records the RDF collection kind (`Seq`/`Bag`/`Alt`) actually observed at parse time in a new unexported `containerTypes` map, consulted first on `Encode`, falling back to the spec table only for properties with no parse-time record (i.e. newly `Set()`). As a side effect, this also fixes a single-item `rdf:Alt` property outside the table leaking its internal `"lang|value"` storage separator into the serialised output text.
44+
- **XMP numeric character references admitted XML 1.0 forbidden code points** (#274, `xmp/rdf.go`): `decodeCharRef` accepted any numeric character reference (`&#N;` / `&#xHH;`) whose value was a legal Unicode scalar value, even when that value falls outside the XML 1.0 §2.2 `Char` production — the C0 control block other than TAB/LF/CR, and the two BMP non-characters U+FFFE/U+FFFF. For U+001E specifically — this library's own internal multi-value record separator — a crafted-but-parseable document containing `` could cause `Encode` to spuriously re-serialise a genuinely scalar/Simple property as an `rdf:Bag`. `decodeCharRef` now substitutes U+FFFD for any such forbidden code point, matching the identical policy `writeXMLEscaped` already applies on the output side, so parsing and serialisation are consistent in both directions.
4145
- **BigTIFF write is now fully supported through the public API** (`write.go`, `exif/write.go`, `format/tiff/relocate.go`, `format/tiff/relocate_bigtiff.go`, #264/#270/#271) — see Added for the full description.
4246
- **XMP encoder now always wraps array-typed properties in their RDF collection container** (`xmp/write.go`, `xmp/namespace.go`): `dc:creator`, `dc:subject`, `dc:description`, `dc:rights`, `dc:title`, and the `xmpMM` ordered-array set (`History`, `Ingredients`, `Pantry`) are now serialised as `<rdf:Seq>`/`<rdf:Bag>`/`<rdf:Alt>` even when they hold exactly one value, per ISO 16684-1 §7.5. Previously, a single-item array-typed property (e.g. the common case of `SetCaption`/`SetCreator` writing exactly one value) was serialised as a bare `<prefix:local>value</prefix:local>` element, which is only correct for Simple (Text) properties. Round-trip value correctness (via this library's own lenient parser) was unaffected, but the produced wire format did not conform to the formal Lang-Alt/array schema that other XMP consumers expect.
4347

@@ -58,6 +62,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Ver
5862
- **IPTC extended-length overflow closed** (`iptc.Encode`): a `Dataset.Value` too long for the 4-byte extended-length field to represent was previously truncated silently rather than rejected, which could desynchronise the encoded stream; `Encode` now returns `iptc.ErrDatasetValueTooLarge` (CWE-190).
5963
- **BigTIFF encode size ceiling added** (`exif.ErrBigTIFFEncodeSizeExceeded`): BigTIFF's 64-bit offset fields have no natural saturation ceiling the way classic TIFF's 32-bit fields do; `Encode` now enforces an explicit, documented, test-overridable 4 GiB sanity ceiling on the total encoded size before allocating the output buffer, preventing a pathological `IFDEntry.Count` from directing an unbounded allocation (CWE-400).
6064
- **INFO: `format/jpeg` 256 MiB aggregate size cap added** (#262): JPEG now enforces the same project-wide aggregate input cap as every other container format, closing a defense-in-depth gap — JPEG was the only container package without one. Per-APP-segment lengths were already 16-bit bounded, so this is a normalisation rather than a fix for a known amplification bug.
65+
- **LOW: XMP numeric character references could carry XML 1.0 forbidden code points** (#274): a crafted document containing a numeric character reference to a C0 control code point (other than TAB/LF/CR) or a BMP non-character (U+FFFE/U+FFFF) — including this library's own internal `\x1e` multi-value sentinel byte — was decoded verbatim instead of being replaced, extending the existing C0 control-character filtering (#170/#171) to this parse path. `decodeCharRef` now applies the identical U+FFFD substitution policy already used on the output side (CWE-91).
6166

6267
## [1.2.0] - 2026-06-10
6368

@@ -304,7 +309,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Ver
304309

305310
---
306311

307-
[Unreleased]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.2.0...HEAD
312+
[Unreleased]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.3.0...HEAD
313+
[1.3.0]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.2.0...v1.3.0
308314
[1.2.0]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.1.0...v1.2.0
309315
[1.1.0]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.0.4...v1.1.0
310316
[1.0.4]: https://github.com/FlavioCFOliveira/GoMetadata/compare/v1.0.3...v1.0.4

0 commit comments

Comments
 (0)