From eb6dccb67522434463b6d1762232395b781436cd Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 17 Feb 2023 20:29:50 -0500 Subject: [PATCH] LibGfx: Implement serialization of MultiLocalizedUnicodeTagData --- .../Libraries/LibGfx/ICC/BinaryWriter.cpp | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp b/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp index d1b1ff5aed..40fd65469a 100644 --- a/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp +++ b/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -13,9 +14,58 @@ namespace Gfx::ICC { +static ErrorOr encode_multi_localized_unicode(MultiLocalizedUnicodeTagData const& tag_data) +{ + // ICC v4, 10.15 multiLocalizedUnicodeType + // "The Unicode strings in storage should be encoded as 16-bit big-endian, UTF-16BE, + // and should not be NULL terminated." + size_t number_of_records = tag_data.records().size(); + size_t header_and_record_size = 4 * sizeof(u32) + number_of_records * sizeof(MultiLocalizedUnicodeRawRecord); + + size_t number_of_codepoints = 0; + Vector utf16_strings; + TRY(utf16_strings.try_ensure_capacity(number_of_records)); + for (auto const& record : tag_data.records()) { + TRY(utf16_strings.try_append(TRY(utf8_to_utf16(record.text)))); + number_of_codepoints += utf16_strings.last().size(); + } + + size_t string_table_size = number_of_codepoints * sizeof(u16); + + auto bytes = TRY(ByteBuffer::create_uninitialized(header_and_record_size + string_table_size)); + + auto* header = bit_cast*>(bytes.data()); + header[0] = (u32)MultiLocalizedUnicodeTagData::Type; + header[1] = 0; + header[2] = number_of_records; + header[3] = sizeof(MultiLocalizedUnicodeRawRecord); + + size_t offset = header_and_record_size; + auto* records = bit_cast(bytes.data() + 16); + for (size_t i = 0; i < number_of_records; ++i) { + records[i].language_code = tag_data.records()[i].iso_639_1_language_code; + records[i].country_code = tag_data.records()[i].iso_3166_1_country_code; + records[i].string_length_in_bytes = utf16_strings[i].size() * sizeof(u16); + records[i].string_offset_in_bytes = offset; + offset += records[i].string_offset_in_bytes; + } + + auto* string_table = bit_cast*>(bytes.data() + header_and_record_size); + for (auto const& utf16_string : utf16_strings) { + for (size_t i = 0; i < utf16_string.size(); ++i) + string_table[i] = utf16_string[i]; + string_table += utf16_string.size(); + } + + return bytes; +} + static ErrorOr encode_tag_data(TagData const& tag_data) { - (void)tag_data; + switch (tag_data.type()) { + case MultiLocalizedUnicodeTagData::Type: + return encode_multi_localized_unicode(static_cast(tag_data)); + } return ByteBuffer {}; }