#!/usr/bin/env python # # competh.py # ASN.1 to Ethereal dissector compiler # 2004 Tomas Kukosa # # $Id$ # """ASN.1 to Ethereal dissector compiler""" # # Compiler from ASN.1 specification to the Ethereal dissector # # Based on ASN.1 to Python compiler from Aaron S. Lav's PyZ3950 package licensed under the X Consortium license # http://www.pobox.com/~asl2/software/PyZ3950/ # (ASN.1 to Python compiler functionality is broken but not removed, it could be revived if necessary) # # It requires Dave Beazley's PLY parsing package licensed under the LGPL (tested with version 1.6) # http://www.dabeaz.com/ply/ # # # ITU-T Recommendation X.680 (07/2002), # Information technology - Abstract Syntax Notation One (ASN.1): Specification of basic notation # # ITU-T Recommendation X.682 (07/2002), # Information technology - Abstract Syntax Notation One (ASN.1): Constraint specification # # ITU-T Recommendation X.683 (07/2002), # Information technology - Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 specifications # from __future__ import nested_scopes import warnings import re import sys import os import os.path import time import getopt import __main__ # XXX blech! import lex import yacc # OID name -> number conversion table oid_names = { '/itu-t' : 0, '0/recommendation' : 0, '0.0/h' : 8, '0.0/q' : 17, '0.0/x' : 24, '0/question' : 1, '0/administration' : 2, '0/network-operator' : 3, '0/identified-organization' : 4, '0/r-recommendation' : 5, '0/data' : 9, '/iso' : 1, '1/standard' : 0, '1/registration-authority' : 1, '1/member-body' : 2, '1/identified-organization' : 3, '/joint-iso-itu-t' : 2, '2/presentation' : 0, '2/asn1' : 1, '2/association-control' : 2, '2/reliable-transfer' : 3, '2/remote-operations' : 4, '2/ds' : 5, '2/mhs' : 6, '2/ccr' : 7, '2/oda' : 8, '2/ms' : 9, } def asn2c(id): return id.replace('-', '_').replace('.', '_') class LexError(Exception): pass class ParseError(Exception): pass # 11 ASN.1 lexical items static_tokens = { r'::=' : 'ASSIGNMENT', # 11.16 Assignment lexical item r'\.\.' : 'RANGE', # 11.17 Range separator r'\.\.\.' : 'ELLIPSIS', # 11.18 Ellipsis #r'\[\[' : 'LVERBRACK', # 11.19 Left version brackets #r'\]\]' : 'RVERBRACK', # 11.20 Right version brackets # 11.26 Single character lexical items r'\{' : 'LBRACE', r'\}' : 'RBRACE', r'<' : 'LT', #r'>' : 'GT', r',' : 'COMMA', r'\.' : 'DOT', r'\(' : 'LPAREN', r'\)' : 'RPAREN', r'\[' : 'LBRACK', r'\]' : 'RBRACK', r'-' : 'MINUS', r':' : 'COLON', #r'=' : 'EQ', #r'"' : 'QUOTATION', #r"'" : 'APOSTROPHE', r';' : 'SEMICOLON', #r'@' : 'AT', #r'\!' : 'EXCLAMATION', #r'\^' : 'CIRCUMFLEX' } # 11.27 Reserved words # all keys in reserved_words must start w/ upper case reserved_words = { 'TAGS' : 'TAGS', 'BOOLEAN' : 'BOOLEAN', 'INTEGER' : 'INTEGER', 'BIT' : 'BIT', 'CHARACTER' : 'CHARACTER', 'STRING' : 'STRING', 'OCTET' : 'OCTET', 'NULL' : 'NULL', 'SEQUENCE': 'SEQUENCE', 'OF' : 'OF', 'SET' : 'SET', 'IMPLICIT': 'IMPLICIT', 'CHOICE' : 'CHOICE', 'ANY' : 'ANY', # 'EXTERNAL' : 'EXTERNAL', # XXX added over base 'OPTIONAL':'OPTIONAL', 'DEFAULT' : 'DEFAULT', 'COMPONENTS': 'COMPONENTS', 'UNIVERSAL' : 'UNIVERSAL', 'APPLICATION' : 'APPLICATION', 'PRIVATE' : 'PRIVATE', 'TRUE' : 'TRUE', 'FALSE' : 'FALSE', 'BEGIN' : 'BEGIN', 'END' : 'END', 'DEFINITIONS' : 'DEFINITIONS', 'EXPLICIT' : 'EXPLICIT', 'ENUMERATED' : 'ENUMERATED', 'EXPORTS' : 'EXPORTS', 'IMPORTS' : 'IMPORTS', 'REAL' : 'REAL', 'INCLUDES': 'INCLUDES', 'MIN' : 'MIN', 'MAX' : 'MAX', 'SIZE' : 'SIZE', 'FROM' : 'FROM', 'PATTERN' : 'PATTERN', 'WITH' : 'WITH', 'COMPONENT': 'COMPONENT', 'PRESENT' : 'PRESENT', 'ABSENT' : 'ABSENT', # 'DEFINED' : 'DEFINED', 'CONSTRAINED' : 'CONSTRAINED', 'BY' : 'BY', 'PLUS-INFINITY' : 'PLUS_INFINITY', 'MINUS-INFINITY' : 'MINUS_INFINITY', 'GeneralizedTime' : 'GeneralizedTime', 'UTCTime' : 'UTCTime', 'ObjectDescriptor': 'ObjectDescriptor', 'AUTOMATIC': 'AUTOMATIC', 'OBJECT': 'OBJECT', 'IDENTIFIER': 'IDENTIFIER', # 'OPERATION' : 'OPERATION', # 'ARGUMENT' : 'ARGUMENT', # 'RESULT' : 'RESULT', # 'ERRORS' : 'ERRORS', # 'LINKED' : 'LINKED', # 'ERROR' : 'ERROR', # 'PARAMETER' : 'PARAMETER', # 'BIND' : 'BIND', # 'BIND-ERROR' : 'BIND_ERROR', # 'UNBIND' : 'UNBIND', # 'APPLICATION-CONTEXT' : 'AC', # 'APPLICATON-SERVICE-ELEMENTS' : 'ASES', # 'REMOTE' : 'REMOTE', # 'INITIATOR' : 'INITIATOR', # 'RESPONDER' : 'RESPONDER', # 'APPLICATION-SERVICE-ELEMENT' : 'ASE', # 'OPERATIONS' : None, # 'EXTENSION-ATTRIBUTE' : 'EXTENSION_ATTRIBUTE', # 'EXTENSIONS' : None, # 'CHOSEN' : None, # 'EXTENSION' : None, # 'CRITICAL': None, # 'FOR' : None, # 'SUBMISSION' : None, # 'DELIVERY' : None, # 'TRANSFER' : None, # 'OBJECT' : None, # 'PORTS' : None, # 'PORT' : None, # r'ABSTRACT\s*OPERATIONS' : 'ABSTR_OPS', # 'REFINE' : None, # 'AS' : None, # 'RECURRING' : None } for k in static_tokens.keys (): if static_tokens [k] == None: static_tokens [k] = k StringTypes = ['Numeric', 'Printable', 'IA5', 'BMP', 'Universal', 'UTF8', 'Teletex', 'T61', 'Videotex', 'Graphic', 'ISO646', 'Visible', 'General'] for s in StringTypes: reserved_words[s + 'String'] = s + 'String' tokens = static_tokens.values() \ + reserved_words.values() \ + ['BSTRING', 'HSTRING', 'QSTRING', 'UCASE_IDENT', 'LCASE_IDENT', 'NUMBER', 'PYQUOTE'] for (k, v) in static_tokens.items (): __main__.__dict__['t_' + v] = k # 11.10 Binary strings def t_BSTRING (t): r"'[01]*'B" return t # 11.12 Hexadecimal strings def t_HSTRING (t): r"'[0-9A-Fa-f]*'H" return t def t_QSTRING (t): r'"([^"]|"")*"' return t # XXX might want to un-"" def t_UCASE_IDENT (t): r"[A-Z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-' t.type = reserved_words.get(t.value, "UCASE_IDENT") return t def t_LCASE_IDENT (t): r"[a-z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-' return t # 11.8 Numbers def t_NUMBER (t): r"0|([1-9][0-9]*)" return t # 11.9 Real numbers # not supported yet # 11.6 Comments pyquote_str = 'PYQUOTE' def t_COMMENT(t): r"--(-[^\-\n]|[^\-\n])*(--|\n|-\n|$|-$)" if (t.value.find("\n") >= 0) : t.lineno += 1 if t.value[2:2+len (pyquote_str)] == pyquote_str: t.value = t.value[2+len(pyquote_str):] t.value = t.value.lstrip () t.type = pyquote_str return t return None t_ignore = " \t\r" def t_NEWLINE(t): r'\n+' t.lineno += t.value.count("\n") def t_error(t): print "Error", t.value[:100], t.lineno raise LexError class Ctx: def __init__ (self, defined_dict, indent = 0): self.tags_def = 'EXPLICIT' # default = explicit self.indent_lev = 0 self.assignments = {} self.dependencies = {} self.pyquotes = [] self.defined_dict = defined_dict self.name_ctr = 0 def spaces (self): return " " * (4 * self.indent_lev) def indent (self): self.indent_lev += 1 def outdent (self): self.indent_lev -= 1 assert (self.indent_lev >= 0) def register_assignment (self, ident, val, dependencies): if self.assignments.has_key (ident): raise "Duplicate assignment for " + ident if self.defined_dict.has_key (ident): raise "cross-module duplicates for " + ident self.defined_dict [ident] = 1 self.assignments[ident] = val self.dependencies [ident] = dependencies return "" # return "#%s depends on %s" % (ident, str (dependencies)) def register_pyquote (self, val): self.pyquotes.append (val) return "" def output_assignments (self): already_output = {} text_list = [] assign_keys = self.assignments.keys() to_output_count = len (assign_keys) while 1: any_output = 0 for (ident, val) in self.assignments.iteritems (): if already_output.has_key (ident): continue ok = 1 for d in self.dependencies [ident]: if (not already_output.has_key (d) and d in assign_keys): ok = 0 if ok: text_list.append ("%s=%s" % (ident, self.assignments [ident])) already_output [ident] = 1 any_output = 1 to_output_count -= 1 assert (to_output_count >= 0) if not any_output: if to_output_count == 0: break # OK, we detected a cycle cycle_list = [] for ident in self.assignments.iterkeys (): if not already_output.has_key (ident): depend_list = [d for d in self.dependencies[ident] if d in assign_keys] cycle_list.append ("%s(%s)" % (ident, ",".join (depend_list))) text_list.append ("# Cycle XXX " + ",".join (cycle_list)) for (ident, val) in self.assignments.iteritems (): if not already_output.has_key (ident): text_list.append ("%s=%s" % (ident, self.assignments [ident])) break return "\n".join (text_list) def output_pyquotes (self): return "\n".join (self.pyquotes) def make_new_name (self): self.name_ctr += 1 return "_compiler_generated_name_%d" % (self.name_ctr,) #--- EthCtx ------------------------------------------------------------------- class EthCtx: def __init__(self, conform, output, indent = 0): self.tags_def = 'EXPLICIT' # default = explicit self.conform = conform self.output = output self.assign = {} self.assign_ord = [] self.field = {} self.pdu_ord = [] self.field_ord = [] self.type = {} self.type_ord = [] self.type_imp = [] self.type_dep = {} self.vassign = {} self.vassign_ord = [] self.value = {} self.value_ord = [] self.value_imp = [] def encp(self): # encoding protocol encp = self.encoding if (self.new): encp += 'n' return encp # API type def OAPI(self): return not self.new def NAPI(self): return self.new def Per(self): return self.encoding == 'per' def OPer(self): return self.OAPI() and self.Per() def NPer(self): return self.NAPI() and self.Per() def Ber(self): return self.encoding == 'ber' def OBer(self): return self.OAPI() and self.Ber() def NBer(self): return self.NAPI() and self.Ber() def dbg(self, d): if (self.dbgopt.find(d) >= 0): return True else: return False def eth_get_type_attr(self, type): types = [type] while (not self.type[type]['import'] and self.type[type]['val'].type == 'Type_Ref'): type = self.type[type]['val'].val types.append(type) attr = {} while len(types): t = types.pop() attr.update(self.type[t]['attr']) attr.update(self.eth_type[self.type[t]['ethname']]['attr']) return attr #--- eth_reg_assign --------------------------------------------------------- def eth_reg_assign(self, ident, val): #print "eth_reg_assign(ident='%s')" % (ident) if self.assign.has_key(ident): raise "Duplicate assignment for " + ident self.assign[ident] = val self.assign_ord.append(ident) #--- eth_reg_vassign -------------------------------------------------------- def eth_reg_vassign(self, vassign): ident = vassign.ident #print "eth_reg_vassign(ident='%s')" % (ident) if self.vassign.has_key(ident): raise "Duplicate value assignment for " + ident self.vassign[ident] = vassign self.vassign_ord.append(ident) #--- eth_import_type -------------------------------------------------------- def eth_import_type(self, ident, mod, proto): #print "eth_import_type(ident='%s', mod='%s', prot='%s')" % (ident, mod, prot) if self.type.has_key(ident): raise "Duplicate type for " + ident self.type[ident] = {'import' : mod, 'proto' : proto, 'ethname' : '' } self.type[ident]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE', 'STRINGS' : 'NULL', 'BITMASK' : '0' } self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident)) self.type_imp.append(ident) #--- eth_import_value ------------------------------------------------------- def eth_import_value(self, ident, mod, proto): #print "eth_import_value(ident='%s', mod='%s', prot='%s')" % (ident, mod, prot) if self.type.has_key(ident): raise "Duplicate value for " + ident self.value[ident] = {'import' : mod, 'proto' : proto, 'ethname' : ''} self.value_imp.append(ident) #--- eth_dep_add ------------------------------------------------------------ def eth_dep_add(self, type, dep): if self.type_dep.has_key(type): self.type_dep[type].append(dep) else: self.type_dep[type] = [dep] #--- eth_reg_type ----------------------------------------------------------- def eth_reg_type(self, ident, val): #print "eth_reg_type(ident='%s')" % (ident) if self.type.has_key(ident): raise "Duplicate type for " + ident self.type[ident] = { 'val' : val, 'import' : None } if len(ident.split('/')) > 1: self.type[ident]['tname'] = val.eth_tname() else: self.type[ident]['tname'] = asn2c(ident) self.type[ident]['export'] = self.conform.use_item('EXPORTS', ident) self.type[ident]['user_def'] = self.conform.use_item('USER_DEFINED', ident) self.type[ident]['no_emit'] = self.conform.use_item('NO_EMIT', ident) self.type[ident]['tname'] = self.conform.use_item('TYPE_RENAME', ident, val_dflt=self.type[ident]['tname']) self.type[ident]['ethname'] = '' if val.type == 'Type_Ref': self.type[ident]['attr'] = {} else: (ftype, display) = val.eth_ftype(self) self.type[ident]['attr'] = { 'TYPE' : ftype, 'DISPLAY' : display, 'STRINGS' : val.eth_strings(), 'BITMASK' : '0' } self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident)) self.type_ord.append(ident) #--- eth_reg_value ---------------------------------------------------------- def eth_reg_value(self, ident, type, value): #print "eth_reg_value(ident='%s')" % (ident) if self.value.has_key(ident): raise "Duplicate value for " + ident self.value[ident] = { 'import' : None, 'proto' : self.proto, 'type' : type, 'value' : value } self.value[ident]['export'] = self.conform.use_item('EXPORTS', ident) self.value[ident]['ethname'] = '' self.value_ord.append(ident) #--- eth_reg_field ---------------------------------------------------------- def eth_reg_field(self, ident, type, idx='', parent=None, impl=False, pdu=None): #print "eth_reg_field(ident='%s', type='%s')" % (ident, type) if self.field.has_key(ident): raise "Duplicate field for " + ident self.field[ident] = {'type' : type, 'idx' : idx, 'impl' : impl, 'pdu' : pdu, 'modified' : '', 'attr' : {} } if self.conform.check_item('FIELD_ATTR', ident): self.field[ident]['modified'] = '#' + str(id(self)) self.field[ident]['attr'].update(self.conform.use_item('FIELD_ATTR', ident)) if (pdu): self.pdu_ord.append(ident) else: self.field_ord.append(ident) if parent: self.eth_dep_add(parent, type) #--- eth_prepare ------------------------------------------------------------ def eth_prepare(self): self.eproto = asn2c(self.proto) #--- dummy types/fields for PDU registration --- nm = 'NULL' if (self.conform.check_item('PDU', nm)): self.eth_reg_type('_dummy/'+nm, NullType()) self.eth_reg_field(nm, '_dummy/'+nm, pdu=self.conform.use_item('PDU', nm)) #--- types ------------------- self.eth_type = {} self.eth_type_ord = [] self.eth_export_ord = [] self.eth_type_dupl = {} self.named_bit = [] for t in self.type_imp: nm = asn2c(t) self.eth_type[nm] = { 'import' : self.type[t]['import'], 'proto' : asn2c(self.type[t]['proto']), 'attr' : {}, 'ref' : []} self.type[t]['ethname'] = nm for t in self.type_ord: nm = self.type[t]['tname'] if ((nm.find('#') >= 0) or ((len(t.split('/'))>1) and (self.conform.get_fn_presence(t) or self.conform.check_item('FN_PARS', t)) and not self.conform.check_item('TYPE_RENAME', t))): if len(t.split('/')) == 2 and t.split('/')[1] == '_item': # Sequnce of type at the 1st level nm = t.split('/')[0] + t.split('/')[1] elif t.split('/')[-1] == '_item': # Sequnce of type at next levels nm = 'T_' + t.split('/')[-2] + t.split('/')[-1] else: nm = 'T_' + t.split('/')[-1] nm = asn2c(nm) if self.eth_type.has_key(nm): if self.eth_type_dupl.has_key(nm): self.eth_type_dupl[nm].append(t) else: self.eth_type_dupl[nm] = [self.eth_type[nm]['ref'][0], t] nm += str(len(self.eth_type_dupl[nm])-1) if self.eth_type.has_key(nm): self.eth_type[nm]['ref'].append(t) else: self.eth_type_ord.append(nm) self.eth_type[nm] = { 'import' : None, 'proto' : self.eproto, 'export' : 0, 'user_def' : 0x03, 'no_emit' : 0x03, 'val' : self.type[t]['val'], 'attr' : {}, 'ref' : [t]} self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm)) self.type[t]['ethname'] = nm if (not self.eth_type[nm]['export'] and self.type[t]['export']): # new export self.eth_export_ord.append(nm) self.eth_type[nm]['export'] |= self.type[t]['export'] self.eth_type[nm]['user_def'] &= self.type[t]['user_def'] self.eth_type[nm]['no_emit'] &= self.type[t]['no_emit'] if self.type[t]['attr'].get('STRINGS') == '$$': self.eth_type[nm]['attr']['STRINGS'] = 'VALS(%s)' % (self.eth_vals_nm(nm)) for t in self.eth_type_ord: bits = self.eth_type[t]['val'].eth_named_bits() if (bits): for (val, id) in bits: self.named_bit.append({'name' : id, 'val' : val, 'ethname' : 'hf_%s_%s_%s' % (self.eproto, t, asn2c(id)), 'ftype' : 'FT_BOOLEAN', 'display' : '8', 'strings' : 'NULL', 'bitmask' : '0x'+('80','40','20','10','08','04','02','01')[val%8]}) if self.eth_type[t]['val'].eth_need_tree(): self.eth_type[t]['tree'] = "ett_%s_%s" % (self.eth_type[t]['proto'], t) else: self.eth_type[t]['tree'] = None #--- value dependencies ------------------- self.value_dep = {} for v in self.value_ord: if isinstance (self.value[v]['value'], Value): dep = self.value[v]['value'].get_dep() else: dep = self.value[v]['value'] if dep and self.value.has_key(dep): self.value_dep.setdefault(v, []).append(dep) #--- exports all necessary values for v in self.value_ord: if not self.value[v]['export']: continue deparr = self.value_dep.get(v, []) while deparr: d = deparr.pop() if not self.value[d]['import']: if not self.value[d]['export']: self.value[d]['export'] = 0x01 deparr.extend(self.value_dep.get(d, [])) #--- values ------------------- self.eth_value = {} self.eth_value_ord = [] for v in self.value_imp: nm = asn2c(v) self.eth_value[nm] = { 'import' : self.value[v]['import'], 'proto' : asn2c(self.value[v]['proto']), 'ref' : []} self.value[v]['ethname'] = nm for v in self.value_ord: nm = asn2c(v) self.eth_value[nm] = { 'import' : None, 'proto' : asn2c(self.value[v]['proto']), 'export' : self.value[v]['export'], 'ref' : [v] } if isinstance (self.value[v]['value'], Value): self.eth_value[nm]['value'] = self.value[v]['value'].to_str() else: self.eth_value[nm]['value'] = self.value[v]['value'] self.eth_value_ord.append(nm) self.value[v]['ethname'] = nm #--- fields ------------------------- self.eth_hf = {} self.eth_hf_ord = [] self.eth_hfpdu_ord = [] self.eth_hf_dupl = {} for f in (self.pdu_ord + self.field_ord): if len(f.split('/')) > 1 and f.split('/')[-1] == '_item': # Sequnce of type nm = f.split('/')[-2] + f.split('/')[-1] name = 'Item' else: nm = f.split('/')[-1] name = nm if (self.NAPI()): name += self.field[f]['idx'] abbrev = asn2c(nm) nm = self.conform.use_item('FIELD_RENAME', f, val_dflt=nm) nm = asn2c(nm) if (self.field[f]['pdu']): nm += '_PDU' t = self.field[f]['type'] if self.type.has_key(t): ethtype = self.type[t]['ethname'] else: # undefined type # dummy imported print "Dummy imported: ", t self.type[t] = {'import' : 'xxx', 'proto' : 'xxx', 'ethname' : t } self.type[t]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE', 'STRINGS' : 'NULL', 'BITMASK' : '0' } self.eth_type[t] = { 'import' : 'xxx', 'proto' : 'xxx' , 'attr' : {}, 'ref' : []} ethtype = t ethtypemod = ethtype + self.field[f]['modified'] if self.eth_hf.has_key(nm): if self.eth_hf_dupl.has_key(nm): if self.eth_hf_dupl[nm].has_key(ethtypemod): nm = self.eth_hf_dupl[nm][ethtypemod] self.eth_hf[nm]['ref'].append(f) self.field[f]['ethname'] = nm continue else: nmx = nm + str(len(self.eth_hf_dupl[nm])) self.eth_hf_dupl[nm][ethtype] = nmx nm = nmx else: if (self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified']) == ethtypemod: self.eth_hf[nm]['ref'].append(f) self.field[f]['ethname'] = nm continue else: self.eth_hf_dupl[nm] = {self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified'] : nm, \ ethtypemod : nm+'1'} nm += '1' if (self.field[f]['pdu']): self.eth_hfpdu_ord.append(nm) else: self.eth_hf_ord.append(nm) fullname = "hf_%s_%s" % (self.eproto, nm) attr = self.eth_get_type_attr(self.field[f]['type']).copy() attr.update(self.field[f]['attr']) attr['NAME'] = '"%s"' % name attr['ABBREV'] = abbrev attr.update(self.conform.use_item('EFIELD_ATTR', nm)) self.eth_hf[nm] = {'fullname' : fullname, 'pdu' : self.field[f]['pdu'], 'ethtype' : ethtype, 'modified' : self.field[f]['modified'], 'attr' : attr.copy(), 'ref' : [f]} self.field[f]['ethname'] = nm #--- type dependencies ------------------- self.eth_type_ord1 = [] self.eth_dep_cycle = [] self.dep_cycle_eth_type = {} x = {} # already emitted #print '# Dependency computation' for t in self.type_ord: if x.has_key(self.type[t]['ethname']): #print 'Continue: %s : %s' % (t, self.type[t]['ethname']) continue stack = [t] stackx = {t : self.type_dep.get(t, [])[:]} #print 'Push: %s : %s' % (t, str(stackx[t])) while stack: if stackx[stack[-1]]: # has dependencies d = stackx[stack[-1]].pop(0) if x.has_key(self.type[d]['ethname']) or self.type[d]['import']: continue if stackx.has_key(d): # cyclic dependency c = stack[:] c.reverse() c = [d] + c[0:c.index(d)+1] c.reverse() self.eth_dep_cycle.append(c) #print 'Cyclic: %s ' % (' -> '.join(c)) continue stack.append(d) stackx[d] = self.type_dep.get(d, [])[:] #print 'Push: %s : %s' % (d, str(stackx[d])) else: #print 'Pop: %s' % (stack[-1]) del stackx[stack[-1]] e = self.type[stack.pop()]['ethname'] if x.has_key(e): continue #print 'Add: %s' % (e) self.eth_type_ord1.append(e) x[e] = True i = 0 while i < len(self.eth_dep_cycle): t = self.type[self.eth_dep_cycle[i][0]]['ethname'] self.dep_cycle_eth_type.setdefault(t, []).append(i) i += 1 #--- value dependencies and export ------------------- self.eth_value_ord1 = [] self.eth_vexport_ord = [] for v in self.eth_value_ord: if self.eth_value[v]['export']: self.eth_vexport_ord.append(v) else: self.eth_value_ord1.append(v) #--- eth_vals_nm ------------------------------------------------------------ def eth_vals_nm(self, tname): out = "" if (not self.eth_type[tname]['export'] & 0x10): out += "%s_" % (self.eproto) out += "%s_vals" % (tname) return out #--- eth_vals --------------------------------------------------------------- def eth_vals(self, tname, vals): out = "" if (not self.eth_type[tname]['export'] & 0x02): out += "static " out += "const value_string %s[] = {\n" % (self.eth_vals_nm(tname)) for (val, id) in vals: out += ' { %3s, "%s" },\n' % (val, id) out += " { 0, NULL }\n};\n" return out #--- eth_bits --------------------------------------------------------------- def eth_bits(self, tname, bits): out = "" out += "static const " out += "asn_namedbit %s_bits[] = {\n" % (tname) for (val, id) in bits: out += ' { %2d, &hf_%s_%s_%s, -1, -1, "%s", NULL },\n' % (val, self.eproto, tname, asn2c(id), id) out += " { 0, NULL, 0, 0, NULL, NULL }\n};\n" return out #--- eth_type_fn_h ---------------------------------------------------------- def eth_type_fn_h(self, tname): out = "" if (not self.eth_type[tname]['export'] & 0x01): out += "static " out += "int " if (self.OBer()): out += "dissect_%s_%s(gboolean implicit_tag, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int hf_index)" % (self.eth_type[tname]['proto'], tname) elif (self.NPer()): out += "dissect_%s_%s(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int hf_index, proto_item **item, void *private_data)" % (self.eth_type[tname]['proto'], tname) elif (self.OPer()): out += "dissect_%s_%s(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int hf_index)" % (self.eth_type[tname]['proto'], tname) out += ";\n" return out #--- eth_fn_call ------------------------------------------------------------ def eth_fn_call(self, fname, ret=None, indent=2, par=None): out = indent * ' ' if (ret): if (ret == 'return'): out += 'return ' else: out += ret + ' = ' out += fname + '(' ind = len(out) for i in range(len(par)): if (i>0): out += ind * ' ' out += ', '.join(par[i]) if (i<(len(par)-1)): out += ',\n' out += ');\n' return out #--- eth_type_fn_hdr -------------------------------------------------------- def eth_type_fn_hdr(self, tname): out = '\n' if (not self.eth_type[tname]['export'] & 0x01): out += "static " out += "int\n" if (self.OBer()): out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname) elif (self.NPer()): out += "dissect_%s_%s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, proto_item **item, void *private_data) {\n" % (self.eth_type[tname]['proto'], tname) elif (self.OPer()): out += "dissect_%s_%s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index) {\n" % (self.eth_type[tname]['proto'], tname) if self.conform.get_fn_presence(tname): out += self.conform.get_fn_text(tname, 'FN_HDR') elif self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]): out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_HDR') return out #--- eth_type_fn_ftr -------------------------------------------------------- def eth_type_fn_ftr(self, tname): out = '\n' if self.conform.get_fn_presence(tname): out += self.conform.get_fn_text(tname, 'FN_FTR') elif self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]): out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_FTR') out += " return offset;\n" out += "}\n" return out #--- eth_type_fn_body ------------------------------------------------------- def eth_type_fn_body(self, tname, body, pars=None): out = body if self.conform.get_fn_body_presence(tname): out = self.conform.get_fn_text(tname, 'FN_BODY') elif self.conform.get_fn_body_presence(self.eth_type[tname]['ref'][0]): out = self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_BODY') if pars: out = out % pars return out #--- eth_output_hf ---------------------------------------------------------- def eth_output_hf (self): if not len(self.eth_hf_ord) and not len(self.eth_hfpdu_ord) and not len(self.named_bit): return fx = self.output.file_open('hf') for f in (self.eth_hfpdu_ord + self.eth_hf_ord): fx.write("%-50s/* %s */\n" % ("static int %s = -1; " % (self.eth_hf[f]['fullname']), self.eth_hf[f]['ethtype'])) if (self.named_bit): fx.write('/* named bits */\n') for nb in self.named_bit: fx.write("static int %s = -1;\n" % (nb['ethname'])) self.output.file_close(fx) #--- eth_output_hf_arr ------------------------------------------------------ def eth_output_hf_arr (self): if not len(self.eth_hf_ord) and not len(self.eth_hfpdu_ord) and not len(self.named_bit): return fx = self.output.file_open('hfarr') for f in (self.eth_hfpdu_ord + self.eth_hf_ord): if len(self.eth_hf[f]['ref']) == 1: blurb = '"' + self.eth_hf[f]['ref'][0] + '"' else: blurb = '""' attr = self.eth_hf[f]['attr'].copy() attr['ABBREV'] = '"%s.%s"' % (self.proto, attr['ABBREV']) if not attr.has_key('BLURB'): attr['BLURB'] = blurb fx.write(' { &%s,\n' % (self.eth_hf[f]['fullname'])) fx.write(' { %(NAME)s, %(ABBREV)s,\n' % attr) fx.write(' %(TYPE)s, %(DISPLAY)s, %(STRINGS)s, %(BITMASK)s,\n' % attr) fx.write(' %(BLURB)s, HFILL }},\n' % attr) for nb in self.named_bit: blurb = '' fx.write(' { &%s,\n' % (nb['ethname'])) fx.write(' { "%s", "%s.%s",\n' % (nb['name'], self.proto, nb['name'])) fx.write(' %s, %s, %s, %s,\n' % (nb['ftype'], nb['display'], nb['strings'], nb['bitmask'])) fx.write(' "%s", HFILL }},\n' % (blurb)) self.output.file_close(fx) #--- eth_output_ett --------------------------------------------------------- def eth_output_ett (self): fx = self.output.file_open('ett') fempty = True #fx.write("static gint ett_%s = -1;\n" % (self.eproto)) for t in self.eth_type_ord: if self.eth_type[t]['tree']: fx.write("static gint %s = -1;\n" % (self.eth_type[t]['tree'])) fempty = False self.output.file_close(fx, discard=fempty) #--- eth_output_ett_arr ----------------------------------------------------- def eth_output_ett_arr(self): fx = self.output.file_open('ettarr') fempty = True #fx.write(" &ett_%s,\n" % (self.eproto)) for t in self.eth_type_ord: if self.eth_type[t]['tree']: fx.write(" &%s,\n" % (self.eth_type[t]['tree'])) fempty = False self.output.file_close(fx, discard=fempty) #--- eth_output_export ------------------------------------------------------ def eth_output_export(self): if (not len(self.eth_export_ord)): return fx = self.output.file_open('exp', ext='h') for t in self.eth_export_ord: # vals if (self.eth_type[t]['export'] & 0x02) and self.eth_type[t]['val'].eth_has_vals(): if self.eth_type[t]['export'] & 0x08: fx.write("ETH_VAR_IMPORT ") else: fx.write("extern ") fx.write("const value_string %s[];\n" % (self.eth_vals_nm(t))) for t in self.eth_export_ord: # functions if (self.eth_type[t]['export'] & 0x01): fx.write(self.eth_type_fn_h(t)) self.output.file_close(fx) #--- eth_output_expcnf ------------------------------------------------------ def eth_output_expcnf(self): if (not len(self.eth_export_ord)): return fx = self.output.file_open('exp', ext='cnf') if self.Ber(): fx.write('#.IMPORT_TAG\n') for t in self.eth_export_ord: # tags if (self.eth_type[t]['export'] & 0x01): fx.write('%-24s ' % (t)) fx.write('%s %s\n' % self.eth_type[t]['val'].GetTag(self)) fx.write('#.END\n\n') fx.write('#.TYPE_ATTR\n') for t in self.eth_export_ord: # attributes if (self.eth_type[t]['export'] & 0x01): fx.write('%-24s ' % (t)) attr = self.eth_get_type_attr(self.eth_type[t]['ref'][0]).copy() fx.write('TYPE = %(TYPE)-9s DISPLAY = %(DISPLAY)-9s STRINGS = %(STRINGS)s BITMASK = %(BITMASK)s\n' % attr) fx.write('#.END\n\n') self.output.file_close(fx, keep_anyway=True) #--- eth_output_val ------------------------------------------------------ def eth_output_val(self): if (not len(self.eth_value_ord1)): return fx = self.output.file_open('val', ext='h') for v in self.eth_value_ord1: fx.write("#define %-30s %s\n" % (v, self.eth_value[v]['value'])) self.output.file_close(fx) #--- eth_output_valexp ------------------------------------------------------ def eth_output_valexp(self): if (not len(self.eth_vexport_ord)): return fx = self.output.file_open('valexp', ext='h') for v in self.eth_vexport_ord: fx.write("#define %-30s %s\n" % (v, self.eth_value[v]['value'])) self.output.file_close(fx) #--- eth_output_types ------------------------------------------------------- def eth_output_types(self): def out_field(f): t = self.eth_hf[f]['ethtype'] if (self.Ber()): x = {} for r in self.eth_hf[f]['ref']: x[self.field[r]['impl']] = self.field[r]['impl'] else: x = {False : False} x = x.values() x.sort() out = '' for i in x: if (i): postfix = '_impl' impl = 'TRUE' else: postfix = '' impl = 'FALSE' if (self.Ber()): if (i): postfix = '_impl'; impl = 'TRUE' else: postfix = ''; impl = 'FALSE' out += 'static int dissect_'+f+postfix+'(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {\n' par=((impl, 'tvb', 'offset', 'pinfo', 'tree', self.eth_hf[f]['fullname']),) else: out += 'static int dissect_'+f+'(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {\n' par=(('tvb', 'offset', 'pinfo', 'tree', self.eth_hf[f]['fullname']),) out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret='return', par=par) out += '}\n' return out #end out_field() def out_pdu(f): t = self.eth_hf[f]['ethtype'] is_new = self.eth_hf[f]['pdu']['new'] if self.field[self.eth_hf[f]['ref'][0]]['impl']: impl = 'TRUE' else: impl = 'FALSE' out = 'static ' if (is_new): out += 'int' else: out += 'void' out += ' dissect_'+f+'(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {\n' if (self.Ber()): par=((impl, 'tvb', '0', 'pinfo', 'tree', self.eth_hf[f]['fullname']),) else: par=(('tvb', '0', 'pinfo', 'tree', self.eth_hf[f]['fullname']),) ret = None if (is_new): ret = 'return' out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret=ret, par=par) out += '}\n' return out #end out_pdu() fx = self.output.file_open('fn') pos = fx.tell() if self.eth_dep_cycle: fx.write('/*--- Cyclic dependencies ---*/\n\n') i = 0 while i < len(self.eth_dep_cycle): t = self.type[self.eth_dep_cycle[i][0]]['ethname'] if self.dep_cycle_eth_type[t][0] != i: i += 1; continue fx.write(''.join(map(lambda i: '/* %s */\n' % ' -> '.join(self.eth_dep_cycle[i]), self.dep_cycle_eth_type[t]))) fx.write(self.eth_type_fn_h(t)) if (not self.new): fx.write('\n') for f in self.eth_hf_ord: if (self.eth_hf[f]['ethtype'] == t): fx.write(out_field(f)) fx.write('\n') i += 1 fx.write('\n') if (not self.new): # fields for imported types fx.write('/*--- Fields for imported types ---*/\n\n') for f in self.eth_hf_ord: if (self.eth_type[self.eth_hf[f]['ethtype']]['import']): fx.write(out_field(f)) fx.write('\n') for t in self.eth_type_ord1: if self.eth_type[t]['import']: continue if self.eth_type[t]['val'].eth_has_vals(): if self.eth_type[t]['no_emit'] & 0x02: pass elif self.eth_type[t]['user_def'] & 0x02: fx.write("extern const value_string %s[];\n" % (self.eth_vals_nm(t))) else: fx.write(self.eth_type[t]['val'].eth_type_vals(t, self)) if self.eth_type[t]['no_emit'] & 0x01: pass elif self.eth_type[t]['user_def'] & 0x01: fx.write(self.eth_type_fn_h(t)) else: fx.write(self.eth_type[t]['val'].eth_type_fn(self.eth_type[t]['proto'], t, self)) if (not self.new and not self.dep_cycle_eth_type.has_key(t)): for f in self.eth_hf_ord: if (self.eth_hf[f]['ethtype'] == t): fx.write(out_field(f)) fx.write('\n') if (len(self.eth_hfpdu_ord)): fx.write('/*--- PDUs ---*/\n\n') for f in self.eth_hfpdu_ord: if (self.eth_hf[f]['pdu']): fx.write(out_pdu(f)) fx.write('\n') fempty = pos == fx.tell() self.output.file_close(fx, discard=fempty) #--- eth_output_dis_hnd ----------------------------------------------------- def eth_output_dis_hnd(self): fx = self.output.file_open('dis-hnd') fempty = True for f in self.eth_hfpdu_ord: pdu = self.eth_hf[f]['pdu'] if (pdu and pdu['reg'] and not pdu['hidden']): dis = self.proto if (pdu['reg'] != '.'): dis += '.' + pdu['reg'] fx.write('static dissector_handle_t %s_handle;\n' % (asn2c(dis))) fempty = False fx.write('\n') self.output.file_close(fx, discard=fempty) #--- eth_output_dis_reg ----------------------------------------------------- def eth_output_dis_reg(self): fx = self.output.file_open('dis-reg') fempty = True for f in self.eth_hfpdu_ord: pdu = self.eth_hf[f]['pdu'] if (pdu and pdu['reg']): new_prefix = '' if (pdu['new']): new_prefix = 'new_' dis = self.proto if (pdu['reg'] != '.'): dis += '.' + pdu['reg'] fx.write(' %sregister_dissector("%s", dissect_%s, proto_%s);\n' % (new_prefix, dis, f, self.eproto)) if (not pdu['hidden']): fx.write(' %s_handle = find_dissector("%s");\n' % (asn2c(dis), dis)) fempty = False fx.write('\n') self.output.file_close(fx, discard=fempty) #--- eth_output_dis_tab ----------------------------------------------------- def eth_output_dis_tab(self): fx = self.output.file_open('dis-tab') fempty = True for k in self.conform.get_order('REGISTER'): reg = self.conform.use_item('REGISTER', k) if not self.field.has_key(reg['pdu']): continue f = self.field[reg['pdu']]['ethname'] pdu = self.eth_hf[f]['pdu'] new_prefix = '' if (pdu['new']): new_prefix = 'new_' if (reg['rtype'] in ('NUM', 'STR')): rstr = '' if (reg['rtype'] == 'STR'): rstr = '_string' if (pdu['reg']): dis = self.proto if (pdu['reg'] != '.'): dis += '.' + pdu['reg'] if (not pdu['hidden']): hnd = '%s_handle' % (asn2c(dis)) else: hnd = 'find_dissector("%s")' % (dis) else: hnd = '%screate_dissector_handle(dissect_%s, proto_%s)' % (new_prefix, f, self.eproto) fx.write(' dissector_add%s("%s", %s, %s);\n' % (rstr, reg['rtable'], reg['rport'], hnd)) elif (reg['rtype'] in ('BER', 'PER')): fx.write(' %sregister_%s_oid_dissector(%s, dissect_%s, proto_%s, %s);\n' % (new_prefix, reg['rtype'].lower(), reg['roid'], f, self.eproto, reg['roidname'])) fempty = False fx.write('\n') self.output.file_close(fx, discard=fempty) #--- dupl_report ----------------------------------------------------- def dupl_report(self): # types tmplist = self.eth_type_dupl.keys() tmplist.sort() for t in tmplist: msg = "The same type names for different types. Explicit type renaming is recommended.\n" msg += t + "\n" x = '' for tt in self.eth_type_dupl[t]: msg += " %-20s %s\n" % (t+str(x), tt) if not x: x = 1 else: x += 1 warnings.warn_explicit(msg, UserWarning, '', '') # fields tmplist = self.eth_hf_dupl.keys() tmplist.sort() for f in tmplist: msg = "The same field names for different types. Explicit field renaming is recommended.\n" msg += f + "\n" for tt in self.eth_hf_dupl[f].keys(): msg += " %-20s %-20s " % (self.eth_hf_dupl[f][tt], tt) msg += ", ".join(self.eth_hf[self.eth_hf_dupl[f][tt]]['ref']) msg += "\n" warnings.warn_explicit(msg, UserWarning, '', '') #--- EthCnf ------------------------------------------------------------------- class EthCnf: def __init__(self): self.tblcfg = {} self.table = {} self.order = {} self.fn = {} # Value name Default value Duplicity check Usage check self.tblcfg['EXPORTS'] = { 'val_nm' : 'flag', 'val_dflt' : 0, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['PDU'] = { 'val_nm' : 'attr', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['REGISTER'] = { 'val_nm' : 'attr', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['USER_DEFINED'] = { 'val_nm' : 'flag', 'val_dflt' : 0, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['NO_EMIT'] = { 'val_nm' : 'flag', 'val_dflt' : 0, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['MODULE_IMPORT'] = { 'val_nm' : 'proto', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['OMIT_ASSIGNMENT'] = { 'val_nm' : 'omit', 'val_dflt' : False, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['TYPE_RENAME'] = { 'val_nm' : 'eth_name', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['FIELD_RENAME'] = { 'val_nm' : 'eth_name', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['IMPORT_TAG'] = { 'val_nm' : 'ttag', 'val_dflt' : (), 'chk_dup' : True, 'chk_use' : False } self.tblcfg['FN_PARS'] = { 'val_nm' : 'pars', 'val_dflt' : {}, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['TYPE_ATTR'] = { 'val_nm' : 'attr', 'val_dflt' : {}, 'chk_dup' : True, 'chk_use' : False } self.tblcfg['ETYPE_ATTR'] = { 'val_nm' : 'attr', 'val_dflt' : {}, 'chk_dup' : True, 'chk_use' : False } self.tblcfg['FIELD_ATTR'] = { 'val_nm' : 'attr', 'val_dflt' : {}, 'chk_dup' : True, 'chk_use' : True } self.tblcfg['EFIELD_ATTR'] = { 'val_nm' : 'attr', 'val_dflt' : {}, 'chk_dup' : True, 'chk_use' : True } for k in self.tblcfg.keys() : self.table[k] = {} self.order[k] = [] def add_item(self, table, key, fn, lineno, **kw): if self.tblcfg[table]['chk_dup'] and self.table[table].has_key(key): warnings.warn_explicit("Duplicated %s for %s. Previous one is at %s:%d" % (table, key, self.table[table][key]['fn'], self.table[table][key]['lineno']), UserWarning, fn, lineno) return self.table[table][key] = {'fn' : fn, 'lineno' : lineno, 'used' : False} self.table[table][key].update(kw) self.order[table].append(key) def get_order(self, table): return self.order[table] def check_item(self, table, key): return self.table[table].has_key(key) def check_item_value(self, table, key, **kw): return self.table[table].has_key(key) and self.table[table][key].has_key(kw.get('val_nm', self.tblcfg[table]['val_nm'])) def use_item(self, table, key, **kw): vdflt = kw.get('val_dflt', self.tblcfg[table]['val_dflt']) if not self.table[table].has_key(key): return vdflt vname = kw.get('val_nm', self.tblcfg[table]['val_nm']) self.table[table][key]['used'] = True return self.table[table][key].get(vname, vdflt) def add_fn_line(self, name, ctx, line, fn, lineno): if not self.fn.has_key(name): self.fn[name] = {'FN_HDR' : None, 'FN_FTR' : None, 'FN_BODY' : None} if (self.fn[name][ctx]): self.fn[name][ctx]['text'] += line else: self.fn[name][ctx] = {'text' : line, 'used' : False, 'fn' : fn, 'lineno' : lineno} def get_fn_presence(self, name): #print "get_fn_presence('%s'):%s" % (name, str(self.fn.has_key(name))) #if self.fn.has_key(name): print self.fn[name] return self.fn.has_key(name) def get_fn_body_presence(self, name): return self.fn.has_key(name) and self.fn[name]['FN_BODY'] def get_fn_text(self, name, ctx): if (not self.fn.has_key(name)): return ''; if (not self.fn[name][ctx]): return ''; return self.fn[name][ctx]['text'] def add_pdu(self, par, is_new, fn, lineno): #print "add_pdu(par=%s, %s, %d)" % (str(par), fn, lineno) (reg, hidden) = (None, False) if (len(par) > 1): reg = par[1] if (reg and reg[0]=='@'): (reg, hidden) = (reg[1:], True) attr = {'new' : is_new, 'reg' : reg, 'hidden' : hidden} self.add_item('PDU', par[0], attr=attr, fn=fn, lineno=lineno) return def add_register(self, pdu, par, fn, lineno): #print "add_register(pdu=%s, par=%s, %s, %d)" % (pdu, str(par), fn, lineno) if (par[0] in ('N', 'NUM')): rtype = 'NUM'; (pmin, pmax) = (2, 2) elif (par[0] in ('S', 'STR')): rtype = 'STR'; (pmin, pmax) = (2, 2) elif (par[0] in ('B', 'BER')): rtype = 'BER'; (pmin, pmax) = (1, 2) elif (par[0] in ('P', 'PER')): rtype = 'PER'; (pmin, pmax) = (1, 2) else: warnings.warn_explicit("Unknown registration type '%s'" % (par[2]), UserWarning, fn, lineno); return if ((len(par)-1) < pmin): warnings.warn_explicit("Too few parameters for %s registration type. At least %d parameters are required" % (rtype, pmin), UserWarning, fn, lineno) return if ((len(par)-1) > pmax): warnings.warn_explicit("Too many parameters for %s registration type. Only %d parameters are allowed" % (rtype, pmax), UserWarning, fn, lineno) attr = {'pdu' : pdu, 'rtype' : rtype} if (rtype in ('NUM', 'STR')): attr['rtable'] = par[1] attr['rport'] = par[2] rkey = '/'.join([rtype, attr['rtable'], attr['rport']]) elif (rtype in ('BER', 'PER')): attr['roid'] = par[1] attr['roidname'] = '""' if (len(par)>=3): attr['roidname'] = par[2] rkey = '/'.join([rtype, attr['roid']]) self.add_item('REGISTER', rkey, attr=attr, fn=fn, lineno=lineno) def read(self, fn): def get_par(line, pmin, pmax, fn, lineno): par = line.split(None, pmax) for i in range(len(par)): if par[i] == '-': par[i] = None continue if par[i][0] == '#': par[i:] = [] break if len(par) < pmin: warnings.warn_explicit("Too few parameters. At least %d parameters are required" % (pmin), UserWarning, fn, lineno) return None if len(par) > pmax: warnings.warn_explicit("Too many parameters. Only %d parameters are allowed" % (pmax), UserWarning, fn, lineno) return par[0:pmax] return par def get_par_nm(line, pnum, fn, lineno): if pnum: par = line.split(None, pnum) else: par = [line,] for i in range(len(par)): if par[i][0] == '#': par[i:] = [] break if len(par) < pnum: warnings.warn_explicit("Too few parameters.", UserWarning, fn, lineno) return None if len(par) > pnum: nmpar = par[pnum] else: nmpar = '' nmpars = {} nmpar_first = re.compile(r'^\s*(?P[_A-Z][_A-Z0-9]*)\s*=\s*') nmpar_next = re.compile(r'\s+(?P[_A-Z][_A-Z0-9]*)\s*=\s*') nmpar_end = re.compile(r'\s*$') result = nmpar_first.search(nmpar) pos = 0 while result: k = result.group('attr') pos = result.end() result = nmpar_next.search(nmpar, pos) p1 = pos if result: p2 = result.start() else: p2 = nmpar_end.search(nmpar, pos).start() v = nmpar[p1:p2] nmpars[k] = v if len(par) > pnum: par[pnum] = nmpars return par f = open(fn, "r") directive = re.compile(r'^\s*#\.(?P[A-Z_]+)\s+') comment = re.compile(r'^\s*#[^.]') empty = re.compile(r'^\s*$') lineno = 0 ctx = None name = '' stack = [] while 1: line = f.readline() lineno += 1 if not line: f.close() if stack: frec = stack.pop() fn, f, lineno = frec['fn'], frec['f'], frec['lineno'] continue else: break if comment.search(line): continue result = directive.search(line) if result: # directive if result.group('name') in ('EXPORTS', 'PDU', 'PDU_NEW', 'REGISTER', 'REGISTER_NEW', 'USER_DEFINED', 'NO_EMIT', 'MODULE_IMPORT', 'OMIT_ASSIGNMENT', 'TYPE_RENAME', 'FIELD_RENAME', 'IMPORT_TAG', 'TYPE_ATTR', 'ETYPE_ATTR', 'FIELD_ATTR', 'EFIELD_ATTR'): ctx = result.group('name') elif result.group('name') in ('FN_HDR', 'FN_FTR', 'FN_BODY'): par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno) if not par: continue ctx = result.group('name') name = par[0] elif result.group('name') == 'FN_PARS': par = get_par(line[result.end():], 0, 1, fn=fn, lineno=lineno) ctx = result.group('name') if not par: name = None else: name = par[0] elif result.group('name') == 'INCLUDE': par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno) if not par: warnings.warn_explicit("INCLUDE requires parameter", UserWarning, fn, lineno) continue fname = os.path.join(os.path.split(fn)[0], par[0]) if (not os.path.exists(fname)): fname = par[0] fnew = open(fname, "r") stack.append({'fn' : fn, 'f' : f, 'lineno' : lineno}) fn, f, lineno = par[0], fnew, 0 elif result.group('name') == 'END': ctx = None else: warnings.warn_explicit("Unknown directive '%s'" % (result.group('name')), UserWarning, fn, lineno) continue if not ctx: if not empty.match(line): warnings.warn_explicit("Non-empty line in empty context", UserWarning, fn, lineno) elif ctx in ('EXPORTS', 'USER_DEFINED', 'NO_EMIT'): if empty.match(line): continue if ctx == 'EXPORTS': par = get_par(line, 1, 4, fn=fn, lineno=lineno) else: par = get_par(line, 1, 2, fn=fn, lineno=lineno) if not par: continue flag = 0x03 p = 2 if (len(par)>=2): if (par[1] == 'WITH_VALS'): flag = 0x03 elif (par[1] == 'WITHOUT_VALS'): flag = 0x01 elif (par[1] == 'ONLY_VALS'): flag = 0x02 elif (ctx == 'EXPORTS'): p = 1 else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[1]), UserWarning, fn, lineno) for i in range(p, len(par)): if (par[i] == 'ETH_VAR'): flag |= 0x08 elif (par[i] == 'NO_PROT_PREFIX'): flag |= 0x10 else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno) self.add_item(ctx, par[0], flag=flag, fn=fn, lineno=lineno) elif ctx in ('PDU', 'PDU_NEW'): if empty.match(line): continue par = get_par(line, 1, 5, fn=fn, lineno=lineno) if not par: continue is_new = False if (ctx == 'PDU_NEW'): is_new = True self.add_pdu(par[0:2], is_new, fn, lineno) if (len(par)>=3): self.add_register(par[0], par[2:5], fn, lineno) elif ctx in ('REGISTER', 'REGISTER_NEW'): if empty.match(line): continue par = get_par(line, 3, 4, fn=fn, lineno=lineno) if not par: continue if not self.check_item('PDU', par[0]): is_new = False if (ctx == 'REGISTER_NEW'): is_new = True self.add_pdu(par[0:1], is_new, fn, lineno) self.add_register(par[0], par[1:4], fn, lineno) elif ctx == 'MODULE_IMPORT': if empty.match(line): continue par = get_par(line, 2, 2, fn=fn, lineno=lineno) if not par: continue self.add_item('MODULE_IMPORT', par[0], proto=par[1], fn=fn, lineno=lineno) elif ctx == 'IMPORT_TAG': if empty.match(line): continue par = get_par(line, 3, 3, fn=fn, lineno=lineno) if not par: continue self.add_item('IMPORT_TAG', par[0], ttag=(par[1], par[2]), fn=fn, lineno=lineno) elif ctx == 'OMIT_ASSIGNMENT': if empty.match(line): continue par = get_par(line, 1, 1, fn=fn, lineno=lineno) if not par: continue self.add_item('OMIT_ASSIGNMENT', par[0], omit=True, fn=fn, lineno=lineno) elif ctx == 'TYPE_RENAME': if empty.match(line): continue par = get_par(line, 2, 2, fn=fn, lineno=lineno) if not par: continue self.add_item('TYPE_RENAME', par[0], eth_name=par[1], fn=fn, lineno=lineno) if not par[1][0].isupper(): warnings.warn_explicit("Type should be renamed to uppercase name (%s)" % (par[1]), UserWarning, fn, lineno) elif ctx == 'FIELD_RENAME': if empty.match(line): continue par = get_par(line, 2, 2, fn=fn, lineno=lineno) if not par: continue self.add_item('FIELD_RENAME', par[0], eth_name=par[1], fn=fn, lineno=lineno) if not par[1][0].islower(): warnings.warn_explicit("Field should be renamed to lowercase name (%s)" % (par[1]), UserWarning, fn, lineno) elif ctx in ('TYPE_ATTR', 'ETYPE_ATTR', 'FIELD_ATTR', 'EFIELD_ATTR'): if empty.match(line): continue par = get_par_nm(line, 1, fn=fn, lineno=lineno) if not par: continue self.add_item(ctx, par[0], attr=par[1], fn=fn, lineno=lineno) elif ctx == 'FN_PARS': if empty.match(line): continue if name: par = get_par_nm(line, 0, fn=fn, lineno=lineno) else: par = get_par_nm(line, 1, fn=fn, lineno=lineno) if not par: continue if name: self.add_item(ctx, name, pars=par[0], fn=fn, lineno=lineno) else: self.add_item(ctx, par[0], pars=par[1], fn=fn, lineno=lineno) elif ctx in ('FN_HDR', 'FN_FTR', 'FN_BODY'): self.add_fn_line(name, ctx, line, fn=fn, lineno=lineno) def unused_report(self): tbls = self.table.keys() tbls.sort() for t in tbls: if not self.tblcfg[t]['chk_use']: continue keys = self.table[t].keys() keys.sort() for k in keys: if not self.table[t][k]['used']: warnings.warn_explicit("Unused %s for %s" % (t, k), UserWarning, self.table[t][k]['fn'], self.table[t][k]['lineno']) #--- EthOut ------------------------------------------------------------------- class EthOut: def __init__(self): self.outnm = None self.outdir = '.' self.single_file = None self.created_files = [] self.unique_created_files = [] self.keep = False #--- output_fname ------------------------------------------------------- def output_fname(self, ftype, ext='c'): fn = '' if not ext in ('cnf',): fn += 'packet-' fn += self.outnm if (ftype): fn += '-' + ftype fn += '.' + ext return fn #--- output_fullname ------------------------------------------------------- def output_fullname(self, ftype, ext='c'): return os.path.join(self.outdir, self.output_fname(ftype, ext=ext)) #--- file_open ------------------------------------------------------- def file_open(self, ftype, ext='c'): fn = self.output_fullname(ftype, ext=ext) fx = file(fn, 'w') if (not self.single_file): if ext in ('cnf',): fx.write(self.fhdr(fn, comment = '#')) else: fx.write(self.fhdr(fn)) return fx #--- file_close ------------------------------------------------------- def file_close(self, fx, discard=False, keep_anyway=False): fx.close() if (discard): os.unlink(fx.name) elif (not keep_anyway): self.created_files.append(os.path.normcase(os.path.abspath(fx.name))) #--- fhdr ------------------------------------------------------- def fhdr(self, fn, comment=None): def outln(ln): if comment: return '# %s\n' % (ln) else: return '/* %-74s */\n' % (ln) out = '' out += outln('Do not modify this file.') out += outln('It is created automatically by the ASN.1 to Ethereal dissector compiler') out += outln(fn) out += outln(' '.join(sys.argv)) out += '\n' return out #--- make_single_file ------------------------------------------------------- def make_single_file(self): if (not self.single_file): return in_nm = self.single_file + '.c' out_nm = self.output_fullname('') self.do_include(out_nm, in_nm) in_nm = self.single_file + '.h' if (os.path.exists(in_nm)): out_nm = self.output_fullname('', ext='h') self.do_include(out_nm, in_nm) if (not self.keep): self.unique_created_files = [] [self.unique_created_files.append(wrd) for wrd in self.created_files if not self.unique_created_files.count(wrd)] for fn in self.unique_created_files: os.unlink(fn) #--- do_include ------------------------------------------------------- def do_include(self, out_nm, in_nm): def check_file(fn, fnlist): fnfull = os.path.normcase(os.path.abspath(fn)) if ((fnfull in fnlist) and os.path.exists(fnfull)): return os.path.normpath(fn) return None fin = file(in_nm, "r") fout = file(out_nm, "w") fout.write(self.fhdr(out_nm)) fout.write('/* Input file: ' + in_nm +' */\n') fout.write('\n') include = re.compile(r'^\s*#\s*include\s+[<"](?P[^>"]+)[>"]', re.IGNORECASE) while (True): line = fin.readline() if (line == ''): break ifile = None result = include.search(line) #if (result): print os.path.normcase(os.path.abspath(result.group('fname'))) if (result): ifile = check_file(os.path.join(os.path.split(in_nm)[0], result.group('fname')), self.created_files) if (not ifile): ifile = check_file(os.path.join(self.outdir, result.group('fname')), self.created_files) if (not ifile): ifile = check_file(result.group('fname'), self.created_files) if (ifile): fout.write('\n') fout.write('/*--- Included file: ' + ifile + ' ---*/\n') fout.write('\n') finc = file(ifile, "r") fout.write(finc.read()) fout.write('\n') fout.write('/*--- End of included file: ' + ifile + ' ---*/\n') fout.write('\n') finc.close() else: fout.write(line) fout.close() fin.close() #--- Node --------------------------------------------------------------------- class Node: def __init__(self,*args, **kw): if len (args) == 0: self.type = self.__class__.__name__ else: assert (len(args) == 1) self.type = args[0] self.__dict__.update (kw) def str_child (self, key, child, depth): indent = " " * (2 * depth) keystr = indent + key + ": " if key == 'type': # already processed in str_depth return "" if isinstance (child, Node): # ugh return keystr + "\n" + child.str_depth (depth+1) if type (child) == type ([]): l = [] for x in child: if isinstance (x, Node): l.append (x.str_depth (depth+1)) else: l.append (indent + " " + str(x) + "\n") return keystr + "[\n" + ''.join(l) + indent + "]\n" else: return keystr + str (child) + "\n" def str_depth (self, depth): # ugh indent = " " * (2 * depth) l = ["%s%s" % (indent, self.type)] l.append ("".join (map (lambda (k,v): self.str_child (k, v, depth + 1), self.__dict__.items ()))) return "\n".join (l) def __str__(self): return "\n" + self.str_depth (0) def to_python (self, ctx): return self.str_depth (ctx.indent_lev) def eth_reg(self, ident, ectx): pass #--- value_assign ------------------------------------------------------------- class value_assign (Node): def __init__(self,*args, **kw) : Node.__init__ (self,*args, **kw) def eth_reg(self, ident, ectx): if ectx.conform.use_item('OMIT_ASSIGNMENT', self.ident): return # Assignment to omit ectx.eth_reg_vassign(self) ectx.eth_reg_value(self.ident, self.typ, self.val) #--- Type --------------------------------------------------------------------- class Type (Node): def __init__(self,*args, **kw) : self.name = None self.constr = None Node.__init__ (self,*args, **kw) def IsNamed(self): if self.name is None : return False else: return True def HasConstraint(self): if self.constr is None : return False else : return True def HasOwnTag(self): return self.__dict__.has_key('tag') def HasImplicitTag(self, ectx): return (self.HasOwnTag() and ((self.tag.mode == 'IMPLICIT') or ((self.tag.mode == 'default') and (ectx.tag_def == 'IMPLICIT')))) def IndetermTag(self, ectx): return False def SetTag(self, tag): self.tag = tag def GetTag(self, ectx): #print "GetTag(%s)\n" % self.name; if (self.HasOwnTag()): return self.tag.GetTag(ectx) else: return self.GetTTag(ectx) def GetTTag(self, ectx): print "#Unhandled GetTTag() in %s" % (self.type) print self.str_depth(1) return ('BER_CLASS_unknown', 'TAG_unknown') def SetName(self, name) : self.name = name def AddConstraint(self, constr): if not self.HasConstraint(): self.constr = constr else: self.constr = Constraint(type = 'Intersection', subtype = [self.constr, constr]) def eth_tname(self): return '#' + self.type + '_' + str(id(self)) def eth_ftype(self, ectx): return ('FT_NONE', 'BASE_NONE') def eth_strings(self): return 'NULL' def eth_need_tree(self): return False def eth_has_vals(self): return False def eth_named_bits(self): return None def eth_reg_sub(self, ident, ectx): pass def eth_reg(self, ident, ectx, idx='', parent=None): nm = '' if ident and self.IsNamed (): nm = ident + '/' + self.name elif self.IsNamed(): nm = self.name elif ident: nm = ident if not ident and ectx.conform.use_item('OMIT_ASSIGNMENT', nm): return # Assignment to omit if not ident: # Assignment ectx.eth_reg_assign(nm, self) if self.type == 'Type_Ref': ectx.eth_reg_type(nm, self) if (ectx.conform.check_item('PDU', nm)): ectx.eth_reg_field(nm, nm, impl=self.HasImplicitTag(ectx), pdu=ectx.conform.use_item('PDU', nm)) if self.type == 'Type_Ref': if ectx.conform.check_item('TYPE_RENAME', nm) or ectx.conform.get_fn_presence(nm): ectx.eth_reg_type(nm, self) # new type trnm = nm else: trnm = self.val else: ectx.eth_reg_type(nm, self) if ident: if self.type == 'Type_Ref': ectx.eth_reg_field(nm, trnm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx)) else: ectx.eth_reg_field(nm, nm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx)) self.eth_reg_sub(nm, ectx) def eth_get_size_constr(self): minv = '-1' maxv = '-1' ext = 'FALSE' if not self.HasConstraint(): minv = '-1' maxv = '-1' ext = 'FALSE' elif self.constr.IsSize(): if self.constr.subtype.type == 'SingleValue': minv = self.constr.subtype.subtype maxv = self.constr.subtype.subtype else: minv = self.constr.subtype.subtype[0] maxv = self.constr.subtype.subtype[1] if hasattr(self.constr.subtype, 'ext') and self.constr.subtype.ext: ext = 'TRUE' else: ext = 'FALSE' return (minv, maxv, ext) def eth_type_vals(self, tname, ectx): if self.eth_has_vals(): print "#Unhandled eth_type_vals('%s') in %s" % (tname, self.type) print self.str_depth(1) return '' def eth_type_default_table(self, ectx, tname): return '' def eth_type_default_body(self, ectx): print "#Unhandled eth_type_default_body() in %s" % (self.type) print self.str_depth(1) return '' def eth_type_default_pars(self, ectx, tname): pars = { 'TNAME' : tname, 'ER' : ectx.encp(), 'PINFO' : 'pinfo', 'TREE' : 'tree', 'TVB' : 'tvb', 'OFFSET' : 'offset', 'HF_INDEX' : 'hf_index', 'VAL_PTR' : 'NULL', 'IMPLICIT_TAG' : 'implicit_tag', 'CREATED_ITEM_PTR' : 'NULL', } if ectx.eth_type[tname]['tree']: pars['ETT_INDEX'] = ectx.eth_type[tname]['tree'] return pars def eth_type_fn(self, proto, tname, ectx): body = self.eth_type_default_body(ectx, tname) pars = self.eth_type_default_pars(ectx, tname) if ectx.conform.check_item('FN_PARS', tname): pars.update(ectx.conform.use_item('FN_PARS', tname)) elif ectx.conform.check_item('FN_PARS', ectx.eth_type[tname]['ref'][0]): pars.update(ectx.conform.use_item('FN_PARS', ectx.eth_type[tname]['ref'][0])) pars['DEFAULT_BODY'] = body for i in range(4): for k in pars.keys(): pars[k] = pars[k] % pars out = '\n' out += self.eth_type_default_table(ectx, tname) % pars out += ectx.eth_type_fn_hdr(tname) out += ectx.eth_type_fn_body(tname, body, pars=pars) out += ectx.eth_type_fn_ftr(tname) return out #--- Value -------------------------------------------------------------------- class Value (Node): def __init__(self,*args, **kw) : self.name = None Node.__init__ (self,*args, **kw) def SetName(self, name) : self.name = name def to_str(self): return str(self) def get_dep(self): return None #--- Constraint --------------------------------------------------------------- class Constraint (Node): def to_python (self, ctx): print "Ignoring constraint:", self.type return self.subtype.typ.to_python (ctx) def __str__ (self): return "Constraint: type=%s, subtype=%s" % (self.type, self.subtype) def IsSize(self): return self.type == 'Size' and (self.subtype.type == 'SingleValue' or self.subtype.type == 'ValueRange') def IsPermAlph(self): return self.type == 'From' and self.subtype.type == 'SingleValue' def eth_constrname(self): def int2str(val): try: if (int(val) < 0): return 'M' + str(-int(val)) else: return str(val) except (ValueError, TypeError): return str(val) ext = '' if hasattr(self, 'ext') and self.ext: ext = '_' if self.type == 'SingleValue': return int2str(self.subtype) + ext elif self.type == 'ValueRange': return int2str(self.subtype[0]) + '_' + int2str(self.subtype[1]) + ext elif self.type == 'Size': return 'SIZE_' + self.subtype.eth_constrname() + ext else: return 'CONSTR' + str(id(self)) + ext class Module (Node): def to_python (self, ctx): ctx.tag_def = self.tag_def.dfl_tag return """#%s %s""" % (self.ident, self.body.to_python (ctx)) def to_eth (self, ectx): if (not ectx.proto): ectx.proto = self.ident.val ectx.tag_def = self.tag_def.dfl_tag self.body.to_eth(ectx) class Module_Body (Node): def to_python (self, ctx): # XXX handle exports, imports. l = map (lambda x: x.to_python (ctx), self.assign_list) l = [a for a in l if a <> ''] return "\n".join (l) def to_eth(self, ectx): for i in self.imports: mod = i.module.val proto = ectx.conform.use_item('MODULE_IMPORT', mod, val_dflt=mod) for s in i.symbol_list: if isinstance(s, Type_Ref): ectx.eth_import_type(s.val, mod, proto) else: ectx.eth_import_value(s, mod, proto) for a in self.assign_list: a.eth_reg('', ectx) class Default_Tags (Node): def to_python (self, ctx): # not to be used directly assert (0) # XXX should just calculate dependencies as we go along. def calc_dependencies (node, dict, trace = 0): if not hasattr (node, '__dict__'): if trace: print "#returning, node=", node return if isinstance (node, Type_Ref): dict [node.val] = 1 if trace: print "#Setting", node.val return for (a, val) in node.__dict__.items (): if trace: print "# Testing node ", node, "attr", a, " val", val if a[0] == '_': continue elif isinstance (val, Node): calc_dependencies (val, dict, trace) elif isinstance (val, type ([])): for v in val: calc_dependencies (v, dict, trace) class Type_Assign (Node): def __init__ (self, *args, **kw): Node.__init__ (self, *args, **kw) if isinstance (self.val, Tag): # XXX replace with generalized get_typ_ignoring_tag (no-op for Node, override in Tag) to_test = self.val.typ else: to_test = self.val if isinstance (to_test, SequenceType): to_test.sequence_name = self.name.name def to_python (self, ctx): dep_dict = {} calc_dependencies (self.val, dep_dict, 0) depend_list = dep_dict.keys () return ctx.register_assignment (self.name.name, self.val.to_python (ctx), depend_list) class PyQuote (Node): def to_python (self, ctx): return ctx.register_pyquote (self.val) #--- Type_Ref ----------------------------------------------------------------- class Type_Ref (Type): def to_python (self, ctx): return self.val def eth_reg_sub(self, ident, ectx): ectx.eth_dep_add(ident, self.val) def eth_tname(self): return asn2c(self.val) def GetTTag(self, ectx): #print "GetTTag(%s)\n" % self.val; if (ectx.type[self.val]['import']): if not ectx.type[self.val].has_key('ttag'): if not ectx.conform.check_item('IMPORT_TAG', self.val): msg = 'Missing tag information for imported type %s from %s (%s)' % (self.val, ectx.type[self.val]['import'], ectx.type[self.val]['proto']) warnings.warn_explicit(msg, UserWarning, '', '') ectx.type[self.val]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.val, val_dflt=('-1 /*imported*/', '-1 /*imported*/')) return ectx.type[self.val]['ttag'] else: return ectx.type[self.val]['val'].GetTag(ectx) def IndetermTag(self, ectx): if (ectx.type[self.val]['import']): return False else: return ectx.type[self.val]['val'].IndetermTag(ectx) def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) t = ectx.type[self.val]['ethname'] pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto'] pars['TYPE_REF_TNAME'] = t pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s' return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'),)) elif (ectx.NPer()): body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'),)) elif (ectx.OPer()): body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'),)) else: body = '#error Can not decode %s' % (tname) return body #--- SqType ----------------------------------------------------------- class SqType (Type): def out_item(self, f, val, optional, ext, ectx): ef = ectx.field[f]['ethname'] efd = ef if (ectx.OBer() and ectx.field[f]['impl']): efd += '_impl' if (ectx.Ber()): #print "optional=%s, e.val.HasOwnTag()=%s, e.val.IndetermTag()=%s" % (str(e.optional), str(e.val.HasOwnTag()), str(e.val.IndetermTag(ectx))) #print val.str_depth(1) opt = '' if (optional): opt = 'BER_FLAGS_OPTIONAL' if (not val.HasOwnTag()): if (opt): opt += '|' opt += 'BER_FLAGS_NOOWNTAG' elif (val.HasImplicitTag(ectx)): if (opt): opt += '|' opt += 'BER_FLAGS_IMPLTAG' if (val.IndetermTag(ectx)): if (opt): opt += '|' opt += 'BER_FLAGS_NOTCHKTAG' if (not opt): opt = '0' else: if optional: opt = 'ASN1_OPTIONAL' else: opt = 'ASN1_NOT_OPTIONAL' if (ectx.OBer()): (tc, tn) = val.GetTag(ectx) out = ' { %-13s, %s, %s, dissect_%s },\n' \ % (tc, tn, opt, efd) elif (ectx.NPer()): out = ' { &%-30s, %-23s, %-17s, dissect_%s_%s },\n' \ % (ef, ext, opt, ectx.eth_type[ectx.eth_hf[ef]['ethtype']]['proto'], ectx.eth_hf[ef]['ethtype']) elif (ectx.OPer()): out = ' { %-30s, %-23s, %-17s, dissect_%s },\n' \ % ('"'+(val.name or '')+'"', ext, opt, efd) else: out = '' return out #--- SeqType ----------------------------------------------------------- class SeqType (SqType): def eth_type_default_table(self, ectx, tname): #print "eth_type_default_table(tname='%s')" % (tname) fname = ectx.eth_type[tname]['ref'][0] table = "static const %(ER)s_sequence_t %(TABLE)s[] = {\n" if hasattr(self, 'ext_list'): ext = 'ASN1_EXTENSION_ROOT' else: ext = 'ASN1_NO_EXTENSIONS' for e in (self.elt_list): f = fname + '/' + e.val.name table += self.out_item(f, e.val, e.optional, ext, ectx) if hasattr(self, 'ext_list'): for e in (self.ext_list): f = fname + '/' + e.val.name table += self.out_item(f, e.val, e.optional, 'ASN1_NOT_EXTENSION_ROOT', ectx) if (ectx.Ber()): table += " { 0, 0, 0, NULL }\n};\n" else: table += " { NULL, 0, 0, NULL }\n};\n" return table #--- SeqOfType ----------------------------------------------------------- class SeqOfType (SqType): def eth_type_default_table(self, ectx, tname): #print "eth_type_default_table(tname='%s')" % (tname) fname = ectx.eth_type[tname]['ref'][0] if self.val.IsNamed (): f = fname + '/' + self.val.name else: f = fname + '/' + '_item' table = "static const %(ER)s_sequence_t %(TABLE)s[1] = {\n" table += self.out_item(f, self.val, False, 'ASN1_NO_EXTENSIONS', ectx) table += "};\n" return table #--- SequenceOfType ----------------------------------------------------------- class SequenceOfType (SeqOfType): def to_python (self, ctx): # name, tag (None for no tag, EXPLICIT() for explicit), typ) # or '' + (1,) for optional sizestr = '' if self.size_constr <> None: print "#Ignoring size constraint:", self.size_constr.subtype return "%sasn1.SEQUENCE_OF (%s%s)" % (ctx.spaces (), self.val.to_python (ctx), sizestr) def eth_reg_sub(self, ident, ectx): itmnm = ident if not self.val.IsNamed (): itmnm += '/' + '_item' self.val.eth_reg(itmnm, ectx, idx='[##]', parent=ident) def eth_tname(self): if self.val.type != 'Type_Ref': return '#' + self.type + '_' + str(id(self)) if not self.HasConstraint(): return "SEQUENCE_OF_" + self.val.eth_tname() elif self.constr.IsSize(): return 'SEQUENCE_' + self.constr.eth_constrname() + '_OF_' + self.val.eth_tname() else: return '#' + self.type + '_' + str(id(self)) def eth_ftype(self, ectx): return ('FT_UINT32', 'BASE_DEC') def eth_need_tree(self): return True def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_SEQUENCE') def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr() pars['TABLE'] = '%(TNAME)s_sequence_of' return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'), ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),)) elif (not self.HasConstraint()): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) elif (self.constr.type == 'Size'): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_constrained_sequence_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_constrained_sequence_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',), ('%(MIN_VAL)s', '%(MAX_VAL)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- SetOfType ---------------------------------------------------------------- class SetOfType (SeqOfType): def eth_reg_sub(self, ident, ectx): itmnm = ident if not self.val.IsNamed (): itmnm += '/' + '_item' self.val.eth_reg(itmnm, ectx, idx='(##)', parent=ident) def eth_tname(self): if self.val.type != 'Type_Ref': return '#' + self.type + '_' + str(id(self)) if not self.HasConstraint(): return "SET_OF_" + self.val.eth_tname() elif self.constr.IsSize(): return 'SET_' + self.constr.eth_constrname() + '_OF_' + self.val.eth_tname() else: return '#' + self.type + '_' + str(id(self)) def eth_ftype(self, ectx): return ('FT_UINT32', 'BASE_DEC') def eth_need_tree(self): return True def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_SET') def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr() pars['TABLE'] = '%(TNAME)s_set_of' return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'), ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),)) elif (not self.HasConstraint()): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) elif (self.constr.type == 'Size'): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_constrained_set_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_constrained_set_of', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',), ('%(MIN_VAL)s', '%(MAX_VAL)s',),)) else: body = '#error Can not decode %s' % (tname) return body def mk_tag_str (ctx, cls, typ, num): # XXX should do conversion to int earlier! val = int (num) typ = typ.upper() if typ == 'DEFAULT': typ = ctx.tags_def return 'asn1.%s(%d,cls=asn1.%s_FLAG)' % (typ, val, cls) # XXX still ned class Tag (Node): def to_python (self, ctx): return 'asn1.TYPE(%s,%s)' % (mk_tag_str (ctx, self.tag.cls, self.tag_typ, self.tag.num), self.typ.to_python (ctx)) def GetTag(self, ectx): tc = '' if (self.cls == 'UNIVERSAL'): tc = 'BER_CLASS_UNI' elif (self.cls == 'APPLICATION'): tc = 'BER_CLASS_APP' elif (self.cls == 'CONTEXT'): tc = 'BER_CLASS_CON' elif (self.cls == 'PRIVATE'): tc = 'BER_CLASS_PRI' return (tc, self.num) #--- SequenceType ------------------------------------------------------------- class SequenceType (SeqType): def to_python (self, ctx): # name, tag (None for no tag, EXPLICIT() for explicit), typ) # or '' + (1,) for optional # XXX should also collect names for SEQUENCE inside SEQUENCE or # CHOICE or SEQUENCE_OF (where should the SEQUENCE_OF name come # from? for others, element or arm name would be fine) seq_name = getattr (self, 'sequence_name', None) if seq_name == None: seq_name = 'None' else: seq_name = "'" + seq_name + "'" if self.__dict__.has_key('ext_list'): return "%sasn1.SEQUENCE ([%s], ext=[%s], seq_name = %s)" % (ctx.spaces (), self.elts_to_py (self.elt_list, ctx), self.elts_to_py (self.ext_list, ctx), seq_name) else: return "%sasn1.SEQUENCE ([%s]), seq_name = %s" % (ctx.spaces (), self.elts_to_py (self.elt_list, ctx), seq_name) def elts_to_py (self, list, ctx): # we have elt_type, val= named_type, maybe default=, optional= # named_type node: either ident = or typ = # need to dismember these in order to generate Python output syntax. ctx.indent () def elt_to_py (e): assert (e.type == 'elt_type') nt = e.val optflag = e.optional #assert (not hasattr (e, 'default')) # XXX add support for DEFAULT! assert (nt.type == 'named_type') tagstr = 'None' identstr = nt.ident if hasattr (nt.typ, 'type') and nt.typ.type == 'tag': # ugh tagstr = mk_tag_str (ctx,nt.typ.tag.cls, nt.typ.tag.tag_typ,nt.typ.tag.num) nt = nt.typ return "('%s',%s,%s,%d)" % (identstr, tagstr, nt.typ.to_python (ctx), optflag) indentstr = ",\n" + ctx.spaces () rv = indentstr.join ([elt_to_py (e) for e in list]) ctx.outdent () return rv def eth_reg_sub(self, ident, ectx): for e in (self.elt_list): e.val.eth_reg(ident, ectx, parent=ident) if hasattr(self, 'ext_list'): for e in (self.ext_list): e.val.eth_reg(ident, ectx, parent=ident) def eth_need_tree(self): return True def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_SEQUENCE') def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) pars['TABLE'] = '%(TNAME)s_sequence' return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'), ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- SetType ------------------------------------------------------------------ class SetType(SeqType): def eth_reg_sub(self, ident, ectx): for e in (self.elt_list): e.val.eth_reg(ident, ectx, parent=ident) if hasattr(self, 'ext_list'): for e in (self.ext_list): e.val.eth_reg(ident, ectx, parent=ident) def eth_need_tree(self): return True def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_SET') def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) pars['TABLE'] = '%(TNAME)s_set' return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'), ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- ChoiceType --------------------------------------------------------------- class ChoiceType (Type): def to_python (self, ctx): # name, tag (None for no tag, EXPLICIT() for explicit), typ) # or '' + (1,) for optional if self.__dict__.has_key('ext_list'): return "%sasn1.CHOICE ([%s], ext=[%s])" % (ctx.spaces (), self.elts_to_py (self.elt_list, ctx), self.elts_to_py (self.ext_list, ctx)) else: return "%sasn1.CHOICE ([%s])" % (ctx.spaces (), self.elts_to_py (self.elt_list, ctx)) def elts_to_py (self, list, ctx): ctx.indent () def elt_to_py (nt): assert (nt.type == 'named_type') tagstr = 'None' if hasattr (nt, 'ident'): identstr = nt.ident else: if hasattr (nt.typ, 'val'): identstr = nt.typ.val # XXX, making up name elif hasattr (nt.typ, 'name'): identstr = nt.typ.name else: identstr = ctx.make_new_name () if hasattr (nt.typ, 'type') and nt.typ.type == 'tag': # ugh tagstr = mk_tag_str (ctx,nt.typ.tag.cls, nt.typ.tag.tag_typ,nt.typ.tag.num) nt = nt.typ return "('%s',%s,%s)" % (identstr, tagstr, nt.typ.to_python (ctx)) indentstr = ",\n" + ctx.spaces () rv = indentstr.join ([elt_to_py (e) for e in list]) ctx.outdent () return rv def eth_reg_sub(self, ident, ectx): #print "eth_reg_sub(ident='%s')" % (ident) for e in (self.elt_list): e.eth_reg(ident, ectx, parent=ident) if hasattr(self, 'ext_list'): for e in (self.ext_list): e.eth_reg(ident, ectx, parent=ident) def eth_ftype(self, ectx): return ('FT_UINT32', 'BASE_DEC') def eth_strings(self): return '$$' def eth_need_tree(self): return True def eth_has_vals(self): return True def GetTTag(self, ectx): lst = self.elt_list cls = '-1/*choice*/' if hasattr(self, 'ext_list'): lst.extend(self.ext_list) if (len(lst) > 0): cls = lst[0].GetTag(ectx)[0] for e in (lst): if (e.GetTag(ectx)[0] != cls): cls = '-1/*choice*/' return (cls, '-1/*choice*/') def IndetermTag(self, ectx): #print "Choice IndetermTag()=%s" % (str(not self.HasOwnTag())) return not self.HasOwnTag() def eth_type_vals(self, tname, ectx): out = '\n' tagval = False if (ectx.Ber()): lst = self.elt_list if hasattr(self, 'ext_list'): lst.extend(self.ext_list) if (len(lst) > 0): t = lst[0].GetTag(ectx)[0] tagval = True if (t == 'BER_CLASS_UNI'): tagval = False for e in (lst): if (e.GetTag(ectx)[0] != t): tagval = False vals = [] cnt = 0 for e in (self.elt_list): if (tagval): val = e.GetTag(ectx)[1] else: val = str(cnt) vals.append((val, e.name)) cnt += 1 if hasattr(self, 'ext_list'): for e in (self.ext_list): if (tagval): val = e.GetTag(ectx)[1] else: val = str(cnt) vals.append((val, e.name)) cnt += 1 out += ectx.eth_vals(tname, vals) return out def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) pars['TABLE'] = '%(TNAME)s_choice' pars['CHOICE_NAME'] = '"%(TNAME)s"' return pars def eth_type_default_table(self, ectx, tname): def out_item(val, e, ext, ectx): f = fname + '/' + e.name ef = ectx.field[f]['ethname'] efd = ef if (ectx.field[f]['impl']): efd += '_impl' if (ectx.Ber()): opt = '' if (not e.HasOwnTag()): opt = 'BER_FLAGS_NOOWNTAG' elif (e.tag.mode == 'IMPLICIT'): if (opt): opt += '|' opt += 'BER_FLAGS_IMPLTAG' if (not opt): opt = '0' if (ectx.OBer()): (tc, tn) = e.GetTag(ectx) out = ' { %3s, %-13s, %s, %s, dissect_%s },\n' \ % (val, tc, tn, opt, efd) elif (ectx.NPer()): out = ' { %3s, &%-30s, %-23s, dissect_%s_%s },\n' \ % (val, ef, ext, ectx.eth_type[ectx.eth_hf[ef]['ethtype']]['proto'], ectx.eth_hf[ef]['ethtype']) elif (ectx.OPer()): out = ' { %3s, %-30s, %-23s, dissect_%s },\n' \ % (val, '"'+e.name+'"', ext, efd) else: out = '' return out # end out_item() #print "eth_type_default_table(tname='%s')" % (tname) fname = ectx.eth_type[tname]['ref'][0] tagval = False if (ectx.Ber()): lst = self.elt_list if hasattr(self, 'ext_list'): lst.extend(self.ext_list) if (len(lst) > 0): t = lst[0].GetTag(ectx)[0] tagval = True if (t == 'BER_CLASS_UNI'): tagval = False for e in (lst): if (e.GetTag(ectx)[0] != t): tagval = False table = "static const %(ER)s_choice_t %(TABLE)s[] = {\n" cnt = 0 if hasattr(self, 'ext_list'): ext = 'ASN1_EXTENSION_ROOT' else: ext = 'ASN1_NO_EXTENSIONS' for e in (self.elt_list): if (tagval): val = e.GetTag(ectx)[1] else: val = str(cnt) table += out_item(val, e, ext, ectx) cnt += 1 if hasattr(self, 'ext_list'): for e in (self.ext_list): if (tagval): val = e.GetTag(ectx)[1] else: val = str(cnt) table += out_item(val, e, 'ASN1_NOT_EXTENSION_ROOT', ectx) cnt += 1 if (ectx.Ber()): table += " { 0, 0, 0, 0, NULL }\n};\n" else: table += " { 0, NULL, 0, NULL }\n};\n" return table def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset', par=(('%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'), ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s'), ('%(VAL_PTR)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(ETT_INDEX)s', '%(TABLE)s', '%(CHOICE_NAME)s',), ('%(VAL_PTR)s',),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(ETT_INDEX)s', '%(TABLE)s', '%(CHOICE_NAME)s',), ('%(VAL_PTR)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- EnumeratedType ----------------------------------------------------------- class EnumeratedType (Type): def to_python (self, ctx): def strify_one (named_num): return "%s=%s" % (named_num.ident, named_num.val) return "asn1.ENUM(%s)" % ",".join (map (strify_one, self.val)) def eth_ftype(self, ectx): return ('FT_UINT32', 'BASE_DEC') def eth_strings(self): return '$$' def eth_has_vals(self): return True def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_ENUMERATED') def get_vals_maxv(self, ectx): vals = [] lastv = 0 used = {} maxv = 0 for e in (self.val): if e.type == 'NamedNumber': used[int(e.val)] = True for e in (self.val): if e.type == 'NamedNumber': val = int(e.val) else: while used.has_key(lastv): lastv += 1 val = lastv used[val] = True vals.append((val, e.ident)) if val > maxv: maxv = val if self.ext is not None: for e in (self.ext): if e.type == 'NamedNumber': used[int(e.val)] = True for e in (self.ext): if e.type == 'NamedNumber': val = int(e.val) else: while used.has_key(lastv): lastv += 1 val = lastv vals.append((val, e.ident)) if val > maxv: maxv = val return (vals, maxv) def eth_type_vals(self, tname, ectx): out = '\n' (vals, xxxx) = self.get_vals_maxv(ectx) out += ectx.eth_vals(tname, vals) return out def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) (xxxx, maxv) = self.get_vals_maxv(ectx) maxv = str(maxv) if self.ext is None: ext = 'FALSE' else: ext = 'TRUE' pars['MIN_VAL'] = '0' pars['MAX_VAL'] = maxv pars['EXT'] = ext return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(VAL_PTR)s',),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s', '%(CREATED_ITEM_PTR)s', '%(EXT)s'),)) else: body = '#error Can not decode %s' % (tname) return body #--- AnyType ----------------------------------------------------------- class AnyType (Type): def to_python (self, ctx): return "asn1.ANY" def eth_ftype(self, ectx): return ('FT_NONE', 'BASE_NONE') def GetTTag(self, ectx): return ('BER_CLASS_ANY', '0') def eth_type_default_body(self, ectx, tname): body = '#error Can not decode %s' % (tname) return body class Literal (Node): def to_python (self, ctx): return self.val #--- NullType ----------------------------------------------------------------- class NullType (Type): def to_python (self, ctx): return 'asn1.NULL' def eth_tname(self): return 'NULL' def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_NULL') def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'NULL'),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'),)) else: body = '#error Can not decode %s' % (tname) return body #--- RealType ----------------------------------------------------------------- class RealType (Type): def to_python (self, ctx): return 'asn1.REAL' def eth_tname(self): return 'REAL' def eth_type_default_body(self, ectx, tname): body = '#error Can not decode %s' % (tname) return body #--- BooleanType -------------------------------------------------------------- class BooleanType (Type): def to_python (self, ctx): return 'asn1.BOOLEAN' def eth_tname(self): return 'BOOLEAN' def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_BOOLEAN') def eth_ftype(self, ectx): return ('FT_BOOLEAN', '8') def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'NULL'),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s', '%(CREATED_ITEM_PTR)s'),)) else: body = '#error Can not decode %s' % (tname) return body #--- OctetStringType ---------------------------------------------------------- class OctetStringType (Type): def to_python (self, ctx): return 'asn1.OCTSTRING' def eth_tname(self): if not self.HasConstraint(): return 'OCTET_STRING' elif self.constr.IsSize(): return 'OCTET_STRING' + '_' + self.constr.eth_constrname() else: return '#' + self.type + '_' + str(id(self)) def eth_ftype(self, ectx): return ('FT_BYTES', 'BASE_HEX') def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_OCTETSTRING') def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr() return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(VAL_PTR)s',),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- CharacterStringType ------------------------------------------------------ class CharacterStringType (Type): def eth_tname(self): if not self.HasConstraint(): return self.eth_tsname() elif self.constr.IsSize(): return self.eth_tsname() + '_' + self.constr.eth_constrname() else: return '#' + self.type + '_' + str(id(self)) def eth_ftype(self, ectx): return ('FT_STRING', 'BASE_NONE') class RestrictedCharacterStringType (CharacterStringType): def to_python (self, ctx): return 'asn1.' + self.eth_tsname() def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_' + self.eth_tsname()) def eth_type_fn(self, proto, tname, ectx): out = ectx.eth_type_fn_hdr(tname) (minv, maxv, ext) = self.eth_get_size_constr() if (ectx.Ber()): body = ectx.eth_fn_call('dissect_ber_restricted_string', ret='offset', par=(('implicit_tag', self.GetTTag(ectx)[1]), ('pinfo', 'tree', 'tvb', 'offset', 'hf_index'), ('NULL',))) elif (ectx.Per() and self.HasConstraint() and self.constr.IsPermAlph()): alphabet = self.constr.subtype.subtype alphabet_length = 'strlen(%s)' % (alphabet) if (ectx.OPer()): body = ectx.eth_fn_call('dissect_per_restricted_character_string', ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'), (minv, maxv, alphabet, alphabet_length), ('NULL','0'))) else: body = '#error Can not decode %s' % (tname) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_pern_' + self.eth_tsname(), ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree'), ('hf_index', 'item', 'private_data'), (minv, maxv, ext), ('NULL', 'NULL'))) elif (ectx.OPer()): if (self.eth_tsname() == 'GeneralString'): body = ectx.eth_fn_call('dissect_per_' + self.eth_tsname(), ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'),)) elif (self.eth_tsname() == 'GeneralizedTime'): body = ectx.eth_fn_call('dissect_per_' + 'VisibleString', ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'), (minv, maxv))) else: body = ectx.eth_fn_call('dissect_per_' + self.eth_tsname(), ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'), (minv, maxv))) else: body = '#error Can not decode %s' % (tname) out += ectx.eth_type_fn_body(tname, body) out += ectx.eth_type_fn_ftr(tname) return out class BMPStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'BMPString' class GeneralStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'GeneralString' class GraphicStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'GraphicString' class IA5StringType (RestrictedCharacterStringType): def eth_tsname(self): return 'IA5String' class NumericStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'NumericString' class PrintableStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'PrintableString' class TeletexStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'TeletexString' class T61StringType (RestrictedCharacterStringType): def eth_tsname(self): return 'T61String' def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_Teletext') class UniversalStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'UniversalString' class UTF8StringType (RestrictedCharacterStringType): def eth_tsname(self): return 'UTF8String' class VideotexStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'VideotexString' class VisibleStringType (RestrictedCharacterStringType): def eth_tsname(self): return 'VisibleString' class ISO646StringType (RestrictedCharacterStringType): def eth_tsname(self): return 'ISO646String' def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_VisibleString') class UnrestrictedCharacterStringType (CharacterStringType): def to_python (self, ctx): return 'asn1.UnrestrictedCharacterString' def eth_tsname(self): return 'CHARACTER_STRING' #--- UsefulType --------------------------------------------------------------- class GeneralizedTime (RestrictedCharacterStringType): def eth_tsname(self): return 'GeneralizedTime' def eth_type_fn(self, proto, tname, ectx): if (ectx.Ber()): out = ectx.eth_type_fn_hdr(tname) body = ectx.eth_fn_call('dissect_ber_GeneralizedTime', ret='offset', par=(('implicit_tag', 'pinfo', 'tree', 'tvb', 'offset', 'hf_index'),)) out += ectx.eth_type_fn_body(tname, body) out += ectx.eth_type_fn_ftr(tname) return out else: return RestrictedCharacterStringType.eth_type_fn(self, proto, tname, ectx) class UTCTime (RestrictedCharacterStringType): def eth_tsname(self): return 'UTCTime' class ObjectDescriptor (RestrictedCharacterStringType): def eth_tsname(self): return 'ObjectDescriptor' #--- ObjectIdentifierType ----------------------------------------------------- class ObjectIdentifierType (Type): def to_python (self, ctx): return 'asn1.OBJECT_IDENTIFIER' def eth_tname(self): return 'OBJECT_IDENTIFIER' def eth_ftype(self, ectx): return ('FT_STRING', 'BASE_NONE') def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_OID') def eth_type_default_body(self, ectx, tname): if (ectx.OBer()): body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s',),)) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', '%(VAL_PTR)s'),)) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s',),)) else: body = '#error Can not decode %s' % (tname) return body #--- ObjectIdentifierValue ---------------------------------------------------- class ObjectIdentifierValue (Value): def get_num(self, path, val): return str(oid_names.get(path + '/' + val, val)) def to_str(self): out = '' path = '' first = True sep = '' for v in self.comp_list: if isinstance(v, Node) and (v.type == 'name_and_number'): vstr = v.number elif v.isdigit(): vstr = v else: vstr = self.get_num(path, v) if first: if vstr.isdigit(): out += '"' + vstr else: out += vstr + '"' else: out += sep + vstr path += sep + vstr first = False sep = '.' out += '"' return out def get_dep(self): v = self.comp_list[0] if isinstance(v, Node) and (v.type == 'name_and_number'): return None elif v.isdigit(): return None else: vstr = self.get_num('', v) if vstr.isdigit(): return None else: return vstr class NamedNumber (Node): def to_python (self, ctx): return "('%s',%s)" % (self.ident, self.val) class NamedNumListBase(Node): def to_python (self, ctx): return "asn1.%s_class ([%s])" % (self.asn1_typ,",".join ( map (lambda x: x.to_python (ctx), self.named_list))) #--- IntegerType -------------------------------------------------------------- class IntegerType (Type): def to_python (self, ctx): return "asn1.INTEGER_class ([%s])" % (",".join ( map (lambda x: x.to_python (ctx), self.named_list))) def eth_tname(self): if self.named_list: return Type.eth_tname(self) if not self.HasConstraint(): return 'INTEGER' elif self.constr.type == 'SingleValue' or self.constr.type == 'ValueRange': return 'INTEGER' + '_' + self.constr.eth_constrname() else: return 'INTEGER' + '_' + self.constr.eth_tname() def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_INTEGER') def eth_ftype(self, ectx): if self.HasConstraint(): if self.constr.type == 'SingleValue': if self.constr.subtype >= 0: return ('FT_UINT32', 'BASE_DEC') elif self.constr.type == 'ValueRange': if self.constr.subtype[0] >= 0: return ('FT_UINT32', 'BASE_DEC') return ('FT_INT32', 'BASE_DEC') def eth_strings(self): if (self.named_list): return '$$' else: return 'NULL' def eth_has_vals(self): if (self.named_list): return True else: return False def eth_type_vals(self, tname, ectx): if not self.eth_has_vals(): return '' out = '\n' vals = [] for e in (self.named_list): vals.append((int(e.val), e.ident)) out += ectx.eth_vals(tname, vals) return out def eth_type_default_pars(self, ectx, tname): pars = Type.eth_type_default_pars(self, ectx, tname) if self.HasConstraint() and ((self.constr.type == 'SingleValue') or (self.constr.type == 'ValueRange')): if self.constr.type == 'SingleValue': minv = self.constr.subtype maxv = self.constr.subtype else: minv = self.constr.subtype[0] maxv = self.constr.subtype[1] if str(minv).isdigit(): minv += 'U' if str(maxv).isdigit(): maxv += 'U' if hasattr(self.constr, 'ext') and self.constr.ext: ext = 'TRUE' else: ext = 'FALSE' pars['MIN_VAL'] = minv pars['MAX_VAL'] = maxv pars['EXT'] = ext return pars def eth_type_default_body(self, ectx, tname): if (ectx.Ber()): body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset', par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s',),)) elif (not self.HasConstraint()): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(VAL_PTR)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(VAL_PTR)s', '%(CREATED_ITEM_PTR)s'),)) elif ((self.constr.type == 'SingleValue') or (self.constr.type == 'ValueRange')): if (ectx.NAPI()): body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s', 'item', 'private_data'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(VAL_PTR)s',),)) else: body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset', par=(('%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'), ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s', '%(CREATED_ITEM_PTR)s', '%(EXT)s'),)) else: body = '#error Can not decode %s' % (tname) return body #--- BitStringType ------------------------------------------------------------ class BitStringType (Type): def to_python (self, ctx): return "asn1.BITSTRING_class ([%s])" % (",".join ( map (lambda x: x.to_python (ctx), self.named_list))) def eth_tname(self): if self.named_list: return Type.eth_tname(self) elif not self.HasConstraint(): return 'BIT_STRING' elif self.constr.IsSize(): return 'BIT_STRING' + '_' + self.constr.eth_constrname() else: return '#' + self.type + '_' + str(id(self)) def GetTTag(self, ectx): return ('BER_CLASS_UNI', 'BER_UNI_TAG_BITSTRING') def eth_ftype(self, ectx): return ('FT_BYTES', 'BASE_HEX') def eth_need_tree(self): return self.named_list def eth_named_bits(self): bits = [] if (self.named_list): for e in (self.named_list): bits.append((int(e.val), e.ident)) return bits def eth_type_fn(self, proto, tname, ectx): out = '' bits = self.eth_named_bits() bitsp = 'NULL' if (bits): out += ectx.eth_bits(tname, bits) bitsp = tname + '_bits' out += ectx.eth_type_fn_hdr(tname) (minv, maxv, ext) = self.eth_get_size_constr() tree = '-1' if (ectx.eth_type[tname]['tree']): tree = ectx.eth_type[tname]['tree'] if (ectx.OBer()): body = ectx.eth_fn_call('dissect_ber_bitstring', ret='offset', par=(('implicit_tag', 'pinfo', 'tree', 'tvb', 'offset'), (bitsp, 'hf_index', tree), ('NULL',))) elif (ectx.NPer()): body = ectx.eth_fn_call('dissect_pern_bit_string', ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree'), ('hf_index', 'item', 'private_data'), (minv, maxv, ext), ('NULL', 'NULL'))) elif (ectx.OPer()): body = ectx.eth_fn_call('dissect_per_bit_string', ret='offset', par=(('tvb', 'offset', 'pinfo', 'tree', 'hf_index'), (minv, maxv))) else: body = '#error Can not decode %s' % (tname) out += ectx.eth_type_fn_body(tname, body) out += ectx.eth_type_fn_ftr(tname) return out #============================================================================== def p_module_list_1 (t): 'module_list : module_list module_def' t[0] = t[1] + [t[2]] def p_module_list_2 (t): 'module_list : module_def' t[0] = [t[1]] #--- ITU-T Recommendation X.680 ----------------------------------------------- # 11 ASN.1 lexical items -------------------------------------------------------- # 11.2 Type references def p_type_ref (t): 'type_ref : UCASE_IDENT' t[0] = Type_Ref(val=t[1]) # 11.4 Value references def p_valuereference (t): 'valuereference : LCASE_IDENT' t[0] = t[1] # 12 Module definition -------------------------------------------------------- # 12.1 def p_module_def (t): 'module_def : module_ident DEFINITIONS TagDefault ASSIGNMENT BEGIN module_body END' t[0] = Module (ident = t[1], tag_def = t[3], body = t[6]) def p_TagDefault_1 (t): '''TagDefault : EXPLICIT TAGS | IMPLICIT TAGS | AUTOMATIC TAGS''' t[0] = Default_Tags (dfl_tag = t[1]) def p_TagDefault_2 (t): 'TagDefault : ' # 12.2 The "TagDefault" is taken as EXPLICIT TAGS if it is "empty". t[0] = Default_Tags (dfl_tag = 'EXPLICIT') def p_module_ident (t): 'module_ident : type_ref assigned_ident' # name, oid # XXX coerce type_ref to module_ref t [0] = Node('module_ident', val = t[1].val, ident = t[2]) # XXX originally we had both type_ref and module_ref, but that caused # a reduce/reduce conflict (because both were UCASE_IDENT). Presumably # this didn't cause a problem in the original ESNACC grammar because it # was LALR(1) and PLY is (as of 1.1) only SLR. #def p_module_ref (t): # 'module_ref : UCASE_IDENT' # t[0] = t[1] def p_assigned_ident_1 (t): 'assigned_ident : ObjectIdentifierValue' t[0] = t[1] def p_assigned_ident_2 (t): 'assigned_ident : LCASE_IDENT' t[0] = t[1] def p_assigned_ident_3 (t): 'assigned_ident : ' pass def p_module_body_1 (t): 'module_body : exports Imports AssignmentList' t[0] = Module_Body (exports = t[1], imports = t[2], assign_list = t[3]) def p_module_body_2 (t): 'module_body : ' t[0] = Node ('module_body', exports = [], imports = [], assign_list = []) def p_exports_1 (t): 'exports : EXPORTS syms_exported SEMICOLON' t[0] = t[2] def p_exports_2 (t): 'exports : ' t[0] = [] def p_syms_exported_1 (t): 'syms_exported : exp_sym_list' t[0] = t[1] def p_syms_exported_2 (t): 'syms_exported : ' t[0] = [] def p_exp_sym_list_1 (t): 'exp_sym_list : Symbol' t[0] = [t[1]] def p_exp_sym_list_2 (t): 'exp_sym_list : exp_sym_list COMMA Symbol' t[0] = t[1] + [t[3]] def p_Imports_1(t): 'Imports : IMPORTS SymbolsImported SEMICOLON' t[0] = t[2] def p_Imports_2 (t): 'Imports : ' t[0] = [] def p_SymbolsImported_1(t): 'SymbolsImported : ' t[0] = [] def p_SymbolsImported_2 (t): 'SymbolsImported : SymbolsFromModuleList' t[0] = t[1] def p_SymbolsFromModuleList_1 (t): 'SymbolsFromModuleList : SymbolsFromModuleList SymbolsFromModule' t[0] = t[1] + [t[2]] def p_SymbolsFromModuleList_2 (t): 'SymbolsFromModuleList : SymbolsFromModule' t[0] = [t[1]] def p_SymbolsFromModule (t): 'SymbolsFromModule : SymbolList FROM module_ident' t[0] = Node ('SymbolList', symbol_list = t[1], module = t[3]) def p_SymbolList_1 (t): 'SymbolList : Symbol' t[0] = [t[1]] def p_SymbolList_2 (t): 'SymbolList : SymbolList COMMA Symbol' t[0] = t[1] + [t[3]] def p_Symbol (t): '''Symbol : type_ref | ParameterizedReference | identifier''' # XXX omit DefinedMacroName t[0] = t[1] def p_Reference (t): '''Reference : type_ref | valuereference''' t[0] = t[1] def p_AssignmentList_1 (t): 'AssignmentList : AssignmentList Assignment' t[0] = t[1] + [t[2]] def p_AssignmentList_2 (t): 'AssignmentList : Assignment SEMICOLON' t[0] = [t[1]] def p_AssignmentList_3 (t): 'AssignmentList : Assignment' t[0] = [t[1]] def p_Assignment (t): '''Assignment : TypeAssignment | ValueAssignment | pyquote | ParameterizedTypeAssignment''' t[0] = t[1] def p_pyquote (t): '''pyquote : PYQUOTE''' t[0] = PyQuote (val = t[1]) # 13 Referencing type and value definitions ----------------------------------- # 13.1 def p_DefinedType (t): '''DefinedType : ext_type_ref | type_ref | ParameterizedType''' t[0] = t[1] def p_DefinedValue(t): '''DefinedValue : ext_val_ref | identifier''' t[0] = t[1] # 15 Assigning types and values ----------------------------------------------- # 15.1 def p_TypeAssignment (t): 'TypeAssignment : UCASE_IDENT ASSIGNMENT Type' t[0] = t[3] t[0].SetName(t[1]) # 15.2 def p_ValueAssignment (t): 'ValueAssignment : identifier Type ASSIGNMENT Value' t[0] = value_assign (ident = t[1], typ = t[2], val = t[4]) # 16 Definition of types and values ------------------------------------------- # 16.1 def p_Type (t): '''Type : BuiltinType | ReferencedType | ConstrainedType''' t[0] = t[1] # 16.2 def p_BuiltinType (t): '''BuiltinType : AnyType | BitStringType | BooleanType | CharacterStringType | ChoiceType | EnumeratedType | IntegerType | NullType | ObjectIdentifierType | OctetStringType | RealType | SequenceType | SequenceOfType | SetType | SetOfType | selection_type | TaggedType''' t[0] = t[1] # 16.3 def p_ReferencedType (t): '''ReferencedType : DefinedType | UsefulType''' t[0] = t[1] def p_ext_type_ref (t): 'ext_type_ref : type_ref DOT type_ref' # XXX coerce 1st type_ref to module_ref t[0] = Node ('ext_type_ref', module = t[1], typ = t[3]) # 16.5 def p_NamedType (t): 'NamedType : identifier Type' t[0] = t[2] t[0].SetName (t[1]) # 16.7 def p_Value (t): '''Value : BuiltinValue | ReferencedValue''' t[0] = t[1] # 16.9 def p_BuiltinValue (t): '''BuiltinValue : BooleanValue | ObjectIdentifierValue | special_real_val | SignedNumber | SequenceValue | hex_string | binary_string | char_string''' # XXX we don't support {data} here t[0] = t[1] # 16.11 def p_ReferencedValue (t): '''ReferencedValue : DefinedValue''' t[0] = t[1] # 16.13 #def p_NamedValue (t): # 'NamedValue : identifier Value' # t[0] = Node ('NamedValue', ident = t[1], value = t[2]) # 17 Notation for the boolean type -------------------------------------------- # 17.1 def p_BooleanType (t): 'BooleanType : BOOLEAN' t[0] = BooleanType () # 17.2 def p_BooleanValue (t): '''BooleanValue : TRUE | FALSE''' t[0] = t[1] # 18 Notation for the integer type -------------------------------------------- # 18.1 def p_IntegerType_1 (t): 'IntegerType : INTEGER' t[0] = IntegerType (named_list = None) def p_IntegerType_2 (t): 'IntegerType : INTEGER LBRACE NamedNumberList RBRACE' t[0] = IntegerType (named_list = t[3]) def p_NamedNumberList_1 (t): 'NamedNumberList : NamedNumber' t[0] = [t[1]] def p_NamedNumberList_2 (t): 'NamedNumberList : NamedNumberList COMMA NamedNumber' t[0] = t[1] + [t[3]] def p_NamedNumber (t): '''NamedNumber : identifier LPAREN SignedNumber RPAREN | identifier LPAREN DefinedValue RPAREN''' t[0] = NamedNumber (ident = t[1], val = t[3]) def p_SignedNumber_1 (t): 'SignedNumber : NUMBER' t[0] = t [1] def p_SignedNumber_2 (t): 'SignedNumber : MINUS NUMBER' t[0] = '-' + t[2] # 19 Notation for the enumerated type ----------------------------------------- # 19.1 def p_EnumeratedType (t): 'EnumeratedType : ENUMERATED LBRACE Enumerations RBRACE' t[0] = EnumeratedType (val = t[3]['val'], ext = t[3]['ext']) def p_Enumerations_1 (t): 'Enumerations : Enumeration' t[0] = { 'val' : t[1], 'ext' : None } def p_Enumerations_2 (t): 'Enumerations : Enumeration COMMA ELLIPSIS ExceptionSpec' t[0] = { 'val' : t[1], 'ext' : [] } def p_Enumerations_3 (t): 'Enumerations : Enumeration COMMA ELLIPSIS ExceptionSpec COMMA Enumeration' t[0] = { 'val' : t[1], 'ext' : t[6] } def p_Enumeration_1 (t): 'Enumeration : EnumerationItem' t[0] = [t[1]] def p_Enumeration_2 (t): 'Enumeration : Enumeration COMMA EnumerationItem' t[0] = t[1] + [t[3]] def p_EnumerationItem (t): '''EnumerationItem : Identifier | NamedNumber''' t[0] = t[1] def p_Identifier (t): 'Identifier : identifier' t[0] = Node ('Identifier', ident = t[1]) # 20 Notation for the real type ----------------------------------------------- # 20.1 def p_RealType (t): 'RealType : REAL' t[0] = RealType () # 21 Notation for the bitstring type ------------------------------------------ # 21.1 def p_BitStringType_1 (t): 'BitStringType : BIT STRING' t[0] = BitStringType (named_list = None) def p_BitStringType_2 (t): 'BitStringType : BIT STRING LBRACE NamedBitList RBRACE' t[0] = BitStringType (named_list = t[4]) def p_NamedBitList_1 (t): 'NamedBitList : NamedBit' t[0] = [t[1]] def p_NamedBitList_2 (t): 'NamedBitList : NamedBitList COMMA NamedBit' t[0] = t[1] + [t[3]] def p_NamedBit (t): '''NamedBit : identifier LPAREN NUMBER RPAREN | identifier LPAREN DefinedValue RPAREN''' t[0] = NamedNumber (ident = t[1], val = t[3]) # 22 Notation for the octetstring type ---------------------------------------- # 22.1 def p_OctetStringType (t): 'OctetStringType : OCTET STRING' t[0] = OctetStringType () # 23 Notation for the null type ----------------------------------------------- # 23.1 def p_NullType (t): 'NullType : NULL' t[0] = NullType () # 23.3 #def p_NullValue (t): # 'NullValue : NULL' # t[0] = t[1] # 24 Notation for sequence types ---------------------------------------------- # 24.1 def p_SequenceType_1 (t): 'SequenceType : SEQUENCE LBRACE RBRACE' t[0] = SequenceType (elt_list = []) def p_SequenceType_2 (t): 'SequenceType : SEQUENCE LBRACE ComponentTypeLists RBRACE' if t[3].has_key('ext_list'): t[0] = SequenceType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list']) else: t[0] = SequenceType (elt_list = t[3]['elt_list']) def p_ExtensionAndException_1 (t): 'ExtensionAndException : ELLIPSIS' t[0] = [] def p_OptionalExtensionMarker_1 (t): 'OptionalExtensionMarker : COMMA ELLIPSIS' t[0] = True def p_OptionalExtensionMarker_2 (t): 'OptionalExtensionMarker : ' t[0] = False def p_ComponentTypeLists_1 (t): 'ComponentTypeLists : element_type_list' t[0] = {'elt_list' : t[1]} def p_ComponentTypeLists_2 (t): 'ComponentTypeLists : element_type_list COMMA ExtensionAndException extension_additions OptionalExtensionMarker' t[0] = {'elt_list' : t[1], 'ext_list' : t[4]} def p_ComponentTypeLists_3 (t): 'ComponentTypeLists : ExtensionAndException extension_additions OptionalExtensionMarker' t[0] = {'elt_list' : [], 'ext_list' : t[2]} def p_extension_additions_1 (t): 'extension_additions : extension_addition_list' t[0] = t[1] def p_extension_additions_2 (t): 'extension_additions : ' t[0] = [] def p_extension_addition_list_1 (t): 'extension_addition_list : COMMA extension_addition' t[0] = [t[2]] def p_extension_addition_list_2 (t): 'extension_addition_list : extension_addition_list COMMA extension_addition' t[0] = t[1] + [t[3]] def p_extension_addition_1 (t): 'extension_addition : element_type' t[0] = t[1] def p_element_type_list_1 (t): 'element_type_list : element_type' t[0] = [t[1]] def p_element_type_list_2 (t): 'element_type_list : element_type_list COMMA element_type' t[0] = t[1] + [t[3]] def p_element_type_1 (t): 'element_type : NamedType' t[0] = Node ('elt_type', val = t[1], optional = 0) def p_element_type_2 (t): 'element_type : NamedType OPTIONAL' t[0] = Node ('elt_type', val = t[1], optional = 1) def p_element_type_3 (t): 'element_type : NamedType DEFAULT Value' t[0] = Node ('elt_type', val = t[1], optional = 1, default = t[3]) # /* # * this rules uses NamedValue instead of Value # * for the stupid choice value syntax (fieldname value) # * it should be like a set/seq value (ie with # * enclosing { } # */ # XXX get to COMPONENTS later # 24.17 def p_SequenceValue_1 (t): 'SequenceValue : LBRACE RBRACE' t[0] = [] #def p_SequenceValue_2 (t): # 'SequenceValue : LBRACE ComponentValueList RBRACE' # t[0] = t[2] #def p_ComponentValueList_1 (t): # 'ComponentValueList : NamedValue' # t[0] = [t[1]] #def p_ComponentValueList_2 (t): # 'ComponentValueList : ComponentValueList COMMA NamedValue' # t[0] = t[1] + [t[3]] # 25 Notation for sequence-of types ------------------------------------------- # 25.1 def p_SequenceOfType (t): '''SequenceOfType : SEQUENCE OF Type | SEQUENCE OF NamedType''' t[0] = SequenceOfType (val = t[3], size_constr = None) # 26 Notation for set types --------------------------------------------------- # 26.1 def p_SetType_1 (t): 'SetType : SET LBRACE RBRACE' if t[3].has_key('ext_list'): t[0] = SetType (elt_list = []) def p_SetType_2 (t): 'SetType : SET LBRACE ComponentTypeLists RBRACE' if t[3].has_key('ext_list'): t[0] = SetType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list']) else: t[0] = SetType (elt_list = t[3]['elt_list']) # 27 Notation for set-of types ------------------------------------------------ # 27.1 def p_SetOfType (t): '''SetOfType : SET OF Type | SET OF NamedType''' t[0] = SetOfType (val = t[3]) # 28 Notation for choice types ------------------------------------------------ # 28.1 def p_ChoiceType (t): 'ChoiceType : CHOICE LBRACE alternative_type_lists RBRACE' if t[3].has_key('ext_list'): t[0] = ChoiceType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list']) else: t[0] = ChoiceType (elt_list = t[3]['elt_list']) def p_alternative_type_lists_1 (t): 'alternative_type_lists : alternative_type_list' t[0] = {'elt_list' : t[1]} def p_alternative_type_lists_2 (t): '''alternative_type_lists : alternative_type_list COMMA ExtensionAndException extension_addition_alternatives OptionalExtensionMarker''' t[0] = {'elt_list' : t[1], 'ext_list' : t[4]} def p_extension_addition_alternatives_1 (t): 'extension_addition_alternatives : extension_addition_alternatives_list' t[0] = t[1] def p_extension_addition_alternatives_2 (t): 'extension_addition_alternatives : ' t[0] = [] def p_extension_addition_alternatives_list_1 (t): 'extension_addition_alternatives_list : COMMA extension_addition_alternative' t[0] = [t[2]] def p_extension_addition_alternatives_list_2 (t): 'extension_addition_alternatives_list : extension_addition_alternatives_list COMMA extension_addition_alternative' t[0] = t[1] + [t[3]] def p_extension_addition_alternative_1 (t): 'extension_addition_alternative : NamedType' t[0] = t[1] def p_alternative_type_list_1 (t): 'alternative_type_list : NamedType' t[0] = [t[1]] def p_alternative_type_list_2 (t): 'alternative_type_list : alternative_type_list COMMA NamedType' t[0] = t[1] + [t[3]] def p_selection_type (t): # XXX what is this? 'selection_type : identifier LT Type' return Node ('seltype', ident = t[1], typ = t[3]) # 30 Notation for tagged types ------------------------------------------------ # 30.1 def p_TaggedType_1 (t): 'TaggedType : Tag Type' t[1].mode = 'default' t[0] = t[2] t[0].SetTag(t[1]) def p_TaggedType_2 (t): '''TaggedType : Tag IMPLICIT Type | Tag EXPLICIT Type''' t[1].mode = t[2] t[0] = t[3] t[0].SetTag(t[1]) def p_Tag (t): 'Tag : LBRACK Class ClassNumber RBRACK' t[0] = Tag(cls = t[2], num = t[3]) def p_ClassNumber_1 (t): 'ClassNumber : number' t[0] = t[1] def p_ClassNumber_2 (t): 'ClassNumber : DefinedValue' t[0] = t[1] def p_Class_1 (t): '''Class : UNIVERSAL | APPLICATION | PRIVATE''' t[0] = t[1] def p_Class_2 (t): 'Class :' t[0] = 'CONTEXT' def p_AnyType (t): 'AnyType : ANY' t[0] = AnyType () #def p_any_type_2 (t): # 'any_type : ANY DEFINED BY identifier' # t[0] = Literal (val='asn1.ANY_constr(def_by="%s")' % t[4]) # XXX # 31 Notation for the object identifier type ---------------------------------- # 31.1 def p_ObjectIdentifierType (t): 'ObjectIdentifierType : OBJECT IDENTIFIER' t[0] = ObjectIdentifierType () # 31.3 def p_ObjectIdentifierValue (t): 'ObjectIdentifierValue : LBRACE oid_comp_list RBRACE' t[0] = ObjectIdentifierValue (comp_list=t[2]) def p_oid_comp_list_1 (t): 'oid_comp_list : oid_comp_list oid_component' t[0] = t[1] + [t[2]] def p_oid_comp_list_2 (t): 'oid_comp_list : oid_component' t[0] = [t[1]] def p_oid_component (t): '''oid_component : number_form | name_form | name_and_number_form''' t[0] = t[1] def p_number_form (t): 'number_form : NUMBER' t [0] = t[1] # 36 Notation for character string types -------------------------------------- # 36.1 def p_CharacterStringType (t): '''CharacterStringType : RestrictedCharacterStringType | UnrestrictedCharacterStringType''' t[0] = t[1] # 37 Definition of restricted character string types -------------------------- def p_RestrictedCharacterStringType_1 (t): 'RestrictedCharacterStringType : BMPString' t[0] = BMPStringType () def p_RestrictedCharacterStringType_2 (t): 'RestrictedCharacterStringType : GeneralString' t[0] = GeneralStringType () def p_RestrictedCharacterStringType_3 (t): 'RestrictedCharacterStringType : GraphicString' t[0] = GraphicStringType () def p_RestrictedCharacterStringType_4 (t): 'RestrictedCharacterStringType : IA5String' t[0] = IA5StringType () def p_RestrictedCharacterStringType_5 (t): 'RestrictedCharacterStringType : ISO646String' t[0] = ISO646StringType () def p_RestrictedCharacterStringType_6 (t): 'RestrictedCharacterStringType : NumericString' t[0] = NumericStringType () def p_RestrictedCharacterStringType_7 (t): 'RestrictedCharacterStringType : PrintableString' t[0] = PrintableStringType () def p_RestrictedCharacterStringType_8 (t): 'RestrictedCharacterStringType : TeletexString' t[0] = TeletexStringType () def p_RestrictedCharacterStringType_9 (t): 'RestrictedCharacterStringType : T61String' t[0] = T61StringType () def p_RestrictedCharacterStringType_10 (t): 'RestrictedCharacterStringType : UniversalString' t[0] = UniversalStringType () def p_RestrictedCharacterStringType_11 (t): 'RestrictedCharacterStringType : UTF8String' t[0] = UTF8StringType () def p_RestrictedCharacterStringType_12 (t): 'RestrictedCharacterStringType : VideotexString' t[0] = VideotexStringType () def p_RestrictedCharacterStringType_13 (t): 'RestrictedCharacterStringType : VisibleString' t[0] = VisibleStringType () # 40 Definition of unrestricted character string types ------------------------ # 40.1 def p_UnrestrictedCharacterStringType (t): 'UnrestrictedCharacterStringType : CHARACTER STRING' t[0] = UnrestrictedCharacterStringType () # 41 Notation for types defined in clauses 42 to 44 --------------------------- # 42 Generalized time --------------------------------------------------------- def p_UsefulType_1 (t): 'UsefulType : GeneralizedTime' t[0] = GeneralizedTime() # 43 Universal time ----------------------------------------------------------- def p_UsefulType_2 (t): 'UsefulType : UTCTime' t[0] = UTCTime() # 44 The object descriptor type ----------------------------------------------- def p_UsefulType_3 (t): 'UsefulType : ObjectDescriptor' t[0] = ObjectDescriptor() # 45 Constrained types -------------------------------------------------------- # 45.1 def p_ConstrainedType_1 (t): 'ConstrainedType : Type Constraint' t[0] = t[1] t[0].AddConstraint(t[2]) def p_ConstrainedType_2 (t): 'ConstrainedType : TypeWithConstraint' t[0] = t[1] # 45.5 def p_TypeWithConstraint_1 (t): '''TypeWithConstraint : SET Constraint OF Type | SET SizeConstraint OF Type''' t[0] = SetOfType (val = t[4], constr = t[2]) def p_TypeWithConstraint_2 (t): '''TypeWithConstraint : SEQUENCE Constraint OF Type | SEQUENCE SizeConstraint OF Type''' t[0] = SequenceOfType (val = t[4], constr = t[2]) def p_TypeWithConstraint_3 (t): '''TypeWithConstraint : SET Constraint OF NamedType | SET SizeConstraint OF NamedType''' t[0] = SetOfType (val = t[4], constr = t[2]) def p_TypeWithConstraint_4 (t): '''TypeWithConstraint : SEQUENCE Constraint OF NamedType | SEQUENCE SizeConstraint OF NamedType''' t[0] = SequenceOfType (val = t[4], constr = t[2]) # 45.6 # 45.7 def p_Constraint (t): 'Constraint : LPAREN ConstraintSpec ExceptionSpec RPAREN' t[0] = t[2] def p_ConstraintSpec (t): '''ConstraintSpec : ElementSetSpecs | GeneralConstraint''' t[0] = t[1] # 46 Element set specification ------------------------------------------------ # 46.1 def p_ElementSetSpecs_1 (t): 'ElementSetSpecs : RootElementSetSpec' t[0] = t[1] def p_ElementSetSpecs_2 (t): 'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS' t[0] = t[1] t[0].ext = True # skip compound constraints, only simple ones are supported def p_RootElementSetSpec_1 (t): 'RootElementSetSpec : SubtypeElements' t[0] = t[1] # 47 Subtype elements --------------------------------------------------------- # 47.1 General def p_SubtypeElements (t): '''SubtypeElements : SingleValue | ContainedSubtype | ValueRange | PermittedAlphabet | SizeConstraint | InnerTypeConstraints | PatternConstraint''' t[0] = t[1] # 47.2 Single value # 47.2.1 def p_SingleValue (t): 'SingleValue : Value' t[0] = Constraint(type = 'SingleValue', subtype = t[1]) # 47.3 Contained subtype # 47.3.1 def p_ContainedSubtype (t): 'ContainedSubtype : Includes Type' t[0] = Constraint(type = 'ContainedSubtype', subtype = t[2]) def p_Includes (t): '''Includes : INCLUDES | ''' # 47.4 Value range # 47.4.1 def p_ValueRange (t): 'ValueRange : lower_end_point RANGE upper_end_point' t[0] = Constraint(type = 'ValueRange', subtype = [t[1], t[3]]) # 47.4.3 def p_lower_end_point_1 (t): 'lower_end_point : lower_end_value ' t[0] = t[1] def p_lower_end_point_2 (t): 'lower_end_point : lower_end_value LT' # XXX LT first? t[0] = t[1] # but not inclusive range def p_upper_end_point_1 (t): 'upper_end_point : upper_end_value' t[0] = t[1] def p_upper_end_point_2 (t): 'upper_end_point : LT upper_end_value' t[0] = t[1] # but not inclusive range def p_lower_end_value (t): '''lower_end_value : Value | MIN''' t[0] = t[1] # XXX def p_upper_end_value (t): '''upper_end_value : Value | MAX''' t[0] = t[1] # 47.5 Size constraint # 47.5.1 def p_SizeConstraint (t): 'SizeConstraint : SIZE Constraint' t[0] = Constraint (type = 'Size', subtype = t[2]) # 47.6 Type constraint # 47.6.1 #def p_TypeConstraint (t): # 'TypeConstraint : Type' # t[0] = Constraint (type = 'Type', subtype = t[2]) # 47.7 Permitted alphabet # 47.7.1 def p_PermittedAlphabet (t): 'PermittedAlphabet : FROM Constraint' t[0] = Constraint (type = 'From', subtype = t[2]) # 47.8 Inner subtyping # 47.8.1 def p_InnerTypeConstraints (t): '''InnerTypeConstraints : WITH COMPONENT SingleTypeConstraint | WITH COMPONENTS MultipleTypeConstraints''' pass # ignore PER invisible constraint # 47.8.3 def p_SingleTypeConstraint (t): 'SingleTypeConstraint : Constraint' t[0] = t[1] # 47.8.4 def p_MultipleTypeConstraints (t): '''MultipleTypeConstraints : FullSpecification | PartialSpecification''' t[0] = t[1] def p_FullSpecification (t): 'FullSpecification : LBRACE TypeConstraints RBRACE' t[0] = t[2] def p_PartialSpecification (t): 'PartialSpecification : LBRACE ELLIPSIS COMMA TypeConstraints RBRACE' t[0] = t[4] def p_TypeConstraints_1 (t): 'TypeConstraints : named_constraint' t [0] = [t[1]] def p_TypeConstraints_2 (t): 'TypeConstraints : TypeConstraints COMMA named_constraint' t[0] = t[1] + [t[3]] def p_named_constraint_1 (t): 'named_constraint : identifier constraint' return Node ('named_constraint', ident = t[1], constr = t[2]) def p_named_constraint_2 (t): 'named_constraint : constraint' return Node ('named_constraint', constr = t[1]) def p_constraint (t): 'constraint : value_constraint presence_constraint' t[0] = Node ('constraint', value = t[1], presence = t[2]) def p_value_constraint_1 (t): 'value_constraint : Constraint' t[0] = t[1] def p_value_constraint_2 (t): 'value_constraint : ' pass def p_presence_constraint_1 (t): '''presence_constraint : PRESENT | ABSENT | OPTIONAL''' t[0] = t[1] def p_presence_constraint_2 (t): '''presence_constraint : ''' pass # 47.9 Pattern constraint # 47.9.1 def p_PatternConstraint (t): 'PatternConstraint : PATTERN Value' t[0] = Constraint (type = 'Pattern', subtype = t[2]) # 49 The exception identifier # 49.4 def p_ExceptionSpec (t): 'ExceptionSpec : ' pass # /*-----------------------------------------------------------------------*/ # /* Value Notation Productions */ # /*-----------------------------------------------------------------------*/ def p_ext_val_ref (t): 'ext_val_ref : type_ref DOT identifier' # XXX coerce type_ref to module_ref return Node ('ext_val_ref', module = t[1], ident = t[3]) def p_special_real_val (t): '''special_real_val : PLUS_INFINITY | MINUS_INFINITY''' t[0] = t[1] # Note that Z39.50 v3 spec has upper-case here for, e.g., SUTRS. # I've hacked the grammar to be liberal about what it accepts. # XXX should have -strict command-line flag to only accept lowercase # here, since that's what X.208 says. def p_name_form (t): '''name_form : type_ref | identifier''' t[0] = t[1] def p_name_and_number_form_1 (t): '''name_and_number_form : identifier LPAREN number_form RPAREN | type_ref LPAREN number_form RPAREN''' t[0] = Node ('name_and_number', ident = t[1], number = t[3]) def p_name_and_number_form_2 (t): 'name_and_number_form : identifier LPAREN DefinedValue RPAREN' t[0] = Node ('name_and_number', ident = t[1], val = t[3]) # see X.208 if you are dubious about lcase only for identifier def p_identifier (t): 'identifier : LCASE_IDENT' t[0] = t[1] def p_binary_string (t): 'binary_string : BSTRING' t[0] = t[1] def p_hex_string (t): 'hex_string : HSTRING' t[0] = t[1] def p_char_string (t): 'char_string : QSTRING' t[0] = t[1] def p_number (t): 'number : NUMBER' t[0] = t[1] #--- ITU-T Recommendation X.682 ----------------------------------------------- # 8 General constraint specification ------------------------------------------ # 8.1 def p_GeneralConstraint (t): '''GeneralConstraint : UserDefinedConstraint''' # | TableConstraint # | ContentsConstraint'' t[0] = t[1] # 9 User-defined constraints -------------------------------------------------- # 9.1 def p_UserDefinedConstraint (t): 'UserDefinedConstraint : CONSTRAINED BY LBRACE UserDefinedConstraintParameterList RBRACE' t[0] = Constraint(type = 'UserDefined', subtype = t[4]) def p_UserDefinedConstraintParameterList_1 (t): 'UserDefinedConstraintParameterList : ' t[0] = [] def p_UserDefinedConstraintParameterList_2 (t): 'UserDefinedConstraintParameterList : UserDefinedConstraintParameter' t[0] = [t[1]] def p_UserDefinedConstraintParameterList_3 (t): 'UserDefinedConstraintParameterList : UserDefinedConstraintParameterList COMMA UserDefinedConstraintParameter' t[0] = t[1] + [t[3]] # 9.3 def p_UserDefinedConstraintParameter (t): 'UserDefinedConstraintParameter : type_ref' t[0] = t[1] #--- ITU-T Recommendation X.683 ----------------------------------------------- # 8 Parameterized assignments ------------------------------------------------- # 8.1 # 8.2 def p_ParameterizedTypeAssignment (t): 'ParameterizedTypeAssignment : UCASE_IDENT ParameterList ASSIGNMENT Type' t[0] = t[4] t[0].SetName(t[1] + 'xxx') # 8.3 def p_ParameterList (t): 'ParameterList : LBRACE Parameters RBRACE' t[0] = t[2] def p_Parameters_1 (t): 'Parameters : Parameter' t[0] = [t[1]] def p_Parameters_2 (t): 'Parameters : Parameters COMMA Parameter' t[0] = t[1] + [t[3]] def p_Parameter_1 (t): 'Parameter : Type COLON Reference' t[0] = [t[1], t[3]] def p_Parameter_2 (t): 'Parameter : Reference' t[0] = t[1] # 9 Referencing parameterized definitions ------------------------------------- # 9.1 def p_ParameterizedReference (t): 'ParameterizedReference : type_ref LBRACE RBRACE' t[0] = t[1] t[0].val += 'xxx' # 9.2 def p_ParameterizedType (t): 'ParameterizedType : type_ref ActualParameterList' t[0] = t[1] t[0].val += 'xxx' # 9.5 def p_ActualParameterList (t): 'ActualParameterList : LBRACE ActualParameters RBRACE' t[0] = t[2] def p_ActualParameters_1 (t): 'ActualParameters : ActualParameter' t[0] = [t[1]] def p_ActualParameters_2 (t): 'ActualParameters : ActualParameters COMMA ActualParameter' t[0] = t[1] + [t[3]] def p_ActualParameter (t): '''ActualParameter : Type | Value''' t[0] = t[1] def p_error(t): raise ParseError(str(t)) def testlex (s): lexer.input (s) while 1: token = lexer.token () if not token: break print token def do_module (ast, defined_dict): assert (ast.type == 'Module') ctx = Ctx (defined_dict) print ast.to_python (ctx) print ctx.output_assignments () print ctx.output_pyquotes () def eth_do_module (ast, ectx): assert (ast.type == 'Module') if ectx.dbg('s'): print ast.str_depth(0) ast.to_eth(ectx) ectx.eth_prepare() if ectx.dbg('a'): print "\n# Assignments" print "\n".join(ectx.assign_ord) print "\n# Value assignments" print "\n".join(ectx.vassign_ord) if ectx.dbg('t'): print "\n# Imported Types" print "%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol") print "-" * 100 for t in ectx.type_imp: print "%-40s %-24s %-24s" % (t, ectx.type[t]['import'], ectx.type[t]['proto']) print "\n# Imported Values" print "%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol") print "-" * 100 for t in ectx.value_imp: print "%-40s %-24s %-24s" % (t, ectx.value[t]['import'], ectx.value[t]['proto']) print "\n# Exported Types" print "%-31s %s" % ("Ethereal type", "Export Flag") print "-" * 100 for t in ectx.eth_export_ord: print "%-31s 0x%02X" % (t, ectx.eth_type[t]['export']) print "\n# Exported Values" print "%-40s %s" % ("Ethereal name", "Value") print "-" * 100 for v in ectx.eth_vexport_ord: print "%-40s %s" % (v, ectx.eth_value[v]['value']) print "\n# ASN.1 Types" print "%-49s %-24s %-24s" % ("ASN.1 unique name", "'tname'", "Ethereal type") print "-" * 100 for t in ectx.type_ord: print "%-49s %-24s %-24s" % (t, ectx.type[t]['tname'], ectx.type[t]['ethname']) print "\n# Ethereal Types" print "Ethereal type References (ASN.1 types)" print "-" * 100 for t in ectx.eth_type_ord: print "%-31s %d" % (t, len(ectx.eth_type[t]['ref'])), print ', '.join(ectx.eth_type[t]['ref']) print "\n# ASN.1 Values" print "%-40s %-18s %s" % ("ASN.1 unique name", "Type", "Value") print "-" * 100 for v in ectx.value_ord: if isinstance (ectx.value[v]['value'], Value): print "%-40s %-18s %s" % (v, ectx.value[v]['type'].eth_tname(), ectx.value[v]['value'].to_str()) else: print "%-40s %-18s %s" % (v, ectx.value[v]['type'].eth_tname(), ectx.value[v]['value']) print "\n# Ethereal Values" print "%-40s %s" % ("Ethereal name", "Value") print "-" * 100 for v in ectx.eth_value_ord: print "%-40s %s" % (v, ectx.eth_value[v]['value']) print "\n# ASN.1 Fields" print "ASN.1 unique name Ethereal name ASN.1 type" print "-" * 100 for f in (ectx.pdu_ord + ectx.field_ord): print "%-40s %-20s %s" % (f, ectx.field[f]['ethname'], ectx.field[f]['type']) print "\n# Ethereal Fields" print "Ethereal name Ethereal type References (ASN.1 fields)" print "-" * 100 for f in (ectx.eth_hfpdu_ord + ectx.eth_hf_ord): print "%-30s %-20s %s" % (f, ectx.eth_hf[f]['ethtype'], len(ectx.eth_hf[f]['ref'])), print ', '.join(ectx.eth_hf[f]['ref']) #print "\n# Order after dependencies" #print '\n'.join(ectx.eth_type_ord1) print "\n# Cyclic dependencies" for c in ectx.eth_dep_cycle: print ' -> '.join(c) ectx.dupl_report() if (not ectx.output.outnm): ectx.output.outnm = ectx.proto ectx.eth_output_hf() ectx.eth_output_ett() ectx.eth_output_types() ectx.eth_output_hf_arr() ectx.eth_output_ett_arr() ectx.eth_output_export() if ectx.expcnf: ectx.eth_output_expcnf() ectx.eth_output_val() ectx.eth_output_valexp() ectx.eth_output_dis_hnd() ectx.eth_output_dis_reg() ectx.eth_output_dis_tab() ectx.conform.unused_report() def testyacc(s, fn, defined_dict): ast = yacc.parse(s, debug=0) time_str = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) print """#!/usr/bin/env python # Auto-generated from %s at %s from PyZ3950 import asn1""" % (fn, time_str) for module in ast: eth_do_module (module, defined_dict) # Ethereal compiler def eth_usage(): print """ asn2eth [-h|?] [-d dbg] [-b] [-p proto] [-c conform_file] [-e] input_file -h|? : usage -d dbg : debug output, dbg = [l][y][p][s][a][t] l - lex y - yacc p - parsing s - internal ASN.1 structure a - list of assignments t - tables -b : BER (default is PER) -X : original dissector API (see Note) -p proto : protocol name (default is module-name from input_file) -o name : output files name core (default is ) -O dir : output directory -c conform_file : conformation file -e : create conformation file for exported types -s template : single file output (templete is input file without .c/.h extension) -k : keep intermediate files though single file output is used input_file : input ASN.1 file Note: It can create output for an original or a new PER/BER dissectors API, but the new PER/BER dissectors API is not implemented now. """ def eth_main(): print "ASN.1 to Ethereal dissector compiler"; try: opts, args = getopt.getopt(sys.argv[1:], "h?d:bXp:o:O:c:es:k"); except getopt.GetoptError: eth_usage(); sys.exit(2) if len(args) != 1: eth_usage(); sys.exit(2) fn = args[0]; conform = EthCnf() output = EthOut() ectx = EthCtx(conform, output) ectx.encoding = 'per' ectx.proto = None ectx.new = True ectx.dbgopt = '' ectx.new = True ectx.expcnf = False ectx.output.outnm = None ectx.output.single_file = None for o, a in opts: if o in ("-h", "-?"): eth_usage(); sys.exit(2) if o in ("-b",): ectx.encoding = 'ber' if o in ("-p",): ectx.proto = a if o in ("-c",): ectx.conform.read(a) if o in ("-X",): ectx.new = False if o in ("-d",): ectx.dbgopt = a if o in ("-e",): ectx.expcnf = True if o in ("-o",): ectx.output.outnm = a if o in ("-O",): ectx.output.outdir = a if o in ("-s",): ectx.output.single_file = a if o in ("-k",): ectx.output.keep = True f = open(fn, "r") s = f.read(); f.close() (ld, yd, pd) = (0, 0, 0); if ectx.dbg('l'): ld = 1 if ectx.dbg('y'): yd = 1 if ectx.dbg('p'): pd = 2 lexer = lex.lex(debug=ld) yacc.yacc(method='SLR', debug=yd) ast = yacc.parse(s, lexer=lexer, debug=pd) for module in ast: eth_do_module(module, ectx) ectx.output.make_single_file() # Python compiler def main(): testfn = testyacc if len (sys.argv) == 1: while 1: s = raw_input ('Query: ') if len (s) == 0: break testfn (s, 'console', {}) else: defined_dict = {} for fn in sys.argv [1:]: f = open (fn, "r") testfn (f.read (), fn, defined_dict) f.close () lexer.lineno = 1 #--- BODY --------------------------------------------------------------------- if __name__ == '__main__': if ('asn2eth' == os.path.splitext(os.path.basename(sys.argv[0]))[0].lower()): eth_main() else: main() #------------------------------------------------------------------------------