Skip to content

Instantly share code, notes, and snippets.

@micahswitzer
Created April 28, 2021 19:34
Show Gist options
  • Save micahswitzer/4bb5f4236cfed29206ce4e8c101abf5d to your computer and use it in GitHub Desktop.
Save micahswitzer/4bb5f4236cfed29206ce4e8c101abf5d to your computer and use it in GitHub Desktop.
Parse PCF tables
#!/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