Created
April 28, 2021 19:34
-
-
Save micahswitzer/4bb5f4236cfed29206ce4e8c101abf5d to your computer and use it in GitHub Desktop.
Parse PCF tables
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 | |
from struct import unpack | |
from argparse import ArgumentParser, FileType | |
# Info taken from https://fontforge.org/docs/techref/pcf-format.html | |
PCF_PROPERTIES = (1<<0) | |
PCF_ACCELERATORS = (1<<1) | |
PCF_METRICS = (1<<2) | |
PCF_BITMAPS = (1<<3) | |
PCF_INK_METRICS = (1<<4) | |
PCF_BDF_ENCODINGS = (1<<5) | |
PCF_SWIDTHS = (1<<6) | |
PCF_GLYPH_NAMES = (1<<7) | |
PCF_BDF_ACCELERATORS = (1<<8) | |
PCF_TYPE_MAP = { | |
PCF_PROPERTIES: 'PROPERTIES', | |
PCF_ACCELERATORS: 'ACCELERATORS', | |
PCF_METRICS: 'METRICS', | |
PCF_BITMAPS: 'BITMAPS', | |
PCF_INK_METRICS: 'INK_METRICS', | |
PCF_BDF_ENCODINGS: 'BDF_ENCODINGS', | |
PCF_SWIDTHS: 'SWIDTHS', | |
PCF_GLYPH_NAMES: 'GLYPH_NAMES', | |
PCF_BDF_ACCELERATORS: 'BDF_ACCELERATORS' | |
} | |
PCF_DEFAULT_FORMAT = 0x00000000 | |
PCF_INKBOUNDS = 0x00000200 | |
PCF_ACCEL_W_INKBOUNDS = 0x00000100 | |
PCF_COMPRESSED_METRICS = 0x00000100 | |
PCF_FORMAT_MAP = { | |
PCF_DEFAULT_FORMAT: 'DEFAULT_FORMAT', | |
PCF_INKBOUNDS: 'INKBOUNDS', | |
PCF_ACCEL_W_INKBOUNDS: 'ACCEL_W_INKBOUNDS', | |
PCF_COMPRESSED_METRICS: 'COMPRESSED_METRICS' | |
} | |
PCF_GLYPH_PAD_MASK = (3<<0) # See the bitmap table for explanation | |
PCF_BYTE_MASK = (1<<2) # If set then Most Sig Byte First | |
PCF_BIT_MASK = (1<<3) # If set then Most Sig Bit First | |
PCF_SCAN_UNIT_MASK = (3<<4) # See the bitmap table for explanation | |
PCF_FORMAT_MODIFIERS_MAP = { | |
PCF_GLYPH_PAD_MASK: 'GLYPH_PAD', | |
PCF_BYTE_MASK: 'BYTE', | |
PCF_BIT_MASK: 'BIT', | |
PCF_SCAN_UNIT_MASK: 'SCAN_UNIT' | |
} | |
def pcf_format_str(f): | |
f_str = PCF_FORMAT_MAP.get(f & ~0xff, 'Unknown format') | |
# really fancy code to iterate all of the flags and select the strings | |
# coresponding to the ones that are set | |
f_mod_str = ', '.join([v for k, v in iter(PCF_FORMAT_MODIFIERS_MAP.items()) if k & (f & 0xff)]) | |
return f'{f_str} ({f_mod_str if f_mod_str != "" else "None"})' | |
def main(): | |
ap = ArgumentParser(description='View information about a PCF file') | |
ap.add_argument('infile', type=FileType('rb'), help='The file to process') | |
args = ap.parse_args() | |
magic, table_count = unpack('<4sI', args.infile.read(8)) | |
if magic != b'\x01fcp': | |
print(f'Error: bad magic: {magic}') | |
args.infile.close() | |
return 1 | |
for _ in range(table_count): | |
t_type, t_format, t_size, t_offset = unpack('<4I', args.infile.read(16)) | |
print(f"""{PCF_TYPE_MAP.get(t_type, 'Unknown type')}, {pcf_format_str(t_format)} | |
size: {t_size:08x}, offset: {t_offset:08x}""") | |
args.infile.close() | |
return 0 | |
if __name__ == '__main__': | |
exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment