0

我希望你们中很少有人对 EOT 文件了解很多(我认为没有人知道),但您可能对一般文件格式有足够的了解,以便对这个问题有所了解。

我可以很好地读取 Python 中的 EOT 字体,但是在修改了一些标头字段并重新计算校验和后,Internet Explorer 拒绝了结果文件。

有两个校验和,一个用于 RootString 字段,另一个用于整个字体文件。该规范可以在这里找到:https ://www.w3.org/Submission/EOT/#Version22

当我解析一个 EOT 文件并重新计算它的 ChecksumAdjustment 时,我得到一个与文件中的数字不匹配的数字,但如果我用这个不同的校验和保存文件,它仍然有效。但是,如果我真的对字体进行任何修改,例如更改字体的名称,它将不再起作用。

如果校验和不是问题,我认为这可能与填充字段有关,我正在努力理解其目的。显然,填充是为了确保 ULONG(4 字节)对齐。某些标头字段具有自定义长度,因此当自定义长度字段破坏对齐时,可能会使用填充。但是第一个填充字段的目的是什么?它前面没有自定义长度字段,并且填充发生在 4 个字节的倍数处,那么为什么需要它?此外,我拥有的文件(我知道它有效)具有每个2 字节的填充字段,即使它破坏了对齐。

这是我解析文件的方式:

def __init__(self, file_path):
    super().__init__(base.FontType.EOT)

    self._file_name = os.path.basename(file_path)

    with open(file_path, 'rb') as f:
        self.eot_size = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.font_data_size = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.version = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.flags = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.font_panose = struct.unpack('<10s', f.read(struct.calcsize('<10s')))[0]
        self.charset = struct.unpack('<s', f.read(struct.calcsize('<s')))[0]
        self.italic = struct.unpack('<s', f.read(struct.calcsize('<s')))[0]
        self.weight = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.fs_type = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.magic_number = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.unicode_range_1 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.unicode_range_2 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.unicode_range_3 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.unicode_range_4 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.code_page_range_1 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.code_page_range_2 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.checksum_adjustment = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.reserved1 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.reserved2 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.reserved3 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.reserved4 = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self._eat_padding(f)
        self.family_name_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.family_name = f.read(self.family_name_size).decode('utf-16')
        self._eat_padding(f)
        self.style_name_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.style_name = f.read(self.style_name_size).decode('utf-16')
        self._eat_padding(f)
        self.version_name_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.version_name = f.read(self.version_name_size).decode('utf-16')
        self._eat_padding(f)
        self.full_name_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.full_name = f.read(self.full_name_size).decode('utf-16')
        self._eat_padding(f)
        self.root_string_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.root_string = f.read(self.root_string_size).decode('utf-16')
        self.root_string_checksum = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.eudc_code_page = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self._eat_padding(f)
        self.signature_size = struct.unpack('<H', f.read(struct.calcsize('<H')))[0]
        self.signature = f.read(self.signature_size)
        self.eudc_flags = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.eudc_font_size = struct.unpack('<L', f.read(struct.calcsize('<L')))[0]
        self.eudc_font_data = f.read(self.eudc_font_size)
        self.font_data = f.read(self.font_data_size)

    _assert_equal(self.family_name_size, len(self.family_name.encode('utf-16-le')))
    _assert_equal(self.style_name_size, len(self.style_name.encode('utf-16-le')))
    _assert_equal(self.version_name_size, len(self.version_name.encode('utf-16-le')))
    _assert_equal(self.full_name_size, len(self.full_name.encode('utf-16-le')))
    _assert_equal(self.root_string_size, len(self.root_string.encode('utf-16-le')))


def _eat_padding(self, f):
    L = struct.calcsize('<L')
    H = struct.calcsize('<H')

#    f.read(H)
#    return

    excess = f.tell() % L
    if excess != 0:
        assert excess % H == 0, 'Font not USHORT aligned'
        bytes = f.read(L - excess)
        assert bytes == b'\x00' * (L - excess), 'Found non-zero padding bytes'

这是我导出文件并计算校验和的方法:

def dump(self, f):
    self._compute_root_string_checksum()

    buf = io.BytesIO()

    buf.write(struct.pack('<L', self.eot_size))
    buf.write(struct.pack('<L', self.font_data_size))
    buf.write(struct.pack('<L', self.version))
    buf.write(struct.pack('<L', self.flags))
    buf.write(struct.pack('<10s', self.font_panose))
    buf.write(struct.pack('<s', self.charset))
    buf.write(struct.pack('<s', self.italic))
    buf.write(struct.pack('<L', self.weight))
    buf.write(struct.pack('<H', self.fs_type))
    buf.write(struct.pack('<H', self.magic_number))
    buf.write(struct.pack('<L', self.unicode_range_1))
    buf.write(struct.pack('<L', self.unicode_range_2))
    buf.write(struct.pack('<L', self.unicode_range_3))
    buf.write(struct.pack('<L', self.unicode_range_4))
    buf.write(struct.pack('<L', self.code_page_range_1))
    buf.write(struct.pack('<L', self.code_page_range_2))
    checksum_adj_pos = buf.tell()
    buf.write(struct.pack('<L', 0))
    buf.write(struct.pack('<L', self.reserved1))
    buf.write(struct.pack('<L', self.reserved2))
    buf.write(struct.pack('<L', self.reserved3))
    buf.write(struct.pack('<L', self.reserved4))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.family_name_size))
    buf.write(self.family_name.encode('utf-16-le'))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.style_name_size))
    buf.write(self.style_name.encode('utf-16-le'))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.version_name_size))
    buf.write(self.version_name.encode('utf-16-le'))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.full_name_size))
    buf.write(self.full_name.encode('utf-16-le'))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.root_string_size))
    buf.write(self.root_string.encode('utf-16-le'))
    buf.write(struct.pack('<L', self.root_string_checksum))
    buf.write(struct.pack('<L', self.eudc_code_page))
    self._add_padding(buf)
    buf.write(struct.pack('<H', self.signature_size))
    buf.write(self.signature)
    buf.write(struct.pack('<L', self.eudc_flags))
    buf.write(struct.pack('<L', self.eudc_font_size))
    buf.write(self.eudc_font_data)
    buf.write(self.font_data)

    total = 0
    buf.seek(0)
    while True:
        bytes = buf.read(4)

        if len(bytes) == 0:
            break

        assert len(bytes) % 4 == 0, 'Font not padded correctly'

        ulong = struct.unpack('<L', bytes)[0]
        total = (total + ulong) & 0xffffffff

    self.checksum_adjustment = (0xB1B0AFBA - total) & 0xffffffff

    buf.seek(checksum_adj_pos)
    buf.write(struct.pack('<L', self.checksum_adjustment))

    buf.seek(0)
    while True:
        bytes = buf.read(1)

        if len(bytes) == 0:
            break

        f.write(bytes)


def _compute_root_string_checksum(self):
    root_string = self.root_string.encode('utf-16-le')
    buf = io.BytesIO(root_string)

    total = 0
    while True:
        bytes = buf.read(4)

        if len(bytes) == 0:
            break

        assert len(bytes) % 4 == 0, 'Root String not padded correctly'

        ulong = struct.unpack('<L', bytes)[0]
        total = (total + ulong) & 0xffffffff

    self.root_string_checksum = total ^ 0x50475342

任何帮助深表感谢。谢谢

4

1 回答 1

0

看这里https://github.com/westmon/formhub/blob/af43646848106d06fbd5a82c90b9f0f6ab43613a/public/assets/plugins/ionicons/builder/scripts/eotlitetool.py

eot.checkSumAdjustment  = otf - > head -> offset + 12
于 2020-04-17T09:54:02.973 回答