From 3dfb012a1adb86e1ec2be03a9c29df39e18ed86c Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sat, 21 Jan 2023 20:50:20 -0500 Subject: [PATCH] LibGfx: Add ICCProfile support for textType This is used in v2 profiles for the required 'cprt' tag. --- Userland/Libraries/LibGfx/ICCProfile.cpp | 50 ++++++++++++++++++++++-- Userland/Libraries/LibGfx/ICCProfile.h | 25 +++++++++++- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibGfx/ICCProfile.cpp b/Userland/Libraries/LibGfx/ICCProfile.cpp index 2d9f6757e1..20c991fd78 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.cpp +++ b/Userland/Libraries/LibGfx/ICCProfile.cpp @@ -532,6 +532,48 @@ DeviceAttributes::DeviceAttributes(u64 bits) { } +static TagTypeSignature tag_type(ReadonlyBytes tag_bytes) +{ + VERIFY(tag_bytes.size() >= sizeof(u32)); + return *bit_cast const*>(tag_bytes.data()); +} + +static ErrorOr check_reserved(ReadonlyBytes tag_bytes) +{ + if (tag_bytes.size() < 2 * sizeof(u32)) + return Error::from_string_literal("ICC::Profile: Not enough data for tag reserved field"); + + if (*bit_cast const*>(tag_bytes.data() + sizeof(u32)) != 0) + return Error::from_string_literal("ICC::Profile: tag reserved field not 0"); + + return {}; +} + +ErrorOr> TextTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.24 textType + VERIFY(tag_type(bytes) == TextTagData::Type); + TRY(check_reserved(bytes)); + + // "The textType is a simple text structure that contains a 7-bit ASCII text string. The length of the string is obtained + // by subtracting 8 from the element size portion of the tag itself. This string shall be terminated with a 00h byte." + u32 length = bytes.size() - 8; + + u8 const* text_data = bytes.data() + 8; + for (u32 i = 0; i < length; ++i) { + if (text_data[i] >= 128) + return Error::from_string_literal("ICC::Profile: textType data not 7-byte ASCII"); + } + + if (length == 0) + return Error::from_string_literal("ICC::Profile: textType too short for \\0 byte"); + + if (text_data[length - 1] != '\0') + return Error::from_string_literal("ICC::Profile: textType data not \\0-terminated"); + + return adopt_ref(*new TextTagData(offset, size, TRY(String::from_utf8(StringView(text_data, length - 1))))); +} + ErrorOr Profile::read_header(ReadonlyBytes bytes) { if (bytes.size() < sizeof(ICCHeader)) @@ -574,12 +616,14 @@ ErrorOr> Profile::read_tag(ReadonlyBytes bytes, Detail::T // what kind of data is contained within a tag." if (tag_bytes.size() < sizeof(u32)) return Error::from_string_literal("ICC::Profile: Not enough data for tag type"); - auto tag_type = *bit_cast const*>(tag_bytes.data()); - switch ((u32)(TagTypeSignature)tag_type) { + auto type = tag_type(tag_bytes); + switch (type) { + case TextTagData::Type: + return TextTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); default: // FIXME: optionally ignore tags of unknown type - return adopt_ref(*new UnknownTagData(entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element, tag_type)); + return adopt_ref(*new UnknownTagData(entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element, type)); } } diff --git a/Userland/Libraries/LibGfx/ICCProfile.h b/Userland/Libraries/LibGfx/ICCProfile.h index 062b93b711..66a91c6da9 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.h +++ b/Userland/Libraries/LibGfx/ICCProfile.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -31,11 +32,11 @@ enum class FourCCType { template struct [[gnu::packed]] DistinctFourCC { - explicit DistinctFourCC(u32 value) + constexpr explicit DistinctFourCC(u32 value) : value(value) { } - explicit operator u32() const { return value; } + constexpr operator u32() const { return value; } char c0() const { return value >> 24; } char c1() const { return (value >> 16) & 0xff; } @@ -256,6 +257,26 @@ public: } }; +// ICC v4, 10.24 textType +class TextTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x74657874 }; // 'text' + + static ErrorOr> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + TextTagData(u32 offset, u32 size, String text) + : TagData(offset, size, Type) + , m_text(move(text)) + { + } + + // Guaranteed to be 7-bit ASCII. + String const& text() const { return m_text; } + +private: + String m_text; +}; + namespace Detail { struct TagTableEntry; }