summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2023-01-04 15:34:25 -0500
committerAndreas Kling <kling@serenityos.org>2023-01-05 10:54:35 +0100
commit68f678f566b533396a9c629784289ae3653f40ed (patch)
tree1550af72430c3adc918e7ef55afd135b9b5be019 /Userland
parentfafacbb87b0acf48420a3e6d5e2e3793f037956e (diff)
downloadserenity-68f678f566b533396a9c629784289ae3653f40ed.zip
LibGfx+icc: Print if profile id is valid
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGfx/ICCProfile.cpp24
-rw-r--r--Userland/Libraries/LibGfx/ICCProfile.h2
-rw-r--r--Userland/Utilities/icc.cpp11
3 files changed, 34 insertions, 3 deletions
diff --git a/Userland/Libraries/LibGfx/ICCProfile.cpp b/Userland/Libraries/LibGfx/ICCProfile.cpp
index e8a4098563..bcdb839c60 100644
--- a/Userland/Libraries/LibGfx/ICCProfile.cpp
+++ b/Userland/Libraries/LibGfx/ICCProfile.cpp
@@ -248,6 +248,9 @@ Optional<Crypto::Hash::MD5::DigestType> parse_profile_id(ICCHeader const& header
Crypto::Hash::MD5::DigestType md5;
static_assert(sizeof(md5.data) == sizeof(header.profile_md5));
memcpy(md5.data, header.profile_md5, sizeof(md5.data));
+
+ // FIXME: Consider comparing read id with compute_id() result and failing if they aren't equal.
+
return md5;
}
}
@@ -386,4 +389,25 @@ ErrorOr<NonnullRefPtr<Profile>> Profile::try_load_from_externally_owned_memory(R
return profile;
}
+Crypto::Hash::MD5::DigestType Profile::compute_id(ReadonlyBytes bytes)
+{
+ // ICC v4, 7.2.18 Profile ID field
+ // The Profile ID shall be calculated using the MD5 fingerprinting method as defined in Internet RFC 1321.
+ // The entire profile, whose length is given by the size field in the header,
+ // with the profile flags field (bytes 44 to 47, see 7.2.11),
+ // rendering intent field (bytes 64 to 67, see 7.2.15),
+ // and profile ID field (bytes 84 to 99) in the profile header
+ // temporarily set to zeros (00h), shall be used to calculate the ID.
+ const u8 zero[16] = {};
+ Crypto::Hash::MD5 md5;
+ md5.update(bytes.slice(0, 44));
+ md5.update(ReadonlyBytes { zero, 4 }); // profile flags field
+ md5.update(bytes.slice(48, 64 - 48));
+ md5.update(ReadonlyBytes { zero, 4 }); // rendering intent field
+ md5.update(bytes.slice(68, 84 - 68));
+ md5.update(ReadonlyBytes { zero, 16 }); // profile ID field
+ md5.update(bytes.slice(100));
+ return md5.digest();
+}
+
}
diff --git a/Userland/Libraries/LibGfx/ICCProfile.h b/Userland/Libraries/LibGfx/ICCProfile.h
index 2d85bd4dcd..e4e0140699 100644
--- a/Userland/Libraries/LibGfx/ICCProfile.h
+++ b/Userland/Libraries/LibGfx/ICCProfile.h
@@ -139,6 +139,8 @@ public:
XYZ const& pcs_illuminant() const { return m_pcs_illuminant; }
Optional<Crypto::Hash::MD5::DigestType> const& id() const { return m_id; }
+ static Crypto::Hash::MD5::DigestType compute_id(ReadonlyBytes);
+
private:
Version m_version;
DeviceClass m_device_class;
diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp
index 6c67b7fec1..67d0ced9d9 100644
--- a/Userland/Utilities/icc.cpp
+++ b/Userland/Utilities/icc.cpp
@@ -40,9 +40,14 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
outln("pcs illuminant: {}", profile->pcs_illuminant());
out("id: ");
- if (auto id = profile->id(); id.has_value())
- outln("{}", *id);
- else
+ if (auto id = profile->id(); id.has_value()) {
+ out("{}", *id);
+ auto computed = Gfx::ICC::Profile::compute_id(icc_file->bytes());
+ if (*id == computed)
+ outln(" (valid)");
+ else
+ outln(" (invalid! valid would be {})", computed);
+ } else
outln("(not set)");
return 0;