mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 16:21:29 +00:00
LibGfx: Add ICCProfile support for multiLocalizedUnicodeType
This is used in v4 profiles for the required 'cprt' and 'desc' tags.
This commit is contained in:
parent
3dfb012a1a
commit
ec7a2058a2
Notes:
sideshowbarker
2024-07-18 00:34:07 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/ec7a2058a2 Pull-request: https://github.com/SerenityOS/serenity/pull/17126
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <AK/Endian.h>
|
||||
#include <LibGfx/ICCProfile.h>
|
||||
#include <LibTextCodec/Decoder.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
|
@ -549,6 +550,68 @@ static ErrorOr<void> check_reserved(ReadonlyBytes tag_bytes)
|
|||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<MultiLocalizedUnicodeTagData>> MultiLocalizedUnicodeTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.15 multiLocalizedUnicodeType
|
||||
VERIFY(tag_type(bytes) == MultiLocalizedUnicodeTagData::Type);
|
||||
TRY(check_reserved(bytes));
|
||||
|
||||
// "Multiple strings within this tag may share storage locations. For example, en/US and en/UK can refer to the
|
||||
// same string data."
|
||||
// This implementation makes redudant string copies in that case.
|
||||
// Most of the time, this costs just a few bytes, so that seems ok.
|
||||
|
||||
if (bytes.size() < 4 * sizeof(u32))
|
||||
return Error::from_string_literal("ICC::Profile: multiLocalizedUnicodeType has not enough data");
|
||||
|
||||
// Table 54 — multiLocalizedUnicodeType
|
||||
u32 number_of_records = *bit_cast<BigEndian<u32> const*>(bytes.data() + 8);
|
||||
u32 record_size = *bit_cast<BigEndian<u32> const*>(bytes.data() + 12);
|
||||
|
||||
// "The fourth field of this tag, the record size, should contain the value 12, which corresponds to the size in bytes
|
||||
// of each record. Any code that needs to access the nth record should determine the record’s offset by multiplying
|
||||
// n by the contents of this size field and adding 16. This minor extra effort allows for future expansion of the record
|
||||
// encoding, should the need arise, without having to define a new tag type."
|
||||
if (record_size < 12)
|
||||
return Error::from_string_literal("ICC::Profile: multiLocalizedUnicodeType record size too small");
|
||||
if (bytes.size() < 16 + number_of_records * record_size)
|
||||
return Error::from_string_literal("ICC::Profile: multiLocalizedUnicodeType not enough data for records");
|
||||
|
||||
Vector<Record> records;
|
||||
TRY(records.try_resize(number_of_records));
|
||||
|
||||
// "For the definition of language codes and country codes, see respectively
|
||||
// ISO 639-1 and ISO 3166-1. The Unicode strings in storage should be encoded as 16-bit big-endian, UTF-16BE,
|
||||
// and should not be NULL terminated."
|
||||
auto& utf_16be_decoder = *TextCodec::decoder_for("utf-16be");
|
||||
|
||||
struct RawRecord {
|
||||
BigEndian<u16> language_code;
|
||||
BigEndian<u16> country_code;
|
||||
BigEndian<u32> string_length_in_bytes;
|
||||
BigEndian<u32> string_offset_in_bytes;
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < number_of_records; ++i) {
|
||||
size_t offset = 16 + i * record_size;
|
||||
RawRecord record = *bit_cast<RawRecord const*>(bytes.data() + offset);
|
||||
|
||||
records[i].iso_639_1_language_code = record.language_code;
|
||||
records[i].iso_3166_1_country_code = record.country_code;
|
||||
|
||||
if (record.string_length_in_bytes % 2 != 0)
|
||||
return Error::from_string_literal("ICC::Profile: multiLocalizedUnicodeType odd UTF-16 byte length");
|
||||
|
||||
if (record.string_offset_in_bytes + record.string_length_in_bytes > bytes.size())
|
||||
return Error::from_string_literal("ICC::Profile: multiLocalizedUnicodeType string offset out of bounds");
|
||||
|
||||
StringView utf_16be_data { bytes.data() + record.string_offset_in_bytes, record.string_length_in_bytes };
|
||||
records[i].text = TRY(String::from_deprecated_string(utf_16be_decoder.to_utf8(utf_16be_data)));
|
||||
}
|
||||
|
||||
return adopt_ref(*new MultiLocalizedUnicodeTagData(offset, size, move(records)));
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<TextTagData>> TextTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.24 textType
|
||||
|
@ -619,6 +682,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, Detail::T
|
|||
|
||||
auto type = tag_type(tag_bytes);
|
||||
switch (type) {
|
||||
case MultiLocalizedUnicodeTagData::Type:
|
||||
return MultiLocalizedUnicodeTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
case TextTagData::Type:
|
||||
return TextTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
default:
|
||||
|
|
|
@ -257,6 +257,29 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// ICC v4, 10.15 multiLocalizedUnicodeType
|
||||
class MultiLocalizedUnicodeTagData : public TagData {
|
||||
public:
|
||||
static constexpr TagTypeSignature Type { 0x6D6C7563 }; // 'mluc'
|
||||
|
||||
static ErrorOr<NonnullRefPtr<MultiLocalizedUnicodeTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
|
||||
|
||||
struct Record {
|
||||
u16 iso_639_1_language_code;
|
||||
u16 iso_3166_1_country_code;
|
||||
String text;
|
||||
};
|
||||
|
||||
MultiLocalizedUnicodeTagData(u32 offset, u32 size, Vector<Record> records)
|
||||
: TagData(offset, size, Type)
|
||||
, m_records(move(records))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<Record> m_records;
|
||||
};
|
||||
|
||||
// ICC v4, 10.24 textType
|
||||
class TextTagData : public TagData {
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue