Created
January 24, 2025 18:01
-
-
Save moyix/6fd663e71f6c401d055c854ce46dff38 to your computer and use it in GitHub Desktop.
Tiny decoder for Chromium Web Custom MIME Data Format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Refs: | |
# https://stackoverflow.com/questions/68745902/what-is-the-data-format-specification-for-chromium-web-custom-mime-data-format/73076391#73076391 | |
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/base/clipboard/custom_data_helper.cc | |
import sys | |
import json | |
def read_u16string(bs): | |
length = int.from_bytes(bs[:4], "little") | |
byte_length = length * 2 | |
if length % 2 != 0: | |
byte_length += 2 | |
return bs[4 : 4 + length * 2].decode("utf-16le"), bs[4 + byte_length :] | |
def decode_chromium_web_custom(bs): | |
# Format: | |
# 0-3: UInt32LE length of data | |
# 4-7: UInt32LE count of pairs | |
# [count pairs of] | |
# U16String key | |
# U16String value | |
# where U16String is: | |
# 0-3: UInt32LE length of string | |
# 4-4+length: UTF-16LE string | |
data_len = int.from_bytes(bs[:4], "little") | |
data = bs[4 : 4 + data_len] | |
assert len(bs) - 4 == data_len | |
count = int.from_bytes(data[:4], "little") | |
data = data[4:] | |
pairs = [] | |
for _ in range(count): | |
key, data = read_u16string(data) | |
value, data = read_u16string(data) | |
pairs.append((key, value)) | |
return pairs | |
def encode_chromium_web_custom(pairs): | |
data = b"" | |
for k, v in pairs: | |
data += len(k).to_bytes(4, "little") + k.encode("utf-16le") | |
if len(k) % 2 != 0: | |
data += b"\0\0" | |
data += len(v).to_bytes(4, "little") + v.encode("utf-16le") | |
if len(v) % 2 != 0: | |
data += b"\0\0" | |
return len(data).to_bytes(4, "little") + len(pairs).to_bytes(4, "little") + data | |
def print_pairs(pairs): | |
for k, v in pairs: | |
if k.endswith("+json"): | |
js = json.loads(v) | |
print(f"{k}: {json.dumps(js, indent=2)}") | |
else: | |
print(f"{k}: {v}") | |
print() | |
if __name__ == "__main__": | |
pairs = decode_chromium_web_custom(open(sys.argv[1], "rb").read()) | |
print_pairs(pairs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment