casio_doc/fontcharacter/tools/fontcharacter/__init__.py

191 lines
5.0 KiB
Python
Executable File

#!/usr/bin/env python3
""" The FONTCHARACTER Python module is used for manipulating the source
and binary formats. See <../../formats/SOURCE.md> for more information.
"""
import os, sys, string, yaml
# Sainitize for the `id` field
def sanitize_id(s):
return ''.join(ch for ch in s \
if ch in string.ascii_letters + string.digits)
class Reference:
""" The FONTCHARACTER source object.
Loads the characters and corrects the data. """
def __init__(self, path, sets_only=False):
# Load sets
self.__load_sets(yaml.load(open(\
os.path.join(path, 'sets.yml')).read()))
if sets_only: return
# Load categories
self.categories = {}
for c in yaml.load(open(os.path.join(path, 'categories.yml')).read()):
self.__explore_category(c, '', '', '')
# Load all of the YAML files
self.__load_characters(yaml.load(open(\
os.path.join(path, 'characters.yml')).read()))
# Gather leaders [TODO: `leading` field?]
for st in self.sets.keys():
lead = []
for code in self.sets[st]['characters'].keys():
lead += [code >> 8]
self.sets[st]['leading'] = set(lead)
def __explore_category(self, c, id, prefix, suffix):
""" Explore a category. """
# Iterate on things
id += c['id']
try: prefix = c['prefix'] + ' ' + prefix
except: True
try: suffix = suffix + ' ' + c['suffix']
except: True
# Add current (sub)category
self.categories[id] = {'prefix': prefix, 'suffix': suffix}
# Explore subcategories
if c.get('sub'):
for s in c['sub']:
self.__explore_category(s, id + '/', prefix, suffix)
def __load_sets(self, raw):
""" Explore sets. """
self.default_set = ''
self.sets = {}
# Initialize kids
kids = {}
# Read raw entries
for s in raw:
self.sets[s['id']] = {
'description': s['description'],
'characters': {},
'parent': s.get('parent'),
'kids': []}
if s.get('default'): self.default_set = s['id']
if s.get('parent'):
if not kids.get(s['parent']): kids[s['parent']] = []
kids[s['parent']] += [s['id']]
# Add kids to real elements
for parent, k in kids.items():
self.sets[parent]['kids'] += kids[parent]
def __inherit_character(self, id, code, inherit, pr):
""" Inherit character.
`id`: id of the set, code: code of the character,
`inherit`: the set to inherit it from,
`pr`: priority (starting from 0, the more the further). """
if not self.sets[id]['characters'].get(code) \
or self.sets[id]['characters'][code]['_pr'] > pr:
self.sets[id]['characters'][code] = {'inherit': inherit, '_pr': pr}
for k in self.sets[id]['kids']:
self.__inherit_character(k, code, inherit, pr + 1)
def __load_characters(self, raw):
""" Load characters. """
# Main loop
for c in raw:
# Get the complete name
n = c['name']
if c.get('category'):
ct = self.categories[c['category']]
n = ct['prefix'] + n + ct['suffix']
# Get the character set, and the priority
try: st = c['set']
except: st = self.default_set
# Make the character
code = c['code']
char = {'name': n, '_pr': 0}
# Check the multi thingy
m = c.get('multi')
if type(m) == list and m:
char['multi'] = \
list(map(lambda x:int(x, 16) if type(x) == str else x, m))
elif type(m) == int:
char['multi'] = [m]
# Check the unicode thingy
u = c.get('unicode')
if type(u) == list and u:
char['unicode'] = \
list(map(lambda x:int(x, 16) if type(x) == str else x, u))
elif type(u) == int:
char['unicode'] = [u]
# Check the ascii thingy
if c.get('ascii'):
char['ascii'] = c['ascii']
elif char.get('unicode') \
and all(0x00 <= c <= 0xFF for c in char['unicode']):
char['ascii'] = ''.join(map(chr,char['unicode']))
# Check the id thingy
if c.get('id'):
char['id'] = c['id']
elif char.get('ascii'):
char['id'] = sanitize_id(char['ascii'])
if not char.get('id') and not char.get('multi'):
char['id'] = sanitize_id(char['name'])
# Add it to the set
self.sets[st]['characters'][code] = char
for k in self.sets[st]['kids']:
self.__inherit_character(k, code, st, 1)
# Get ascii/unicode equivalents
for id, st in self.sets.items():
for code in st['characters'].keys():
self.__deduce_character_id(id, code)
def __deduce_character_id(self, id, code):
""" Calculate a multi-character's ID. """
char = self.sets[id]['characters'][code]
if char['_pr'] > 0 or char.get('id'): return
m = ""
if not char.get('multi'): m = sanitize_id(char.get('name'))
else:
for num, c in map(lambda x:(x, self.sets[id]['characters'][x]), \
char['multi']):
parent = id
if c['_pr'] > 0:
parent = c['inherit']
c = self.sets[parent]['characters'][num]
if c.get('multi'):
self.__deduce_character_id(parent, num)
m += c['id']
char['id'] = m
def list(self):
""" Get the list of sets. """
l = list(self.sets.keys())
l.remove(self.default_set)
return [self.default_set] + l
def get(self, id = None):
""" Get a set. """
if type(id) != str:
id = self.default_set
st = self.sets[id]
st['id'] = id
return st
# End of file.