| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | '''Generate HWPv5 Binary Spec Document |
| | |
| | Usage:: |
| | |
| | hwp5spec xml [--loglevel=<loglevel>] |
| | hwp5spec -h | --help |
| | hwp5spec --version |
| | |
| | Options:: |
| | |
| | -h --help Show this screen |
| | --version Show version |
| | --loglevel=<loglevel> Set log level [default: warning] |
| | ''' |
| |
|
| | import logging |
| | import xml.etree.ElementTree as ET |
| |
|
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| |
|
| | def define_enum_type(enum_type): |
| | attrs = dict(name=enum_type.__name__) |
| | if enum_type.scoping_struct: |
| | attrs['scope'] = enum_type.scoping_struct.__name__ |
| | elem = ET.Element('EnumType', attrs) |
| | value_names = list((e, e.name) for e in enum_type.instances) |
| | value_names.sort() |
| | for value, name in value_names: |
| | item = ET.Element('item', dict(name=name, value=str(value))) |
| | elem.append(item) |
| | return elem |
| |
|
| |
|
| | def define_bitfield(bitgroup_name, bitgroup_desc): |
| | attrs = dict(name=bitgroup_name, |
| | lsb=str(bitgroup_desc.lsb), |
| | msb=str(bitgroup_desc.msb)) |
| | elem = ET.Element('BitField', attrs) |
| | elem.append(reference_type(bitgroup_desc.valuetype)) |
| | return elem |
| |
|
| |
|
| | def define_flags_type(flags_type): |
| | elem = ET.Element('FlagsType') |
| | from hwp5.dataio import BitGroupDescriptor |
| | base = ET.SubElement(elem, 'base') |
| | base.append(reference_type(flags_type.basetype)) |
| | bitgroups = flags_type.__dict__.items() |
| | bitgroups = ((v.lsb, (k, v)) for k, v in bitgroups |
| | if isinstance(v, BitGroupDescriptor)) |
| | bitgroups = list(bitgroups) |
| | bitgroups.sort() |
| | bitgroups = reversed(bitgroups) |
| | bitgroups = ((k, v) for lsb, (k, v) in bitgroups) |
| | bitgroups = (define_bitfield(k, v) for k, v in bitgroups) |
| | for bitgroup in bitgroups: |
| | elem.append(bitgroup) |
| | return elem |
| |
|
| |
|
| | def define_fixed_array_type(array_type): |
| | attrs = dict() |
| | attrs['size'] = str(array_type.size) |
| | elem = ET.Element('FixedArrayType', attrs) |
| | item_type_elem = ET.SubElement(elem, 'item-type') |
| | item_type_elem.append(reference_type(array_type.itemtype)) |
| | return elem |
| |
|
| |
|
| | def define_variable_length_array_type(array_type): |
| | elem = ET.Element('VariableLengthArrayType') |
| | count_type_elem = ET.SubElement(elem, 'count-type') |
| | count_type_elem.append(reference_type(array_type.counttype)) |
| | item_type_elem = ET.SubElement(elem, 'item-type') |
| | item_type_elem.append(reference_type(array_type.itemtype)) |
| | return elem |
| |
|
| |
|
| | def define_x_array_type(t): |
| | elem = ET.Element('XArrayType', dict(size=t.count_reference.__doc__)) |
| | item_type_elem = ET.SubElement(elem, 'item-type') |
| | item_type_elem.append(reference_type(t.itemtype)) |
| | return elem |
| |
|
| |
|
| | def define_selective_type(t): |
| | elem = ET.Element('SelectiveType', |
| | dict(selector=t.selector_reference.__doc__)) |
| | for k, v in t.selections.items(): |
| | sel = ET.SubElement(elem, 'selection', |
| | dict(when=make_condition_value(k))) |
| | sel.append(reference_type(v)) |
| | return elem |
| |
|
| |
|
| | def reference_type(t): |
| | attrs = dict() |
| | attrs['name'] = t.__name__ |
| | attrs['meta'] = type(t).__name__ |
| | elem = ET.Element('type-ref', attrs) |
| |
|
| | from hwp5.dataio import EnumType |
| | from hwp5.dataio import FlagsType |
| | from hwp5.dataio import FixedArrayType |
| | from hwp5.dataio import X_ARRAY |
| | from hwp5.dataio import VariableLengthArrayType |
| | from hwp5.dataio import SelectiveType |
| | if isinstance(t, EnumType): |
| | if t.scoping_struct: |
| | elem.attrib['scope'] = t.scoping_struct.__name__ |
| | elif isinstance(t, FlagsType): |
| | elem.append(define_flags_type(t)) |
| | elif isinstance(t, FixedArrayType): |
| | elem.append(define_fixed_array_type(t)) |
| | elif isinstance(t, X_ARRAY): |
| | elem.append(define_x_array_type(t)) |
| | elif isinstance(t, VariableLengthArrayType): |
| | elem.append(define_variable_length_array_type(t)) |
| | elif isinstance(t, SelectiveType): |
| | elem.append(define_selective_type(t)) |
| | return elem |
| |
|
| |
|
| | def referenced_types_by_member(member): |
| | t = member.get('type') |
| | if t: |
| | yield t |
| | for x in direct_referenced_types(t): |
| | yield x |
| |
|
| |
|
| | def define_member(struct_type, member): |
| | attrs = dict(name=member['name']) |
| |
|
| | version = member.get('version') |
| | if version: |
| | version = '.'.join(str(x) for x in version) |
| | attrs['version'] = version |
| |
|
| | elem = ET.Element('member', attrs) |
| |
|
| | t = member.get('type') |
| | if t: |
| | elem.append(reference_type(t)) |
| |
|
| | condition = member.get('condition') |
| | if condition: |
| | condition = condition.__doc__ or condition.__name__ or '' |
| | condition = condition.strip() |
| | condition_elem = ET.Element('condition') |
| | condition_elem.text = condition |
| | elem.append(condition_elem) |
| |
|
| | return elem |
| |
|
| |
|
| | def direct_referenced_types(t): |
| | from hwp5.dataio import FlagsType |
| | from hwp5.dataio import FixedArrayType |
| | from hwp5.dataio import X_ARRAY |
| | from hwp5.dataio import VariableLengthArrayType |
| | from hwp5.dataio import StructType |
| | from hwp5.dataio import SelectiveType |
| | if isinstance(t, FlagsType): |
| | for k, desc in t.bitfields.items(): |
| | yield desc.valuetype |
| | elif isinstance(t, FixedArrayType): |
| | yield t.itemtype |
| | elif isinstance(t, X_ARRAY): |
| | yield t.itemtype |
| | elif isinstance(t, VariableLengthArrayType): |
| | yield t.counttype |
| | yield t.itemtype |
| | elif isinstance(t, StructType): |
| | if 'members' in t.__dict__: |
| | for member in t.members: |
| | for x in referenced_types_by_member(member): |
| | yield x |
| | elif isinstance(t, SelectiveType): |
| | for selection in t.selections.values(): |
| | yield selection |
| |
|
| |
|
| | def referenced_types_by_struct_type(t): |
| | if 'members' in t.__dict__: |
| | for member in t.members: |
| | for x in referenced_types_by_member(member): |
| | yield x |
| |
|
| |
|
| | def extension_sort_key(cls): |
| | import inspect |
| | key = inspect.getmro(cls) |
| | key = list(x.__name__ for x in key) |
| | key = tuple(reversed(key)) |
| | return key |
| |
|
| |
|
| | def sort_extensions(extension_types): |
| | extension_types = extension_types.items() |
| | extension_types = list((extension_sort_key(cls), (k, cls)) |
| | for k, cls in extension_types) |
| | extension_types.sort() |
| | extension_types = ((k, cls) for sort_key, (k, cls) in extension_types) |
| | return extension_types |
| |
|
| |
|
| | def extensions_of_tag_model(tag_model): |
| | extension_types = getattr(tag_model, 'extension_types', None) |
| | if extension_types: |
| | extension_types = sort_extensions(extension_types) |
| | key_condition = getattr(tag_model, 'get_extension_key', None) |
| | key_condition = key_condition.__doc__.strip() |
| | for key, extension_type in extension_types: |
| | yield (key_condition, key), extension_type |
| |
|
| |
|
| | def define_struct_type(t): |
| | elem = ET.Element('StructType', |
| | dict(name=t.__name__)) |
| | for extend in get_extends(t): |
| | elem.append(define_extends(extend)) |
| |
|
| | if 'members' in t.__dict__: |
| | for member in t.members: |
| | elem.append(define_member(t, member)) |
| | return elem |
| |
|
| |
|
| | def define_tag_model(tag_id): |
| | from hwp5.tagids import tagnames |
| | from hwp5.binmodel import tag_models |
| | tag_name = tagnames[tag_id] |
| | tag_model = tag_models[tag_id] |
| | elem = ET.Element('TagModel', |
| | dict(tag_id=str(tag_id), |
| | name=tag_name)) |
| | elem.append(define_base_type(tag_model)) |
| | for (name, value), extension_type in extensions_of_tag_model(tag_model): |
| | elem.append(define_extension(extension_type, |
| | tag_model, |
| | name, |
| | value)) |
| | return elem |
| |
|
| |
|
| | def define_base_type(t): |
| | elem = ET.Element('base', dict(name=t.__name__)) |
| | return elem |
| |
|
| |
|
| | def make_condition_value(value): |
| | from hwp5.dataio import EnumType |
| | if isinstance(value, tuple): |
| | value = tuple(make_condition_value(v) for v in value) |
| | return '('+', '.join(value)+')' |
| | elif isinstance(type(value), EnumType): |
| | return repr(value) |
| | elif isinstance(value, type): |
| | return value.__name__ |
| | else: |
| | return str(value) |
| |
|
| |
|
| | def define_extension(t, up_to_type, name, value): |
| | attrs = dict(name=t.__name__) |
| | elem = ET.Element('extension', attrs) |
| | condition = ET.Element('condition') |
| | condition.text = name + ' == ' + make_condition_value(value) |
| | elem.append(condition) |
| |
|
| | for extend in get_extends(t, up_to_type): |
| | elem.append(define_extends(extend)) |
| |
|
| | if 'members' in t.__dict__: |
| | for member in t.members: |
| | elem.append(define_member(t, member)) |
| | return elem |
| |
|
| |
|
| | def get_extends(t, up_to_type=None): |
| | def take_up_to(up_to_type, mro): |
| | for t in mro: |
| | yield t |
| | if t is up_to_type: |
| | return |
| | from itertools import takewhile |
| |
|
| | import inspect |
| | mro = inspect.getmro(t) |
| | mro = mro[1:] |
| | |
| | mro = takewhile(lambda cls: cls is not up_to_type, mro) |
| | mro = (t for t in mro if 'members' in t.__dict__) |
| | mro = list(mro) |
| | mro = reversed(mro) |
| | return mro |
| |
|
| |
|
| | def define_extends(t): |
| | attrs = dict(name=t.__name__) |
| | elem = ET.Element('extends', attrs) |
| | return elem |
| |
|
| |
|
| | def define_primitive_type(t): |
| | attrs = dict(name=t.__name__) |
| | fixed_size = getattr(t, 'fixed_size', None) |
| | if fixed_size: |
| | attrs['size'] = str(fixed_size) |
| |
|
| | elem = ET.Element('PrimitiveType', attrs) |
| |
|
| | binfmt = getattr(t, 'binfmt', None) |
| | if binfmt: |
| | binfmt_elem = ET.Element('binfmt') |
| | binfmt_elem.text = binfmt |
| | elem.append(binfmt_elem) |
| | return elem |
| |
|
| |
|
| | def main(): |
| | from docopt import docopt |
| | from hwp5 import __version__ |
| | from hwp5.proc import rest_to_docopt |
| |
|
| | doc = rest_to_docopt(__doc__) |
| | args = docopt(doc, version=__version__) |
| |
|
| | if '--loglevel' in args: |
| | loglevel = args['--loglevel'].lower() |
| | loglevel = dict(error=logging.ERROR, |
| | warning=logging.WARNING, |
| | info=logging.INFO, |
| | debug=logging.DEBUG).get(loglevel, logging.WARNING) |
| | logger.setLevel(loglevel) |
| | logger.addHandler(logging.StreamHandler()) |
| |
|
| | from hwp5 import binmodel |
| | import sys |
| |
|
| | enum_types = set() |
| | extensions = set() |
| | struct_types = set() |
| | primitive_types = set() |
| |
|
| | root = ET.Element('binspec', dict(version=__version__)) |
| | for tag_id, tag_model in binmodel.tag_models.items(): |
| | logger.debug('TAG_MODEL: %s', tag_model.__name__) |
| | root.append(define_tag_model(tag_id)) |
| | struct_types.add(tag_model) |
| |
|
| | from hwp5.dataio import EnumType |
| | from hwp5.dataio import StructType |
| | from hwp5.dataio import PrimitiveType |
| | for t in referenced_types_by_struct_type(tag_model): |
| | if isinstance(t, EnumType): |
| | enum_types.add(t) |
| | if isinstance(t, StructType): |
| | struct_types.add(t) |
| | if isinstance(t, PrimitiveType): |
| | logger.debug('- PrimitiveType: %s', t.__name__) |
| | primitive_types.add(t) |
| |
|
| | for _, t in extensions_of_tag_model(tag_model): |
| | extensions.add(t) |
| |
|
| | for t in extensions: |
| | struct_types.add(t) |
| | for extends in get_extends(t): |
| | struct_types.add(extends) |
| |
|
| | for struct_type in struct_types: |
| | for t in referenced_types_by_struct_type(struct_type): |
| | if isinstance(t, EnumType): |
| | enum_types.add(t) |
| | if isinstance(t, PrimitiveType): |
| | primitive_types.add(t) |
| |
|
| | enum_types = list((t.__name__, t) for t in enum_types) |
| | enum_types.sort() |
| | enum_types = (t for name, t in enum_types) |
| | for t in enum_types: |
| | root.append(define_enum_type(t)) |
| |
|
| | struct_types = list((t.__name__, t) for t in struct_types) |
| | struct_types.sort() |
| | struct_types = (t for name, t in struct_types) |
| | for t in struct_types: |
| | root.append(define_struct_type(t)) |
| |
|
| | primitive_types = list((t.__name__, t) for t in primitive_types) |
| | primitive_types.sort() |
| | primitive_types = (t for name, t in primitive_types) |
| | for t in primitive_types: |
| | root.append(define_primitive_type(t)) |
| |
|
| | doc = ET.ElementTree(root) |
| | doc.write(sys.stdout, 'utf-8') |
| |
|