Skip to content

gamut-png: the iCCP profile name gets none of the keyword's §11.3.2.3 checks #619

Description

@justin13888

gamut-png polices a text chunk's keyword against §11.3.3.1 and reports every deviation
through MetadataNotice. The iCCP profile name has, word for word, the same rules — and
gets none of that machinery. §11.3.2.3:

Profile name — 1-79 bytes (character string) … Profile names shall contain only printable
Latin-1 characters and spaces (only code points 0x20-7E and 0xA1-FF are allowed). Leading,
trailing, and consecutive spaces are not permitted.

Compare §11.3.3.1's keyword clause, which keyword_verdict in crates/gamut-png/src/ancillary.rs
implements: same repertoire, same 1–79 bytes, same spacing prohibition. The writer, by contrast,
is three lines in Ancillary::write_pre_plte:

let mut data = name.clone().into_bytes();
data.push(0); // null separator

String::into_bytes is UTF-8, and nothing checks length, emptiness or an embedded null.

Executed

Encoding a 2×2 RGB image with PngEncoder::with_icc_profile(name, profile) and reading the
output back with gamut_png::metadata, on fix/483-png-metadata-preservation:

Profile name Read back as Notices
œrofile (U+0153) Å\u{93}rofile — mojibake, the UTF-8 pair C5 93 read as two Latin-1 bytes none
"" (empty) profile gone none
"p" × 80 profile gone none
pro\0file profile gone none
" profile" (leading space) " profile" — written verbatim, §11.3.2.3 forbids it none
profile profile none

The three "profile gone" rows are this crate's own reader rejecting what this crate's own writer
produced: split_keyword refuses a name field outside 1–79 bytes, and an embedded null makes the
byte after the split the compression method, which is then not 0. An ICC profile — the payload
whose loss silently changes what a viewer paints — disappears between a write and a read with
nothing said.

What would close this

The notice channel already exists and already has the vocabulary. Route the profile name through
the same verdict the keyword takes, with the same outcomes:

  • outside Latin-1, or outside 1–79 bytes, or holding a null → drop the iCCP chunk and report it
    (the profile cannot be carried, and dropping it loudly beats dropping it silently);
  • outside the printable repertoire, or with a leading/trailing/consecutive space → write verbatim
    and report that the datastream is non-conforming per §15.3.1, exactly as TextKeywordRepertoire
    and TextKeywordSpacing do.

MetadataNotice is #[non_exhaustive] with permanent append-only discriminants, so the new
variants are additive.

Why it was not fixed in #550

It is pre-existing (the iCCP writer predates that branch), it is unreachable through the
metadata carry that PR is about — a name read out of a file has already passed split_keyword,
so it is Latin-1 and 1–79 bytes by construction — and it is outside that PR's manifest. It is
filed here because it is the one other field the specification defines identically to the
keyword, and because the notice channel it needs now exists.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions