1#!/usr/bin/env python3
2
3#
4# asn2wrs.py
5# ASN.1 to Wireshark dissector compiler
6# Copyright 2004 Tomas Kukosa
7#
8# SPDX-License-Identifier: MIT
9#
10
11"""ASN.1 to Wireshark dissector compiler"""
12
13#
14# Compiler from ASN.1 specification to the Wireshark dissector
15#
16# Based on ASN.1 to Python compiler from Aaron S. Lav's PyZ3950 package licensed under the X Consortium license
17# https://www.pobox.com/~asl2/software/PyZ3950/
18# (ASN.1 to Python compiler functionality is broken but not removed, it could be revived if necessary)
19#
20# It requires Dave Beazley's PLY parsing package licensed under the LGPL (tested with version 2.3)
21# https://www.dabeaz.com/ply/
22#
23#
24# ITU-T Recommendation X.680 (07/2002),
25#   Information technology - Abstract Syntax Notation One (ASN.1): Specification of basic notation
26#
27# ITU-T Recommendation X.681 (07/2002),
28#   Information technology - Abstract Syntax Notation One (ASN.1): Information object specification
29#
30# ITU-T Recommendation X.682 (07/2002),
31#   Information technology - Abstract Syntax Notation One (ASN.1): Constraint specification
32#
33# ITU-T Recommendation X.683 (07/2002),
34#   Information technology - Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 specifications
35#
36# ITU-T Recommendation X.880 (07/1994),
37#   Information technology - Remote Operations: Concepts, model and notation
38#
39
40import warnings
41
42import re
43import sys
44import os
45import os.path
46import time
47import getopt
48import traceback
49
50try:
51    from ply import lex
52    from ply import yacc
53except ImportError:
54    # Fallback: use lex.py and yacc from the tools directory within the
55    # Wireshark source tree if python-ply is not installed.
56    import lex
57    import yacc
58
59if sys.version_info[0] < 3:
60    from string import maketrans
61
62
63# OID name -> number conversion table
64oid_names = {
65    '/itu-t' : 0,
66    '/itu'   : 0,
67    '/ccitt' : 0,
68    '/itu-r' : 0,
69    '0/recommendation' : 0,
70    '0.0/a' : 1,
71    '0.0/b' : 2,
72    '0.0/c' : 3,
73    '0.0/d' : 4,
74    '0.0/e' : 5,
75    '0.0/f' : 6,
76    '0.0/g' : 7,
77    '0.0/h' : 8,
78    '0.0/i' : 9,
79    '0.0/j' : 10,
80    '0.0/k' : 11,
81    '0.0/l' : 12,
82    '0.0/m' : 13,
83    '0.0/n' : 14,
84    '0.0/o' : 15,
85    '0.0/p' : 16,
86    '0.0/q' : 17,
87    '0.0/r' : 18,
88    '0.0/s' : 19,
89    '0.0/t' : 20,
90    '0.0/tseries' : 20,
91    '0.0/u' : 21,
92    '0.0/v' : 22,
93    '0.0/w' : 23,
94    '0.0/x' : 24,
95    '0.0/y' : 25,
96    '0.0/z' : 26,
97    '0/question' : 1,
98    '0/administration' : 2,
99    '0/network-operator' : 3,
100    '0/identified-organization' : 4,
101    '0/r-recommendation' : 5,
102    '0/data' : 9,
103    '/iso' : 1,
104    '1/standard' : 0,
105    '1/registration-authority' : 1,
106    '1/member-body' : 2,
107    '1/identified-organization' : 3,
108    '/joint-iso-itu-t' : 2,
109    '/joint-iso-ccitt' : 2,
110    '2/presentation' : 0,
111    '2/asn1' : 1,
112    '2/association-control' : 2,
113    '2/reliable-transfer' : 3,
114    '2/remote-operations' : 4,
115    '2/ds' : 5,
116    '2/directory' : 5,
117    '2/mhs' : 6,
118    '2/mhs-motis' : 6,
119    '2/ccr' : 7,
120    '2/oda' : 8,
121    '2/ms' : 9,
122    '2/osi-management' : 9,
123    '2/transaction-processing' : 10,
124    '2/dor' : 11,
125    '2/distinguished-object-reference' : 11,
126    '2/reference-data-transfe' : 12,
127    '2/network-layer' : 13,
128    '2/network-layer-management' : 13,
129    '2/transport-layer' : 14,
130    '2/transport-layer-management' : 14,
131    '2/datalink-layer' : 15,
132    '2/datalink-layer-managemen' : 15,
133    '2/datalink-layer-management-information' : 15,
134    '2/country' : 16,
135    '2/registration-procedures' : 17,
136    '2/registration-procedure' : 17,
137    '2/physical-layer' : 18,
138    '2/physical-layer-management' : 18,
139    '2/mheg' : 19,
140    '2/genericULS' : 20,
141    '2/generic-upper-layers-security' : 20,
142    '2/guls' : 20,
143    '2/transport-layer-security-protocol' : 21,
144    '2/network-layer-security-protocol' : 22,
145    '2/international-organizations' : 23,
146    '2/internationalRA' : 23,
147    '2/sios' : 24,
148    '2/uuid' : 25,
149    '2/odp' : 26,
150    '2/upu' : 40,
151}
152
153ITEM_FIELD_NAME = '_item'
154UNTAG_TYPE_NAME = '_untag'
155
156def asn2c(id):
157    return id.replace('-', '_').replace('.', '_').replace('&', '_')
158
159input_file = None
160g_conform = None
161lexer = None
162in_oid = False
163
164class LexError(Exception):
165    def __init__(self, tok, filename=None):
166        self.tok = tok
167        self.filename = filename
168        self.msg =  "Unexpected character %r" % (self.tok.value[0])
169        Exception.__init__(self, self.msg)
170    def __repr__(self):
171        return "%s:%d: %s" % (self.filename, self.tok.lineno, self.msg)
172    __str__ = __repr__
173
174
175class ParseError(Exception):
176    def __init__(self, tok, filename=None):
177        self.tok = tok
178        self.filename = filename
179        self.msg =  "Unexpected token %s(%r)" % (self.tok.type, self.tok.value)
180        Exception.__init__(self, self.msg)
181    def __repr__(self):
182        return "%s:%d: %s" % (self.filename, self.tok.lineno, self.msg)
183    __str__ = __repr__
184
185
186class DuplicateError(Exception):
187    def __init__(self, type, ident):
188        self.type = type
189        self.ident = ident
190        self.msg =  "Duplicate %s for %s" % (self.type, self.ident)
191        Exception.__init__(self, self.msg)
192    def __repr__(self):
193        return self.msg
194    __str__ = __repr__
195
196class CompError(Exception):
197    def __init__(self, msg):
198        self.msg =  msg
199        Exception.__init__(self, self.msg)
200    def __repr__(self):
201        return self.msg
202    __str__ = __repr__
203
204
205states = (
206  ('braceignore','exclusive'),
207)
208
209precedence = (
210  ('left', 'UNION', 'BAR'),
211  ('left', 'INTERSECTION', 'CIRCUMFLEX'),
212)
213# 11 ASN.1 lexical items
214
215static_tokens = {
216    r'::='    : 'ASSIGNMENT',  # 11.16 Assignment lexical item
217    r'\.\.'   : 'RANGE',       # 11.17 Range separator
218    r'\.\.\.' : 'ELLIPSIS',    # 11.18 Ellipsis
219    r'\[\['   : 'LVERBRACK',   # 11.19 Left version brackets
220    r'\]\]'   : 'RVERBRACK',   # 11.20 Right version brackets
221    # 11.26 Single character lexical items
222    r'\{' : 'LBRACE',
223    r'\}' : 'RBRACE',
224    r'<'  : 'LT',
225    #r'>'  : 'GT',
226    r','  : 'COMMA',
227    r'\.' : 'DOT',
228    r'\(' : 'LPAREN',
229    r'\)' : 'RPAREN',
230    r'\[' : 'LBRACK',
231    r'\]' : 'RBRACK',
232    r'-'  : 'MINUS',
233    r':'  : 'COLON',
234    #r'='  : 'EQ',
235    #r'"'  : 'QUOTATION',
236    #r"'"  : 'APOSTROPHE',
237    r';'  : 'SEMICOLON',
238    r'@'  : 'AT',
239    r'\!' : 'EXCLAMATION',
240    r'\^' : 'CIRCUMFLEX',
241    r'\&' : 'AMPERSAND',
242    r'\|' : 'BAR'
243}
244
245# 11.27 Reserved words
246
247# all keys in reserved_words must start w/ upper case
248reserved_words = {
249    'ABSENT'      : 'ABSENT',
250    'ABSTRACT-SYNTAX' : 'ABSTRACT_SYNTAX',
251    'ALL'         : 'ALL',
252    'APPLICATION' : 'APPLICATION',
253    'AUTOMATIC'   : 'AUTOMATIC',
254    'BEGIN'       : 'BEGIN',
255    'BIT'         : 'BIT',
256    'BOOLEAN'     : 'BOOLEAN',
257    'BY'          : 'BY',
258    'CHARACTER'   : 'CHARACTER',
259    'CHOICE'      : 'CHOICE',
260    'CLASS'       : 'CLASS',
261    'COMPONENT'   : 'COMPONENT',
262    'COMPONENTS'  : 'COMPONENTS',
263    'CONSTRAINED' : 'CONSTRAINED',
264    'CONTAINING'  : 'CONTAINING',
265    'DEFAULT'     : 'DEFAULT',
266    'DEFINITIONS' : 'DEFINITIONS',
267    'EMBEDDED'    : 'EMBEDDED',
268#    'ENCODED'     : 'ENCODED',
269    'END'         : 'END',
270    'ENUMERATED'  : 'ENUMERATED',
271#    'EXCEPT'      : 'EXCEPT',
272    'EXPLICIT'    : 'EXPLICIT',
273    'EXPORTS'     : 'EXPORTS',
274#    'EXTENSIBILITY' : 'EXTENSIBILITY',
275    'EXTERNAL'    : 'EXTERNAL',
276    'FALSE'       : 'FALSE',
277    'FROM'        : 'FROM',
278    'GeneralizedTime' : 'GeneralizedTime',
279    'IDENTIFIER'  : 'IDENTIFIER',
280    'IMPLICIT'    : 'IMPLICIT',
281#    'IMPLIED'     : 'IMPLIED',
282    'IMPORTS'     : 'IMPORTS',
283    'INCLUDES'    : 'INCLUDES',
284    'INSTANCE'    : 'INSTANCE',
285    'INTEGER'     : 'INTEGER',
286    'INTERSECTION' : 'INTERSECTION',
287    'MAX'         : 'MAX',
288    'MIN'         : 'MIN',
289    'MINUS-INFINITY' : 'MINUS_INFINITY',
290    'NULL'        : 'NULL',
291    'OBJECT'      : 'OBJECT',
292    'ObjectDescriptor' : 'ObjectDescriptor',
293    'OCTET'       : 'OCTET',
294    'OF'          : 'OF',
295    'OPTIONAL'    : 'OPTIONAL',
296    'PATTERN'     : 'PATTERN',
297    'PDV'         : 'PDV',
298    'PLUS-INFINITY' : 'PLUS_INFINITY',
299    'PRESENT'     : 'PRESENT',
300    'PRIVATE'     : 'PRIVATE',
301    'REAL'        : 'REAL',
302    'RELATIVE-OID' : 'RELATIVE_OID',
303    'SEQUENCE'    : 'SEQUENCE',
304    'SET'         : 'SET',
305    'SIZE'        : 'SIZE',
306    'STRING'      : 'STRING',
307    'SYNTAX'      : 'SYNTAX',
308    'TAGS'        : 'TAGS',
309    'TRUE'        : 'TRUE',
310    'TYPE-IDENTIFIER' : 'TYPE_IDENTIFIER',
311    'UNION'       : 'UNION',
312    'UNIQUE'      : 'UNIQUE',
313    'UNIVERSAL'   : 'UNIVERSAL',
314    'UTCTime'     : 'UTCTime',
315    'WITH'        : 'WITH',
316# X.208 obsolete but still used
317    'ANY'         : 'ANY',
318    'DEFINED'     : 'DEFINED',
319}
320
321for k in list(static_tokens.keys()):
322    if static_tokens [k] is None:
323        static_tokens [k] = k
324
325StringTypes = ['Numeric', 'Printable', 'IA5', 'BMP', 'Universal', 'UTF8',
326               'Teletex', 'T61', 'Videotex', 'Graphic', 'ISO646', 'Visible',
327               'General']
328
329for s in StringTypes:
330    reserved_words[s + 'String'] = s + 'String'
331
332tokens = list(static_tokens.values()) \
333         + list(reserved_words.values()) \
334         + ['BSTRING', 'HSTRING', 'QSTRING',
335            'UCASE_IDENT', 'LCASE_IDENT', 'LCASE_IDENT_ASSIGNED', 'CLASS_IDENT',
336            'REAL_NUMBER', 'NUMBER', 'PYQUOTE']
337
338
339cur_mod = __import__ (__name__) # XXX blech!
340
341for (k, v) in list(static_tokens.items ()):
342    cur_mod.__dict__['t_' + v] = k
343
344# 11.10 Binary strings
345def t_BSTRING (t):
346    r"'[01]*'B"
347    return t
348
349# 11.12 Hexadecimal strings
350def t_HSTRING (t):
351    r"'[0-9A-Fa-f]*'H"
352    return t
353
354def t_QSTRING (t):
355    r'"([^"]|"")*"'
356    return t
357
358def t_UCASE_IDENT (t):
359    r"[A-Z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-'
360    if (is_class_ident(t.value)): t.type = 'CLASS_IDENT'
361    if (is_class_syntax(t.value)): t.type = t.value
362    t.type = reserved_words.get(t.value, t.type)
363    return t
364
365lcase_ident_assigned = {}
366def t_LCASE_IDENT (t):
367    r"[a-z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-'
368    if (not in_oid and (t.value in lcase_ident_assigned)): t.type = 'LCASE_IDENT_ASSIGNED'
369    return t
370
371# 11.9 Real numbers
372def t_REAL_NUMBER (t):
373    r"[0-9]+\.[0-9]*(?!\.)"
374    return t
375
376# 11.8 Numbers
377def t_NUMBER (t):
378    r"0|([1-9][0-9]*)"
379    return t
380
381# 11.6 Comments
382pyquote_str = 'PYQUOTE'
383def t_COMMENT(t):
384    r"--(-[^\-\n]|[^\-\n])*(--|\n|-\n|$|-$)"
385    if (t.value.find("\n") >= 0) : t.lexer.lineno += 1
386    if t.value[2:2+len (pyquote_str)] == pyquote_str:
387        t.value = t.value[2+len(pyquote_str):]
388        t.value = t.value.lstrip ()
389        t.type = pyquote_str
390        return t
391    return None
392
393t_ignore = " \t\r"
394
395def t_NEWLINE(t):
396    r'\n+'
397    t.lexer.lineno += t.value.count("\n")
398
399def t_error(t):
400    global input_file
401    raise LexError(t, input_file)
402
403# state 'braceignore'
404
405def t_braceignore_lbrace(t):
406    r'\{'
407    t.lexer.level +=1
408
409def t_braceignore_rbrace(t):
410    r'\}'
411    t.lexer.level -=1
412    # If closing brace, return token
413    if t.lexer.level == 0:
414        t.type = 'RBRACE'
415        return t
416
417def t_braceignore_QSTRING (t):
418    r'"([^"]|"")*"'
419    t.lexer.lineno += t.value.count("\n")
420
421def t_braceignore_COMMENT(t):
422    r"--(-[^\-\n]|[^\-\n])*(--|\n|-\n|$|-$)"
423    if (t.value.find("\n") >= 0) : t.lexer.lineno += 1
424
425def t_braceignore_nonspace(t):
426    r'[^\s\{\}\"-]+|-(?!-)'
427
428t_braceignore_ignore = " \t\r"
429
430def t_braceignore_NEWLINE(t):
431    r'\n+'
432    t.lexer.lineno += t.value.count("\n")
433
434def t_braceignore_error(t):
435    t.lexer.skip(1)
436
437class Ctx:
438    def __init__ (self, defined_dict, indent = 0):
439        self.tags_def = 'EXPLICIT' # default = explicit
440        self.indent_lev = 0
441        self.assignments = {}
442        self.dependencies = {}
443        self.pyquotes = []
444        self.defined_dict = defined_dict
445        self.name_ctr = 0
446    def spaces (self):
447        return " " * (4 * self.indent_lev)
448    def indent (self):
449        self.indent_lev += 1
450    def outdent (self):
451        self.indent_lev -= 1
452        assert (self.indent_lev >= 0)
453    def register_assignment (self, ident, val, dependencies):
454        if ident in self.assignments:
455            raise DuplicateError("assignment", ident)
456        if ident in self.defined_dict:
457            raise Exception("cross-module duplicates for %s" % ident)
458        self.defined_dict [ident] = 1
459        self.assignments[ident] = val
460        self.dependencies [ident] = dependencies
461        return ""
462    #        return "#%s depends on %s" % (ident, str (dependencies))
463    def register_pyquote (self, val):
464        self.pyquotes.append (val)
465        return ""
466    def output_assignments (self):
467        already_output = {}
468        text_list = []
469        assign_keys = list(self.assignments.keys())
470        to_output_count = len (assign_keys)
471        while True:
472            any_output = 0
473            for (ident, val) in list(self.assignments.items ()):
474                if ident in already_output:
475                    continue
476                ok = 1
477                for d in self.dependencies [ident]:
478                    if ((d not in already_output) and
479                        (d in assign_keys)):
480                        ok = 0
481                if ok:
482                    text_list.append ("%s=%s" % (ident,
483                                                self.assignments [ident]))
484                    already_output [ident] = 1
485                    any_output = 1
486                    to_output_count -= 1
487                    assert (to_output_count >= 0)
488            if not any_output:
489                if to_output_count == 0:
490                    break
491                # OK, we detected a cycle
492                cycle_list = []
493                for ident in list(self.assignments.keys ()):
494                    if ident not in already_output:
495                        depend_list = [d for d in self.dependencies[ident] if d in assign_keys]
496                        cycle_list.append ("%s(%s)" % (ident, ",".join (depend_list)))
497
498                text_list.append ("# Cycle XXX " + ",".join (cycle_list))
499                for (ident, val) in list(self.assignments.items ()):
500                    if ident not in already_output:
501                        text_list.append ("%s=%s" % (ident, self.assignments [ident]))
502                break
503
504        return "\n".join (text_list)
505    def output_pyquotes (self):
506        return "\n".join (self.pyquotes)
507    def make_new_name (self):
508        self.name_ctr += 1
509        return "_compiler_generated_name_%d" % (self.name_ctr,)
510
511#--- Flags for EXPORT, USER_DEFINED, NO_EMIT, MAKE_ENUM -------------------------------
512EF_TYPE    = 0x0001
513EF_VALS    = 0x0002
514EF_ENUM    = 0x0004
515EF_WS_DLL  = 0x0010 #  exported from shared library
516EF_EXTERN  = 0x0020
517EF_NO_PROT = 0x0040
518EF_NO_TYPE = 0x0080
519EF_UCASE   = 0x0100
520EF_TABLE   = 0x0400
521EF_DEFINE  = 0x0800
522EF_MODULE  = 0x1000
523
524#--- common dependency computation ---
525# Input  : list of items
526#          dictionary with lists of dependency
527#
528#
529# Output : list of two outputs:
530#          [0] list of items in dependency
531#          [1] list of cycle dependency cycles
532def dependency_compute(items, dependency, map_fn = lambda t: t, ignore_fn = lambda t: False):
533    item_ord = []
534    item_cyc = []
535    x = {}  # already emitted
536    #print '# Dependency computation'
537    for t in items:
538        if map_fn(t) in x:
539            #print 'Continue: %s : %s' % (t, (map_fn(t))
540            continue
541        stack = [t]
542        stackx = {t : dependency.get(t, [])[:]}
543        #print 'Push: %s : %s' % (t, str(stackx[t]))
544        while stack:
545            if stackx[stack[-1]]:  # has dependencies
546                d = stackx[stack[-1]].pop(0)
547                if map_fn(d) in x or ignore_fn(d):
548                    continue
549                if d in stackx:  # cyclic dependency
550                    c = stack[:]
551                    c.reverse()
552                    c = [d] + c[0:c.index(d)+1]
553                    c.reverse()
554                    item_cyc.append(c)
555                    #print 'Cyclic: %s ' % (' -> '.join(c))
556                    continue
557                stack.append(d)
558                stackx[d] = dependency.get(d, [])[:]
559                #print 'Push: %s : %s' % (d, str(stackx[d]))
560            else:
561                #print 'Pop: %s' % (stack[-1])
562                del stackx[stack[-1]]
563                e = map_fn(stack.pop())
564                if e in x:
565                    continue
566                #print 'Add: %s' % (e)
567                item_ord.append(e)
568                x[e] = True
569    return (item_ord, item_cyc)
570
571# Given a filename, return a relative path from the current directory
572def relpath(filename):
573    return os.path.relpath(filename)
574
575# Given a filename, return a relative path from epan/dissectors
576def rel_dissector_path(filename):
577    path_parts = os.path.abspath(filename).split(os.sep)
578    while (len(path_parts) > 3 and path_parts[0] != 'asn1'):
579        path_parts.pop(0)
580    path_parts.insert(0, '.')
581    return '/'.join(path_parts)
582
583
584#--- EthCtx -------------------------------------------------------------------
585class EthCtx:
586    def __init__(self, conform, output, indent = 0):
587        self.conform = conform
588        self.output = output
589        self.conform.ectx = self
590        self.output.ectx = self
591        self.encoding = 'per'
592        self.aligned = False
593        self.default_oid_variant = ''
594        self.default_opentype_variant = ''
595        self.default_containing_variant = '_pdu_new'
596        self.default_embedded_pdv_cb = None
597        self.default_external_type_cb = None
598        self.remove_prefix = None
599        self.srcdir = None
600        self.emitted_pdu = {}
601        self.module = {}
602        self.module_ord = []
603        self.all_type_attr = {}
604        self.all_tags = {}
605        self.all_vals = {}
606
607    def encp(self):  # encoding protocol
608        encp = self.encoding
609        return encp
610
611    # Encoding
612    def Per(self): return self.encoding == 'per'
613    def Ber(self): return self.encoding == 'ber'
614    def Oer(self): return self.encoding == 'oer'
615    def Aligned(self): return self.aligned
616    def Unaligned(self): return not self.aligned
617    def NeedTags(self): return self.tag_opt or self.Ber()
618    def NAPI(self): return False  # disable planned features
619
620    def Module(self):  # current module name
621        return self.modules[-1][0]
622
623    def groups(self):
624        return self.group_by_prot or (self.conform.last_group > 0)
625
626    def dbg(self, d):
627        if (self.dbgopt.find(d) >= 0):
628            return True
629        else:
630            return False
631
632    def value_max(self, a, b):
633        if (a == 'MAX') or (b == 'MAX'): return 'MAX';
634        if a == 'MIN': return b;
635        if b == 'MIN': return a;
636        try:
637            if (int(a) > int(b)):
638                return a
639            else:
640                return b
641        except (ValueError, TypeError):
642            pass
643        return "MAX((%s),(%s))" % (a, b)
644
645    def value_min(self, a, b):
646        if (a == 'MIN') or (b == 'MIN'): return 'MIN';
647        if a == 'MAX': return b;
648        if b == 'MAX': return a;
649        try:
650            if (int(a) < int(b)):
651                return a
652            else:
653                return b
654        except (ValueError, TypeError):
655            pass
656        return "MIN((%s),(%s))" % (a, b)
657
658    def value_get_eth(self, val):
659        if isinstance(val, Value):
660            return val.to_str(self)
661        ethname = val
662        if val in self.value:
663            ethname = self.value[val]['ethname']
664        return ethname
665
666    def value_get_val(self, nm):
667        val = asn2c(nm)
668        if nm in self.value:
669            if self.value[nm]['import']:
670                v = self.get_val_from_all(nm, self.value[nm]['import'])
671                if v is None:
672                    msg = 'Need value of imported value identifier %s from %s (%s)' % (nm, self.value[nm]['import'], self.value[nm]['proto'])
673                    warnings.warn_explicit(msg, UserWarning, '', 0)
674                else:
675                    val = v
676            else:
677                val = self.value[nm]['value']
678                if isinstance (val, Value):
679                    val = val.to_str(self)
680        else:
681            msg = 'Need value of unknown value identifier %s' % (nm)
682            warnings.warn_explicit(msg, UserWarning, '', 0)
683        return val
684
685    def eth_get_type_attr(self, type):
686        #print "eth_get_type_attr(%s)" % (type)
687        types = [type]
688        while (not self.type[type]['import']):
689            val =  self.type[type]['val']
690            #print val
691            ttype = type
692            while (val.type == 'TaggedType'):
693                val = val.val
694                ttype += '/' + UNTAG_TYPE_NAME
695            if (val.type != 'Type_Ref'):
696                if (type != ttype):
697                    types.append(ttype)
698                break
699            type = val.val
700            types.append(type)
701        attr = {}
702        #print " ", types
703        while len(types):
704            t = types.pop()
705            if (self.type[t]['import']):
706                attr.update(self.type[t]['attr'])
707                attr.update(self.eth_get_type_attr_from_all(t, self.type[t]['import']))
708            elif (self.type[t]['val'].type == 'SelectionType'):
709                val = self.type[t]['val']
710                (ftype, display) = val.eth_ftype(self)
711                attr.update({ 'TYPE' : ftype, 'DISPLAY' : display,
712                              'STRINGS' : val.eth_strings(), 'BITMASK' : '0' });
713            else:
714                attr.update(self.type[t]['attr'])
715                attr.update(self.eth_type[self.type[t]['ethname']]['attr'])
716        if attr['STRINGS'].startswith('VALS64(') and '|BASE_VAL64_STRING' not in attr['DISPLAY']:
717            attr['DISPLAY'] += '|BASE_VAL64_STRING'
718        #print " ", attr
719        return attr
720
721    def eth_get_type_attr_from_all(self, type, module):
722        attr = {}
723        if module in self.all_type_attr and type in self.all_type_attr[module]:
724            attr = self.all_type_attr[module][type]
725        return attr
726
727    def get_ttag_from_all(self, type, module):
728        ttag = None
729        if module in self.all_tags and type in self.all_tags[module]:
730            ttag = self.all_tags[module][type]
731        return ttag
732
733    def get_val_from_all(self, nm, module):
734        val = None
735        if module in self.all_vals and nm in self.all_vals[module]:
736            val = self.all_vals[module][nm]
737        return val
738
739    def get_obj_repr(self, ident, flds=[], not_flds=[]):
740        def set_type_fn(cls, field, fnfield):
741            obj[fnfield + '_fn'] = 'NULL'
742            obj[fnfield + '_pdu'] = 'NULL'
743            if field in val and isinstance(val[field], Type_Ref):
744                p = val[field].eth_type_default_pars(self, '')
745                obj[fnfield + '_fn'] = p['TYPE_REF_FN']
746                obj[fnfield + '_fn'] = obj[fnfield + '_fn'] % p  # one iteration
747                if (self.conform.check_item('PDU', cls + '.' + field)):
748                    obj[fnfield + '_pdu'] = 'dissect_' + self.field[val[field].val]['ethname']
749            return
750        # end of get_type_fn()
751        obj = { '_name' : ident, '_ident' : asn2c(ident)}
752        obj['_class'] = self.oassign[ident].cls
753        obj['_module'] = self.oassign[ident].module
754        val = self.oassign[ident].val
755        for f in flds:
756            if f not in val:
757                return None
758        for f in not_flds:
759            if f in val:
760                return None
761        for f in list(val.keys()):
762            if isinstance(val[f], Node):
763                obj[f] = val[f].fld_obj_repr(self)
764            else:
765                obj[f] = str(val[f])
766        if (obj['_class'] == 'TYPE-IDENTIFIER') or (obj['_class'] == 'ABSTRACT-SYNTAX'):
767            set_type_fn(obj['_class'], '&Type', '_type')
768        if (obj['_class'] == 'OPERATION'):
769            set_type_fn(obj['_class'], '&ArgumentType', '_argument')
770            set_type_fn(obj['_class'], '&ResultType', '_result')
771        if (obj['_class'] == 'ERROR'):
772            set_type_fn(obj['_class'], '&ParameterType', '_parameter')
773        return obj
774
775    #--- eth_reg_module -----------------------------------------------------------
776    def eth_reg_module(self, module):
777        #print "eth_reg_module(module='%s')" % (module)
778        name = module.get_name()
779        self.modules.append([name, module.get_proto(self)])
780        if name in self.module:
781            raise DuplicateError("module", name)
782        self.module[name] = []
783        self.module_ord.append(name)
784
785    #--- eth_module_dep_add ------------------------------------------------------------
786    def eth_module_dep_add(self, module, dep):
787        self.module[module].append(dep)
788
789    #--- eth_exports ------------------------------------------------------------
790    def eth_exports(self, exports):
791        self.exports_all = False
792        if ((len(exports) == 1) and (exports[0] == 'ALL')):
793            self.exports_all = True
794            return
795        for e in (exports):
796            if isinstance(e, Type_Ref):
797                self.exports.append(e.val)
798            elif isinstance(e, Class_Ref):
799                self.cexports.append(e.val)
800            else:
801                self.vexports.append(e)
802
803    #--- eth_reg_assign ---------------------------------------------------------
804    def eth_reg_assign(self, ident, val, virt=False):
805        #print "eth_reg_assign(ident='%s')" % (ident)
806        if ident in self.assign:
807            raise DuplicateError("assignment", ident)
808        self.assign[ident] = { 'val' : val , 'virt' : virt }
809        self.assign_ord.append(ident)
810        if  (self.exports_all):
811            self.exports.append(ident)
812
813    #--- eth_reg_vassign --------------------------------------------------------
814    def eth_reg_vassign(self, vassign):
815        ident = vassign.ident
816        #print "eth_reg_vassign(ident='%s')" % (ident)
817        if ident in self.vassign:
818            raise DuplicateError("value assignment", ident)
819        self.vassign[ident] = vassign
820        self.vassign_ord.append(ident)
821        if  (self.exports_all):
822            self.vexports.append(ident)
823
824    #--- eth_reg_oassign --------------------------------------------------------
825    def eth_reg_oassign(self, oassign):
826        ident = oassign.ident
827        #print "eth_reg_oassign(ident='%s')" % (ident)
828        if ident in self.oassign:
829            if self.oassign[ident] == oassign:
830                return  # OK - already defined
831            else:
832                raise DuplicateError("information object assignment", ident)
833        self.oassign[ident] = oassign
834        self.oassign_ord.append(ident)
835        self.oassign_cls.setdefault(oassign.cls, []).append(ident)
836
837    #--- eth_import_type --------------------------------------------------------
838    def eth_import_type(self, ident, mod, proto):
839        #print "eth_import_type(ident='%s', mod='%s', prot='%s')" % (ident, mod, proto)
840        if ident in self.type:
841            #print "already defined '%s' import=%s, module=%s" % (ident, str(self.type[ident]['import']), self.type[ident].get('module', '-'))
842            if not self.type[ident]['import'] and (self.type[ident]['module'] == mod) :
843                return  # OK - already defined
844            elif self.type[ident]['import'] and (self.type[ident]['import'] == mod) :
845                return  # OK - already imported
846            else:
847                raise DuplicateError("type", ident)
848        self.type[ident] = {'import'  : mod, 'proto' : proto,
849                            'ethname' : '' }
850        self.type[ident]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE',
851                                     'STRINGS' : 'NULL', 'BITMASK' : '0' }
852        mident = "$%s$%s" % (mod, ident)
853        if (self.conform.check_item('TYPE_ATTR', mident)):
854            self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', mident))
855        else:
856            self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident))
857        if (self.conform.check_item('IMPORT_TAG', mident)):
858            self.conform.copy_item('IMPORT_TAG', ident, mident)
859        self.type_imp.append(ident)
860
861    #--- dummy_import_type --------------------------------------------------------
862    def dummy_import_type(self, ident):
863        # dummy imported
864        if ident in self.type:
865            raise Exception("Try to dummy import for existing type :%s" % ident)
866        ethtype = asn2c(ident)
867        self.type[ident] = {'import'  : 'xxx', 'proto' : 'xxx',
868                            'ethname' : ethtype }
869        self.type[ident]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE',
870                                     'STRINGS' : 'NULL', 'BITMASK' : '0' }
871        self.eth_type[ethtype] = { 'import' : 'xxx', 'proto' : 'xxx' , 'attr' : {}, 'ref' : []}
872        print("Dummy imported: %s (%s)" % (ident, ethtype))
873        return ethtype
874
875    #--- eth_import_class --------------------------------------------------------
876    def eth_import_class(self, ident, mod, proto):
877        #print "eth_import_class(ident='%s', mod='%s', prot='%s')" % (ident, mod, proto)
878        if ident in self.objectclass:
879            #print "already defined import=%s, module=%s" % (str(self.objectclass[ident]['import']), self.objectclass[ident]['module'])
880            if not self.objectclass[ident]['import'] and (self.objectclass[ident]['module'] == mod) :
881                return  # OK - already defined
882            elif self.objectclass[ident]['import'] and (self.objectclass[ident]['import'] == mod) :
883                return  # OK - already imported
884            else:
885                raise DuplicateError("object class", ident)
886        self.objectclass[ident] = {'import'  : mod, 'proto' : proto,
887                            'ethname' : '' }
888        self.objectclass_imp.append(ident)
889
890    #--- eth_import_value -------------------------------------------------------
891    def eth_import_value(self, ident, mod, proto):
892        #print "eth_import_value(ident='%s', mod='%s', prot='%s')" % (ident, mod, prot)
893        if ident in self.value:
894            #print "already defined import=%s, module=%s" % (str(self.value[ident]['import']), self.value[ident]['module'])
895            if not self.value[ident]['import'] and (self.value[ident]['module'] == mod) :
896                return  # OK - already defined
897            elif self.value[ident]['import'] and (self.value[ident]['import'] == mod) :
898                return  # OK - already imported
899            else:
900                raise DuplicateError("value", ident)
901        self.value[ident] = {'import'  : mod, 'proto' : proto,
902                             'ethname' : ''}
903        self.value_imp.append(ident)
904
905    #--- eth_sel_req ------------------------------------------------------------
906    def eth_sel_req(self, typ, sel):
907        key = typ + '.' + sel
908        if key not in self.sel_req:
909            self.sel_req[key] = { 'typ' : typ , 'sel' : sel}
910            self.sel_req_ord.append(key)
911        return key
912
913    #--- eth_comp_req ------------------------------------------------------------
914    def eth_comp_req(self, type):
915        self.comp_req_ord.append(type)
916
917    #--- eth_dep_add ------------------------------------------------------------
918    def eth_dep_add(self, type, dep):
919        if type not in self.type_dep:
920            self.type_dep[type] = []
921        self.type_dep[type].append(dep)
922
923    #--- eth_reg_type -----------------------------------------------------------
924    def eth_reg_type(self, ident, val, mod=None):
925        #print "eth_reg_type(ident='%s', type='%s')" % (ident, val.type)
926        if ident in self.type:
927            if self.type[ident]['import'] and (self.type[ident]['import'] == self.Module()) :
928                # replace imported type
929                del self.type[ident]
930                self.type_imp.remove(ident)
931            else:
932                raise DuplicateError("type", ident)
933        val.ident = ident
934        self.type[ident] = { 'val' : val, 'import' : None }
935        self.type[ident]['module'] = self.Module()
936        self.type[ident]['proto'] = self.proto
937        if len(ident.split('/')) > 1:
938            self.type[ident]['tname'] = val.eth_tname()
939        else:
940            self.type[ident]['tname'] = asn2c(ident)
941        if mod :
942            mident = "$%s$%s" % (mod, ident)
943        else:
944            mident = None
945        self.type[ident]['export'] = self.conform.use_item('EXPORTS', ident)
946        self.type[ident]['enum'] = self.conform.use_item('MAKE_ENUM', ident)
947        self.type[ident]['vals_ext'] = self.conform.use_item('USE_VALS_EXT', ident)
948        self.type[ident]['user_def'] = self.conform.use_item('USER_DEFINED', ident)
949        if mident and self.conform.check_item('NO_EMIT', mident) :
950            self.type[ident]['no_emit'] = self.conform.use_item('NO_EMIT', mident)
951        else:
952            self.type[ident]['no_emit'] = self.conform.use_item('NO_EMIT', ident)
953        self.type[ident]['tname'] = self.conform.use_item('TYPE_RENAME', ident, val_dflt=self.type[ident]['tname'])
954        self.type[ident]['ethname'] = ''
955        if (val.type == 'Type_Ref') or (val.type == 'TaggedType') or (val.type == 'SelectionType') :
956            self.type[ident]['attr'] = {}
957        else:
958            (ftype, display) = val.eth_ftype(self)
959            self.type[ident]['attr'] = { 'TYPE' : ftype, 'DISPLAY' : display,
960                                         'STRINGS' : val.eth_strings(), 'BITMASK' : '0' }
961        self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident))
962        self.type_ord.append(ident)
963        # PDU
964        if (self.conform.check_item('PDU', ident)):
965            self.eth_reg_field(ident, ident, impl=val.HasImplicitTag(self), pdu=self.conform.use_item('PDU', ident))
966
967    #--- eth_reg_objectclass ----------------------------------------------------------
968    def eth_reg_objectclass(self, ident, val):
969        #print "eth_reg_objectclass(ident='%s')" % (ident)
970        if ident in self.objectclass:
971            if self.objectclass[ident]['import'] and (self.objectclass[ident]['import'] == self.Module()) :
972                # replace imported object class
973                del self.objectclass[ident]
974                self.objectclass_imp.remove(ident)
975            elif isinstance(self.objectclass[ident]['val'], Class_Ref) and \
976                 isinstance(val, Class_Ref) and \
977                 (self.objectclass[ident]['val'].val == val.val):
978                pass  # ignore duplicated CLASS1 ::= CLASS2
979            else:
980                raise DuplicateError("object class", ident)
981        self.objectclass[ident] = { 'import' : None, 'module' : self.Module(), 'proto' : self.proto }
982        self.objectclass[ident]['val'] = val
983        self.objectclass[ident]['export'] = self.conform.use_item('EXPORTS', ident)
984        self.objectclass_ord.append(ident)
985
986    #--- eth_reg_value ----------------------------------------------------------
987    def eth_reg_value(self, ident, type, value, ethname=None):
988        #print "eth_reg_value(ident='%s')" % (ident)
989        if ident in self.value:
990            if self.value[ident]['import'] and (self.value[ident]['import'] == self.Module()) :
991                # replace imported value
992                del self.value[ident]
993                self.value_imp.remove(ident)
994            elif ethname:
995                self.value[ident]['ethname'] = ethname
996                return
997            else:
998                raise DuplicateError("value", ident)
999        self.value[ident] = { 'import' : None, 'module' : self.Module(), 'proto' : self.proto,
1000                              'type' : type, 'value' : value,
1001                              'no_emit' : False }
1002        self.value[ident]['export'] = self.conform.use_item('EXPORTS', ident)
1003        self.value[ident]['ethname'] = ''
1004        if (ethname): self.value[ident]['ethname'] = ethname
1005        self.value_ord.append(ident)
1006
1007    #--- eth_reg_field ----------------------------------------------------------
1008    def eth_reg_field(self, ident, type, idx='', parent=None, impl=False, pdu=None):
1009        #print "eth_reg_field(ident='%s', type='%s')" % (ident, type)
1010        if ident in self.field:
1011            if pdu and (type == self.field[ident]['type']):
1012                pass  # OK already created PDU
1013            else:
1014                raise DuplicateError("field", ident)
1015        self.field[ident] = {'type' : type, 'idx' : idx, 'impl' : impl, 'pdu' : pdu,
1016                             'modified' : '', 'attr' : {} }
1017        name = ident.split('/')[-1]
1018        if self.remove_prefix and name.startswith(self.remove_prefix):
1019            name = name[len(self.remove_prefix):]
1020
1021        if len(ident.split('/')) > 1 and name == ITEM_FIELD_NAME:  # Sequence/Set of type
1022            if len(self.field[ident]['type'].split('/')) > 1:
1023                self.field[ident]['attr']['NAME'] = '"%s item"' % ident.split('/')[-2]
1024                self.field[ident]['attr']['ABBREV'] = asn2c(ident.split('/')[-2] + name)
1025            else:
1026                self.field[ident]['attr']['NAME'] = '"%s"' % self.field[ident]['type']
1027                self.field[ident]['attr']['ABBREV'] = asn2c(self.field[ident]['type'])
1028        else:
1029            self.field[ident]['attr']['NAME'] = '"%s"' % name
1030            self.field[ident]['attr']['ABBREV'] = asn2c(name)
1031        if self.conform.check_item('FIELD_ATTR', ident):
1032            self.field[ident]['modified'] = '#' + str(id(self))
1033            self.field[ident]['attr'].update(self.conform.use_item('FIELD_ATTR', ident))
1034        if (pdu):
1035            self.field[ident]['pdu']['export'] = (self.conform.use_item('EXPORTS', ident + '_PDU') != 0)
1036            self.pdu_ord.append(ident)
1037        else:
1038            self.field_ord.append(ident)
1039        if parent:
1040            self.eth_dep_add(parent, type)
1041
1042    def eth_dummy_eag_field_required(self):
1043        if (not self.dummy_eag_field):
1044            self.dummy_eag_field = 'eag_field'
1045
1046    #--- eth_clean --------------------------------------------------------------
1047    def eth_clean(self):
1048        self.proto = self.proto_opt;
1049        #--- ASN.1 tables ----------------
1050        self.assign = {}
1051        self.assign_ord = []
1052        self.field = {}
1053        self.pdu_ord = []
1054        self.field_ord = []
1055        self.type = {}
1056        self.type_ord = []
1057        self.type_imp = []
1058        self.type_dep = {}
1059        self.sel_req = {}
1060        self.sel_req_ord = []
1061        self.comp_req_ord = []
1062        self.vassign = {}
1063        self.vassign_ord = []
1064        self.value = {}
1065        self.value_ord = []
1066        self.value_imp = []
1067        self.objectclass = {}
1068        self.objectclass_ord = []
1069        self.objectclass_imp = []
1070        self.oassign = {}
1071        self.oassign_ord = []
1072        self.oassign_cls = {}
1073        #--- Modules ------------
1074        self.modules = []
1075        self.exports_all = False
1076        self.exports = []
1077        self.cexports = []
1078        self.vexports = []
1079        #--- types -------------------
1080        self.eth_type = {}
1081        self.eth_type_ord = []
1082        self.eth_export_ord = []
1083        self.eth_type_dupl = {}
1084        self.named_bit = []
1085        #--- value dependencies -------------------
1086        self.value_dep = {}
1087        #--- values -------------------
1088        self.eth_value = {}
1089        self.eth_value_ord = []
1090        #--- fields -------------------------
1091        self.eth_hf = {}
1092        self.eth_hf_ord = []
1093        self.eth_hfpdu_ord = []
1094        self.eth_hf_dupl = {}
1095        self.dummy_eag_field = None
1096        #--- type dependencies -------------------
1097        self.eth_type_ord1 = []
1098        self.eth_dep_cycle = []
1099        self.dep_cycle_eth_type = {}
1100        #--- value dependencies and export -------------------
1101        self.eth_value_ord1 = []
1102        self.eth_vexport_ord = []
1103
1104    #--- eth_prepare ------------------------------------------------------------
1105    def eth_prepare(self):
1106        self.eproto = asn2c(self.proto)
1107
1108        #--- dummy types/fields for PDU registration ---
1109        nm = 'NULL'
1110        if (self.conform.check_item('PDU', nm)):
1111            self.eth_reg_type('_dummy/'+nm, NullType())
1112            self.eth_reg_field(nm, '_dummy/'+nm, pdu=self.conform.use_item('PDU', nm))
1113
1114        #--- required PDUs ----------------------------
1115        for t in self.type_ord:
1116            pdu = self.type[t]['val'].eth_need_pdu(self)
1117            if not pdu: continue
1118            f = pdu['type']
1119            pdu['reg'] = None
1120            pdu['hidden'] = False
1121            pdu['need_decl'] = True
1122            if f not in self.field:
1123                self.eth_reg_field(f, f, pdu=pdu)
1124
1125        #--- values -> named values -------------------
1126        t_for_update = {}
1127        for v in self.value_ord:
1128            if (self.value[v]['type'].type == 'Type_Ref') or self.conform.check_item('ASSIGN_VALUE_TO_TYPE', v):
1129                if self.conform.check_item('ASSIGN_VALUE_TO_TYPE', v):
1130                    tnm = self.conform.use_item('ASSIGN_VALUE_TO_TYPE', v)
1131                else:
1132                    tnm = self.value[v]['type'].val
1133                if tnm in self.type \
1134                   and not self.type[tnm]['import'] \
1135                   and (self.type[tnm]['val'].type == 'IntegerType'):
1136                    self.type[tnm]['val'].add_named_value(v, self.value[v]['value'])
1137                    self.value[v]['no_emit'] = True
1138                    t_for_update[tnm] = True
1139        for t in list(t_for_update.keys()):
1140            self.type[t]['attr']['STRINGS'] = self.type[t]['val'].eth_strings()
1141            self.type[t]['attr'].update(self.conform.use_item('TYPE_ATTR', t))
1142
1143        #--- required components of ---------------------------
1144        #print "self.comp_req_ord = ", self.comp_req_ord
1145        for t in self.comp_req_ord:
1146            self.type[t]['val'].eth_reg_sub(t, self, components_available=True)
1147
1148        #--- required selection types ---------------------------
1149        #print "self.sel_req_ord = ", self.sel_req_ord
1150        for t in self.sel_req_ord:
1151            tt = self.sel_req[t]['typ']
1152            if tt not in self.type:
1153                self.dummy_import_type(t)
1154            elif self.type[tt]['import']:
1155                self.eth_import_type(t, self.type[tt]['import'], self.type[tt]['proto'])
1156            else:
1157                self.type[tt]['val'].sel_req(t, self.sel_req[t]['sel'], self)
1158
1159        #--- types -------------------
1160        for t in self.type_imp: # imported types
1161            nm = asn2c(t)
1162            self.eth_type[nm] = { 'import' : self.type[t]['import'],
1163                                  'proto' : asn2c(self.type[t]['proto']),
1164                                  'attr' : {}, 'ref' : []}
1165            self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm))
1166            self.type[t]['ethname'] = nm
1167        for t in self.type_ord: # dummy import for missing type reference
1168            tp = self.type[t]['val']
1169            #print "X : %s %s " % (t, tp.type)
1170            if isinstance(tp, TaggedType):
1171                #print "%s : %s " % (tp.type, t)
1172                tp = tp.val
1173            if isinstance(tp, Type_Ref):
1174                #print "%s : %s ::= %s " % (tp.type, t, tp.val)
1175                if tp.val not in self.type:
1176                    self.dummy_import_type(tp.val)
1177        for t in self.type_ord:
1178            nm = self.type[t]['tname']
1179            if ((nm.find('#') >= 0) or
1180                ((len(t.split('/'))>1) and
1181                 (self.conform.get_fn_presence(t) or self.conform.check_item('FN_PARS', t) or
1182                  self.conform.get_fn_presence('/'.join((t,ITEM_FIELD_NAME))) or self.conform.check_item('FN_PARS', '/'.join((t,ITEM_FIELD_NAME)))) and
1183                 not self.conform.check_item('TYPE_RENAME', t))):
1184                if len(t.split('/')) == 2 and t.split('/')[1] == ITEM_FIELD_NAME:  # Sequence of type at the 1st level
1185                    nm = t.split('/')[0] + t.split('/')[1]
1186                elif t.split('/')[-1] == ITEM_FIELD_NAME:  # Sequence/Set of type at next levels
1187                    nm = 'T_' + self.conform.use_item('FIELD_RENAME', '/'.join(t.split('/')[0:-1]), val_dflt=t.split('/')[-2]) + t.split('/')[-1]
1188                elif t.split('/')[-1] == UNTAG_TYPE_NAME:  # Untagged type
1189                    nm = self.type['/'.join(t.split('/')[0:-1])]['ethname'] + '_U'
1190                else:
1191                    nm = 'T_' + self.conform.use_item('FIELD_RENAME', t, val_dflt=t.split('/')[-1])
1192                nm = asn2c(nm)
1193                if nm in self.eth_type:
1194                    if nm in self.eth_type_dupl:
1195                        self.eth_type_dupl[nm].append(t)
1196                    else:
1197                        self.eth_type_dupl[nm] = [self.eth_type[nm]['ref'][0], t]
1198                    nm += '_%02d' % (len(self.eth_type_dupl[nm])-1)
1199            if nm in self.eth_type:
1200                self.eth_type[nm]['ref'].append(t)
1201            else:
1202                self.eth_type_ord.append(nm)
1203                self.eth_type[nm] = { 'import' : None, 'proto' : self.eproto, 'export' : 0, 'enum' : 0, 'vals_ext' : 0,
1204                                      'user_def' : EF_TYPE|EF_VALS, 'no_emit' : EF_TYPE|EF_VALS,
1205                                      'val' : self.type[t]['val'],
1206                                      'attr' : {}, 'ref' : [t]}
1207            self.type[t]['ethname'] = nm
1208            if (not self.eth_type[nm]['export'] and self.type[t]['export']):  # new export
1209                self.eth_export_ord.append(nm)
1210            self.eth_type[nm]['export'] |= self.type[t]['export']
1211            self.eth_type[nm]['enum'] |= self.type[t]['enum']
1212            self.eth_type[nm]['vals_ext'] |= self.type[t]['vals_ext']
1213            self.eth_type[nm]['user_def'] &= self.type[t]['user_def']
1214            self.eth_type[nm]['no_emit'] &= self.type[t]['no_emit']
1215            if self.type[t]['attr'].get('STRINGS') == '$$':
1216                use_ext = self.type[t]['vals_ext']
1217                if (use_ext):
1218                    self.eth_type[nm]['attr']['STRINGS'] = '&%s_ext' % (self.eth_vals_nm(nm))
1219                else:
1220                    if self.eth_type[nm]['val'].type == 'IntegerType' \
1221                       and self.eth_type[nm]['val'].HasConstraint() \
1222                       and self.eth_type[nm]['val'].constr.Needs64b(self):
1223                        self.eth_type[nm]['attr']['STRINGS'] = 'VALS64(%s)' % (self.eth_vals_nm(nm))
1224                    else:
1225                        self.eth_type[nm]['attr']['STRINGS'] = 'VALS(%s)' % (self.eth_vals_nm(nm))
1226            self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm))
1227        for t in self.eth_type_ord:
1228            bits = self.eth_type[t]['val'].eth_named_bits()
1229            if (bits):
1230                old_val = 0
1231                for (val, id) in bits:
1232                    self.named_bit.append({'name' : id, 'val' : val,
1233                                            'ethname' : 'hf_%s_%s_%s' % (self.eproto, t, asn2c(id)),
1234                                            'ftype'   : 'FT_BOOLEAN', 'display' : '8',
1235                                            'strings' : 'NULL',
1236                                            'bitmask' : '0x'+('80','40','20','10','08','04','02','01')[val%8]})
1237                    old_val = val + 1
1238            if self.eth_type[t]['val'].eth_need_tree():
1239                self.eth_type[t]['tree'] = "ett_%s_%s" % (self.eth_type[t]['proto'], t)
1240            else:
1241                self.eth_type[t]['tree'] = None
1242
1243        #--- register values from enums ------------
1244        for t in self.eth_type_ord:
1245            if (self.eth_type[t]['val'].eth_has_enum(t, self)):
1246                self.eth_type[t]['val'].reg_enum_vals(t, self)
1247
1248        #--- value dependencies -------------------
1249        for v in self.value_ord:
1250            if isinstance (self.value[v]['value'], Value):
1251                dep = self.value[v]['value'].get_dep()
1252            else:
1253                dep = self.value[v]['value']
1254            if dep and dep in self.value:
1255                self.value_dep.setdefault(v, []).append(dep)
1256
1257        #--- exports all necessary values
1258        for v in self.value_ord:
1259            if not self.value[v]['export']: continue
1260            deparr = self.value_dep.get(v, [])
1261            while deparr:
1262                d = deparr.pop()
1263                if not self.value[d]['import']:
1264                    if not self.value[d]['export']:
1265                        self.value[d]['export'] = EF_TYPE
1266                        deparr.extend(self.value_dep.get(d, []))
1267
1268        #--- values -------------------
1269        for v in self.value_imp:
1270            nm = asn2c(v)
1271            self.eth_value[nm] = { 'import' : self.value[v]['import'],
1272                                   'proto' : asn2c(self.value[v]['proto']),
1273                                   'ref' : []}
1274            self.value[v]['ethname'] = nm
1275        for v in self.value_ord:
1276            if (self.value[v]['ethname']):
1277                continue
1278            if (self.value[v]['no_emit']):
1279                continue
1280            nm = asn2c(v)
1281            self.eth_value[nm] = { 'import' : None,
1282                                   'proto' : asn2c(self.value[v]['proto']),
1283                                   'export' : self.value[v]['export'], 'ref' : [v] }
1284            self.eth_value[nm]['value'] = self.value[v]['value']
1285            self.eth_value_ord.append(nm)
1286            self.value[v]['ethname'] = nm
1287
1288        #--- fields -------------------------
1289        for f in (self.pdu_ord + self.field_ord):
1290            if len(f.split('/')) > 1 and f.split('/')[-1] == ITEM_FIELD_NAME:  # Sequence/Set of type
1291                nm = self.conform.use_item('FIELD_RENAME', '/'.join(f.split('/')[0:-1]), val_dflt=f.split('/')[-2]) + f.split('/')[-1]
1292            else:
1293                nm = f.split('/')[-1]
1294            nm = self.conform.use_item('FIELD_RENAME', f, val_dflt=nm)
1295            nm = asn2c(nm)
1296            if (self.field[f]['pdu']):
1297                nm += '_PDU'
1298                if (not self.merge_modules or self.field[f]['pdu']['export']):
1299                    nm = self.eproto + '_' + nm
1300            t = self.field[f]['type']
1301            if t in self.type:
1302                ethtype = self.type[t]['ethname']
1303            else:  # undefined type
1304                ethtype = self.dummy_import_type(t)
1305            ethtypemod = ethtype + self.field[f]['modified']
1306            if nm in self.eth_hf:
1307                if nm in self.eth_hf_dupl:
1308                    if ethtypemod in self.eth_hf_dupl[nm]:
1309                        nm = self.eth_hf_dupl[nm][ethtypemod]
1310                        self.eth_hf[nm]['ref'].append(f)
1311                        self.field[f]['ethname'] = nm
1312                        continue
1313                    else:
1314                        nmx = nm + ('_%02d' % (len(self.eth_hf_dupl[nm])))
1315                        self.eth_hf_dupl[nm][ethtype] = nmx
1316                        nm = nmx
1317                else:
1318                    if (self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified']) == ethtypemod:
1319                        self.eth_hf[nm]['ref'].append(f)
1320                        self.field[f]['ethname'] = nm
1321                        continue
1322                    else:
1323                        nmx = nm + '_01'
1324                        self.eth_hf_dupl[nm] = {self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified'] : nm, \
1325                                                ethtypemod : nmx}
1326                        nm = nmx
1327            if (self.field[f]['pdu']):
1328                self.eth_hfpdu_ord.append(nm)
1329            else:
1330                self.eth_hf_ord.append(nm)
1331            fullname = 'hf_%s_%s' % (self.eproto, nm)
1332            attr = self.eth_get_type_attr(self.field[f]['type']).copy()
1333            attr.update(self.field[f]['attr'])
1334            if (self.NAPI() and 'NAME' in attr):
1335                attr['NAME'] += self.field[f]['idx']
1336            attr.update(self.conform.use_item('EFIELD_ATTR', nm))
1337            use_vals_ext = self.eth_type[ethtype].get('vals_ext')
1338            if (use_vals_ext):
1339                attr['DISPLAY'] += '|BASE_EXT_STRING'
1340            self.eth_hf[nm] = {'fullname' : fullname, 'pdu' : self.field[f]['pdu'],
1341                               'ethtype' : ethtype, 'modified' : self.field[f]['modified'],
1342                               'attr' : attr.copy(),
1343                               'ref' : [f]}
1344            self.field[f]['ethname'] = nm
1345        if (self.dummy_eag_field):
1346            # Prepending "dummy_" avoids matching checkhf.pl.
1347            self.dummy_eag_field = 'dummy_hf_%s_%s' % (self.eproto, self.dummy_eag_field)
1348        #--- type dependencies -------------------
1349        (self.eth_type_ord1, self.eth_dep_cycle) = dependency_compute(self.type_ord, self.type_dep, map_fn = lambda t: self.type[t]['ethname'], ignore_fn = lambda t: self.type[t]['import'])
1350        i = 0
1351        while i < len(self.eth_dep_cycle):
1352            t = self.type[self.eth_dep_cycle[i][0]]['ethname']
1353            self.dep_cycle_eth_type.setdefault(t, []).append(i)
1354            i += 1
1355
1356        #--- value dependencies and export -------------------
1357        for v in self.eth_value_ord:
1358            if self.eth_value[v]['export']:
1359                self.eth_vexport_ord.append(v)
1360            else:
1361                self.eth_value_ord1.append(v)
1362
1363        #--- export tags, values, ... ---
1364        for t in self.exports:
1365            if t not in self.type:
1366                continue
1367            if self.type[t]['import']:
1368                continue
1369            m = self.type[t]['module']
1370            if not self.Per() and not self.Oer():
1371                if m not in self.all_tags:
1372                    self.all_tags[m] = {}
1373                self.all_tags[m][t] = self.type[t]['val'].GetTTag(self)
1374            if m not in self.all_type_attr:
1375                self.all_type_attr[m] = {}
1376            self.all_type_attr[m][t] = self.eth_get_type_attr(t).copy()
1377        for v in self.vexports:
1378            if v not in self.value:
1379                continue
1380            if self.value[v]['import']:
1381                continue
1382            m = self.value[v]['module']
1383            if m not in self.all_vals:
1384                self.all_vals[m] = {}
1385            vv = self.value[v]['value']
1386            if isinstance (vv, Value):
1387                vv = vv.to_str(self)
1388            self.all_vals[m][v] = vv
1389
1390    #--- eth_vals_nm ------------------------------------------------------------
1391    def eth_vals_nm(self, tname):
1392        out = ""
1393        if (not self.eth_type[tname]['export'] & EF_NO_PROT):
1394            out += "%s_" % (self.eproto)
1395        out += "%s_vals" % (tname)
1396        return out
1397
1398    #--- eth_vals ---------------------------------------------------------------
1399    def eth_vals(self, tname, vals):
1400        out = ""
1401        has_enum = self.eth_type[tname]['enum'] & EF_ENUM
1402        use_ext = self.eth_type[tname]['vals_ext']
1403        if (use_ext):
1404            vals.sort(key=lambda vals_entry: int(vals_entry[0]))
1405        if (not self.eth_type[tname]['export'] & EF_VALS):
1406            out += 'static '
1407        if (self.eth_type[tname]['export'] & EF_VALS) and (self.eth_type[tname]['export'] & EF_TABLE):
1408            out += 'static '
1409        if self.eth_type[tname]['val'].HasConstraint() and self.eth_type[tname]['val'].constr.Needs64b(self) \
1410           and self.eth_type[tname]['val'].type == 'IntegerType':
1411            out += "const val64_string %s[] = {\n" % (self.eth_vals_nm(tname))
1412        else:
1413            out += "const value_string %s[] = {\n" % (self.eth_vals_nm(tname))
1414        for (val, id) in vals:
1415            if (has_enum):
1416                vval = self.eth_enum_item(tname, id)
1417            else:
1418                vval = val
1419            out += '  { %3s, "%s" },\n' % (vval, id)
1420        out += "  { 0, NULL }\n};\n"
1421        if (use_ext):
1422            out += "\nstatic value_string_ext %s_ext = VALUE_STRING_EXT_INIT(%s);\n" % (self.eth_vals_nm(tname), self.eth_vals_nm(tname))
1423        return out
1424
1425    #--- eth_enum_prefix ------------------------------------------------------------
1426    def eth_enum_prefix(self, tname, type=False):
1427        out = ""
1428        if (self.eth_type[tname]['export'] & EF_ENUM):
1429            no_prot = self.eth_type[tname]['export'] & EF_NO_PROT
1430        else:
1431            no_prot = self.eth_type[tname]['enum'] & EF_NO_PROT
1432        if (not no_prot):
1433            out += self.eproto
1434        if ((not self.eth_type[tname]['enum'] & EF_NO_TYPE) or type):
1435            if (out): out += '_'
1436            out += tname
1437        if (self.eth_type[tname]['enum'] & EF_UCASE):
1438            out = out.upper()
1439        if (out): out += '_'
1440        return out
1441
1442    #--- eth_enum_nm ------------------------------------------------------------
1443    def eth_enum_nm(self, tname):
1444        out = self.eth_enum_prefix(tname, type=True)
1445        out += "enum"
1446        return out
1447
1448    #--- eth_enum_item ---------------------------------------------------------------
1449    def eth_enum_item(self, tname, ident):
1450        out = self.eth_enum_prefix(tname)
1451        out += asn2c(ident)
1452        if (self.eth_type[tname]['enum'] & EF_UCASE):
1453            out = out.upper()
1454        return out
1455
1456    #--- eth_enum ---------------------------------------------------------------
1457    def eth_enum(self, tname, vals):
1458        out = ""
1459        if (self.eth_type[tname]['enum'] & EF_DEFINE):
1460            out += "/* enumerated values for %s */\n" % (tname)
1461            for (val, id) in vals:
1462                out += '#define %-12s %3s\n' % (self.eth_enum_item(tname, id), val)
1463        else:
1464            out += "typedef enum _%s {\n" % (self.eth_enum_nm(tname))
1465            first_line = 1
1466            for (val, id) in vals:
1467                if (first_line == 1):
1468                    first_line = 0
1469                else:
1470                    out += ",\n"
1471                out += '  %-12s = %3s' % (self.eth_enum_item(tname, id), val)
1472            out += "\n} %s;\n" % (self.eth_enum_nm(tname))
1473        return out
1474
1475    #--- eth_bits ---------------------------------------------------------------
1476    def eth_bits(self, tname, bits):
1477        out = ""
1478        out += "static int * const "
1479        out += "%(TABLE)s[] = {\n"
1480        for (val, id) in bits:
1481            out += '  &hf_%s_%s_%s,\n' % (self.eproto, tname, asn2c(id))
1482        out += "  NULL\n};\n"
1483        return out
1484
1485    #--- eth_type_fn_h ----------------------------------------------------------
1486    def eth_type_fn_h(self, tname):
1487        out = ""
1488        if (not self.eth_type[tname]['export'] & EF_TYPE):
1489            out += 'static '
1490        out += "int "
1491        if (self.Ber()):
1492            out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)" % (self.eth_type[tname]['proto'], tname)
1493        elif (self.Per() or self.Oer()):
1494            out += "dissect_%s_%s(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)" % (self.eth_type[tname]['proto'], tname)
1495        out += ";\n"
1496        return out
1497
1498    #--- eth_fn_call ------------------------------------------------------------
1499    def eth_fn_call(self, fname, ret=None, indent=2, par=None):
1500        out = indent * ' '
1501        if (ret):
1502            if (ret == 'return'):
1503                out += 'return '
1504            else:
1505                out += ret + ' = '
1506        out += fname + '('
1507        ind = len(out)
1508        for i in range(len(par)):
1509            if (i>0): out += ind * ' '
1510            out += ', '.join(par[i])
1511            if (i<(len(par)-1)): out += ',\n'
1512        out += ');\n'
1513        return out
1514
1515    def output_proto_root(self):
1516        out = ''
1517        if self.conform.proto_root_name:
1518            out += '  proto_item *prot_ti = proto_tree_add_item(tree, ' + self.conform.proto_root_name + ', tvb, 0, -1, ENC_NA);\n'
1519            out += '  proto_item_set_hidden(prot_ti);\n'
1520        return out
1521
1522    #--- eth_type_fn_hdr --------------------------------------------------------
1523    def eth_type_fn_hdr(self, tname):
1524        out = '\n'
1525        if (not self.eth_type[tname]['export'] & EF_TYPE):
1526            out += 'static '
1527        out += "int\n"
1528        if (self.Ber()):
1529            out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname)
1530        elif (self.Per() or self.Oer()):
1531            out += "dissect_%s_%s(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname)
1532        #if self.conform.get_fn_presence(tname):
1533        #  out += self.conform.get_fn_text(tname, 'FN_HDR')
1534        #el
1535        if self.conform.check_item('PDU', tname):
1536            out += self.output_proto_root()
1537
1538        if self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
1539            out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_HDR')
1540        return out
1541
1542    #--- eth_type_fn_ftr --------------------------------------------------------
1543    def eth_type_fn_ftr(self, tname):
1544        out = '\n'
1545        #if self.conform.get_fn_presence(tname):
1546        #  out += self.conform.get_fn_text(tname, 'FN_FTR')
1547        #el
1548        if self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
1549            out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_FTR')
1550        out += "  return offset;\n"
1551        out += "}\n"
1552        return out
1553
1554    #--- eth_type_fn_body -------------------------------------------------------
1555    def eth_type_fn_body(self, tname, body, pars=None):
1556        out = body
1557        #if self.conform.get_fn_body_presence(tname):
1558        #  out = self.conform.get_fn_text(tname, 'FN_BODY')
1559        #el
1560        if self.conform.get_fn_body_presence(self.eth_type[tname]['ref'][0]):
1561            out = self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_BODY')
1562        if pars:
1563            try:
1564                out = out % pars
1565            except (TypeError):
1566                pass
1567        return out
1568
1569    #--- eth_out_pdu_decl ----------------------------------------------------------
1570    def eth_out_pdu_decl(self, f):
1571        t = self.eth_hf[f]['ethtype']
1572        out = ''
1573        if (not self.eth_hf[f]['pdu']['export']):
1574            out += 'static '
1575        out += 'int '
1576        out += 'dissect_'+f+'(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_);\n'
1577        return out
1578
1579    #--- eth_output_hf ----------------------------------------------------------
1580    def eth_output_hf (self):
1581        if not len(self.eth_hf_ord) and not len(self.eth_hfpdu_ord) and not len(self.named_bit): return
1582        fx = self.output.file_open('hf')
1583        for f in (self.eth_hfpdu_ord + self.eth_hf_ord):
1584            fx.write("%-50s/* %s */\n" % ("static int %s = -1;  " % (self.eth_hf[f]['fullname']), self.eth_hf[f]['ethtype']))
1585        if (self.named_bit):
1586            fx.write('/* named bits */\n')
1587        for nb in self.named_bit:
1588            fx.write("static int %s = -1;\n" % (nb['ethname']))
1589        if (self.dummy_eag_field):
1590            fx.write("static int %s = -1; /* never registered */\n" % (self.dummy_eag_field))
1591        self.output.file_close(fx)
1592
1593    #--- eth_output_hf_arr ------------------------------------------------------
1594    def eth_output_hf_arr (self):
1595        if not len(self.eth_hf_ord) and not len(self.eth_hfpdu_ord) and not len(self.named_bit): return
1596        fx = self.output.file_open('hfarr')
1597        for f in (self.eth_hfpdu_ord + self.eth_hf_ord):
1598            t = self.eth_hf[f]['ethtype']
1599            if self.remove_prefix and t.startswith(self.remove_prefix):
1600                t = t[len(self.remove_prefix):]
1601            name=self.eth_hf[f]['attr']['NAME']
1602            try: # Python < 3
1603                trantab = maketrans("- ", "__")
1604            except Exception:
1605                trantab = str.maketrans("- ", "__")
1606            name = name.translate(trantab)
1607            namelower = name.lower()
1608            tquoted_lower = '"' + t.lower() + '"'
1609            # Try to avoid giving blurbs that give no more info than the name
1610            if tquoted_lower == namelower or \
1611               t == "NULL" or \
1612               tquoted_lower.replace("t_", "") == namelower:
1613                blurb = 'NULL'
1614            else:
1615                blurb = '"%s"' % (t)
1616            attr = self.eth_hf[f]['attr'].copy()
1617            if attr['TYPE'] == 'FT_NONE':
1618                attr['ABBREV'] = '"%s.%s_element"' % (self.proto, attr['ABBREV'])
1619            else:
1620                attr['ABBREV'] = '"%s.%s"' % (self.proto, attr['ABBREV'])
1621            if 'BLURB' not in attr:
1622                attr['BLURB'] = blurb
1623            fx.write('    { &%s,\n' % (self.eth_hf[f]['fullname']))
1624            fx.write('      { %(NAME)s, %(ABBREV)s,\n' % attr)
1625            fx.write('        %(TYPE)s, %(DISPLAY)s, %(STRINGS)s, %(BITMASK)s,\n' % attr)
1626            fx.write('        %(BLURB)s, HFILL }},\n' % attr)
1627        for nb in self.named_bit:
1628            flt_str = nb['ethname']
1629            # cut out hf_
1630            flt_str = flt_str[3:]
1631            flt_str = flt_str.replace('_' , '.')
1632            #print("filter string=%s" % (flt_str))
1633            fx.write('    { &%s,\n' % (nb['ethname']))
1634            fx.write('      { "%s", "%s",\n' % (nb['name'], flt_str))
1635            fx.write('        %s, %s, %s, %s,\n' % (nb['ftype'], nb['display'], nb['strings'], nb['bitmask']))
1636            fx.write('        NULL, HFILL }},\n')
1637        self.output.file_close(fx)
1638
1639    #--- eth_output_ett ---------------------------------------------------------
1640    def eth_output_ett (self):
1641        fx = self.output.file_open('ett')
1642        fempty = True
1643        #fx.write("static gint ett_%s = -1;\n" % (self.eproto))
1644        for t in self.eth_type_ord:
1645            if self.eth_type[t]['tree']:
1646                fx.write("static gint %s = -1;\n" % (self.eth_type[t]['tree']))
1647                fempty = False
1648        self.output.file_close(fx, discard=fempty)
1649
1650    #--- eth_output_ett_arr -----------------------------------------------------
1651    def eth_output_ett_arr(self):
1652        fx = self.output.file_open('ettarr')
1653        fempty = True
1654        #fx.write("    &ett_%s,\n" % (self.eproto))
1655        for t in self.eth_type_ord:
1656            if self.eth_type[t]['tree']:
1657                fx.write("    &%s,\n" % (self.eth_type[t]['tree']))
1658                fempty = False
1659        self.output.file_close(fx, discard=fempty)
1660
1661    #--- eth_output_export ------------------------------------------------------
1662    def eth_output_export(self):
1663        fx = self.output.file_open('exp', ext='h')
1664        for t in self.eth_export_ord:  # vals
1665            if (self.eth_type[t]['export'] & EF_ENUM) and self.eth_type[t]['val'].eth_has_enum(t, self):
1666                fx.write(self.eth_type[t]['val'].eth_type_enum(t, self))
1667            if (self.eth_type[t]['export'] & EF_VALS) and self.eth_type[t]['val'].eth_has_vals():
1668                if not self.eth_type[t]['export'] & EF_TABLE:
1669                    if self.eth_type[t]['export'] & EF_WS_DLL:
1670                        fx.write("WS_DLL_PUBLIC ")
1671                    else:
1672                        fx.write("extern ")
1673                    if self.eth_type[t]['val'].HasConstraint() and self.eth_type[t]['val'].constr.Needs64b(self) \
1674                       and self.eth_type[t]['val'].type == 'IntegerType':
1675                        fx.write("const val64_string %s[];\n" % (self.eth_vals_nm(t)))
1676                    else:
1677                        fx.write("const value_string %s[];\n" % (self.eth_vals_nm(t)))
1678                else:
1679                    fx.write(self.eth_type[t]['val'].eth_type_vals(t, self))
1680        for t in self.eth_export_ord:  # functions
1681            if (self.eth_type[t]['export'] & EF_TYPE):
1682                if self.eth_type[t]['export'] & EF_EXTERN:
1683                    if self.eth_type[t]['export'] & EF_WS_DLL:
1684                        fx.write("WS_DLL_PUBLIC ")
1685                    else:
1686                        fx.write("extern ")
1687                fx.write(self.eth_type_fn_h(t))
1688        for f in self.eth_hfpdu_ord:  # PDUs
1689            if (self.eth_hf[f]['pdu'] and self.eth_hf[f]['pdu']['export']):
1690                fx.write(self.eth_out_pdu_decl(f))
1691        self.output.file_close(fx)
1692
1693    #--- eth_output_expcnf ------------------------------------------------------
1694    def eth_output_expcnf(self):
1695        fx = self.output.file_open('exp', ext='cnf')
1696        fx.write('#.MODULE\n')
1697        maxw = 0
1698        for (m, p) in self.modules:
1699            if (len(m) > maxw): maxw = len(m)
1700        for (m, p) in self.modules:
1701            fx.write("%-*s  %s\n" % (maxw, m, p))
1702        fx.write('#.END\n\n')
1703        for cls in self.objectclass_ord:
1704            if self.objectclass[cls]['export']:
1705                cnm = cls
1706                if self.objectclass[cls]['export'] & EF_MODULE:
1707                    cnm = "$%s$%s" % (self.objectclass[cls]['module'], cnm)
1708                fx.write('#.CLASS %s\n' % (cnm))
1709                maxw = 2
1710                for fld in self.objectclass[cls]['val'].fields:
1711                    w = len(fld.fld_repr()[0])
1712                    if (w > maxw): maxw = w
1713                for fld in self.objectclass[cls]['val'].fields:
1714                    repr = fld.fld_repr()
1715                    fx.write('%-*s  %s\n' % (maxw, repr[0], ' '.join(repr[1:])))
1716                fx.write('#.END\n\n')
1717        if self.Ber():
1718            fx.write('#.IMPORT_TAG\n')
1719            for t in self.eth_export_ord:  # tags
1720                if (self.eth_type[t]['export'] & EF_TYPE):
1721                    fx.write('%-24s ' % self.eth_type[t]['ref'][0])
1722                    fx.write('%s %s\n' % self.eth_type[t]['val'].GetTag(self))
1723            fx.write('#.END\n\n')
1724        fx.write('#.TYPE_ATTR\n')
1725        for t in self.eth_export_ord:  # attributes
1726            if (self.eth_type[t]['export'] & EF_TYPE):
1727                tnm = self.eth_type[t]['ref'][0]
1728                if self.eth_type[t]['export'] & EF_MODULE:
1729                    tnm = "$%s$%s" % (self.type[tnm]['module'], tnm)
1730                fx.write('%-24s ' % tnm)
1731                attr = self.eth_get_type_attr(self.eth_type[t]['ref'][0]).copy()
1732                fx.write('TYPE = %(TYPE)-9s  DISPLAY = %(DISPLAY)-9s  STRINGS = %(STRINGS)s  BITMASK = %(BITMASK)s\n' % attr)
1733        fx.write('#.END\n\n')
1734        self.output.file_close(fx, keep_anyway=True)
1735
1736    #--- eth_output_val ------------------------------------------------------
1737    def eth_output_val(self):
1738        fx = self.output.file_open('val', ext='h')
1739        for v in self.eth_value_ord1:
1740            vv = self.eth_value[v]['value']
1741            if isinstance (vv, Value):
1742                vv = vv.to_str(self)
1743            fx.write("#define %-30s %s\n" % (v, vv))
1744        for t in self.eth_type_ord1:
1745            if self.eth_type[t]['import']:
1746                continue
1747            if self.eth_type[t]['val'].eth_has_enum(t, self) and not (self.eth_type[t]['export'] & EF_ENUM):
1748                fx.write(self.eth_type[t]['val'].eth_type_enum(t, self))
1749        self.output.file_close(fx)
1750
1751    #--- eth_output_valexp ------------------------------------------------------
1752    def eth_output_valexp(self):
1753        if (not len(self.eth_vexport_ord)): return
1754        fx = self.output.file_open('valexp', ext='h')
1755        for v in self.eth_vexport_ord:
1756            vv = self.eth_value[v]['value']
1757            if isinstance (vv, Value):
1758                vv = vv.to_str(self)
1759            fx.write("#define %-30s %s\n" % (v, vv))
1760        self.output.file_close(fx)
1761
1762    #--- eth_output_types -------------------------------------------------------
1763    def eth_output_types(self):
1764        def out_pdu(f):
1765            t = self.eth_hf[f]['ethtype']
1766            impl = 'FALSE'
1767            out = ''
1768            if (not self.eth_hf[f]['pdu']['export']):
1769                out += 'static '
1770            out += 'int '
1771            out += 'dissect_'+f+'(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_) {\n'
1772            out += self.output_proto_root()
1773
1774            out += '  int offset = 0;\n'
1775            off_par = 'offset'
1776            ret_par = 'offset'
1777            if (self.Per()):
1778                if (self.Aligned()):
1779                    aligned = 'TRUE'
1780                else:
1781                    aligned = 'FALSE'
1782                out += "  asn1_ctx_t asn1_ctx;\n"
1783                out += self.eth_fn_call('asn1_ctx_init', par=(('&asn1_ctx', 'ASN1_ENC_PER', aligned, 'pinfo'),))
1784            if (self.Ber()):
1785                out += "  asn1_ctx_t asn1_ctx;\n"
1786                out += self.eth_fn_call('asn1_ctx_init', par=(('&asn1_ctx', 'ASN1_ENC_BER', 'TRUE', 'pinfo'),))
1787                par=((impl, 'tvb', off_par,'&asn1_ctx', 'tree', self.eth_hf[f]['fullname']),)
1788            elif (self.Per()):
1789                par=(('tvb', off_par, '&asn1_ctx', 'tree', self.eth_hf[f]['fullname']),)
1790            elif (self.Oer()):
1791                out += "  asn1_ctx_t asn1_ctx;\n"
1792                out += self.eth_fn_call('asn1_ctx_init', par=(('&asn1_ctx', 'ASN1_ENC_OER', 'TRUE', 'pinfo'),))
1793                par=(('tvb', off_par,'&asn1_ctx', 'tree', self.eth_hf[f]['fullname']),)
1794            else:
1795                par=((),)
1796            out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret=ret_par, par=par)
1797            if (self.Per()):
1798                out += '  offset += 7; offset >>= 3;\n'
1799            out += '  return offset;\n'
1800            out += '}\n'
1801            return out
1802        #end out_pdu()
1803        fx = self.output.file_open('fn')
1804        pos = fx.tell()
1805        if (len(self.eth_hfpdu_ord)):
1806            first_decl = True
1807            for f in self.eth_hfpdu_ord:
1808                if (self.eth_hf[f]['pdu'] and self.eth_hf[f]['pdu']['need_decl']):
1809                    if first_decl:
1810                        fx.write('/*--- PDUs declarations ---*/\n')
1811                        first_decl = False
1812                    fx.write(self.eth_out_pdu_decl(f))
1813            if not first_decl:
1814                fx.write('\n')
1815        if self.eth_dep_cycle:
1816            fx.write('/*--- Cyclic dependencies ---*/\n\n')
1817            i = 0
1818            while i < len(self.eth_dep_cycle):
1819                t = self.type[self.eth_dep_cycle[i][0]]['ethname']
1820                if self.dep_cycle_eth_type[t][0] != i: i += 1; continue
1821                fx.write(''.join(['/* %s */\n' % ' -> '.join(self.eth_dep_cycle[i]) for i in self.dep_cycle_eth_type[t]]))
1822                if not self.eth_type[t]['export'] & EF_TYPE:
1823                    fx.write(self.eth_type_fn_h(t))
1824                else:
1825                    fx.write('/*' + self.eth_type_fn_h(t).strip() + '*/\n')
1826                fx.write('\n')
1827                i += 1
1828            fx.write('\n')
1829        for t in self.eth_type_ord1:
1830            if self.eth_type[t]['import']:
1831                continue
1832            if self.eth_type[t]['val'].eth_has_vals():
1833                if self.eth_type[t]['no_emit'] & EF_VALS:
1834                    pass
1835                elif self.eth_type[t]['user_def'] & EF_VALS:
1836                    if self.eth_type[t]['val'].HasConstraint() and self.eth_type[t]['val'].constr.Needs64b(self) \
1837                       and self.eth_type[t]['val'].type == 'IntegerType':
1838                        fx.write("extern const val64_string %s[];\n" % (self.eth_vals_nm(t)))
1839                    else:
1840                        fx.write("extern const value_string %s[];\n" % (self.eth_vals_nm(t)))
1841                elif (self.eth_type[t]['export'] & EF_VALS) and (self.eth_type[t]['export'] & EF_TABLE):
1842                    pass
1843                else:
1844                    fx.write(self.eth_type[t]['val'].eth_type_vals(t, self))
1845            if self.eth_type[t]['no_emit'] & EF_TYPE:
1846                pass
1847            elif self.eth_type[t]['user_def'] & EF_TYPE:
1848                fx.write(self.eth_type_fn_h(t))
1849            else:
1850                fx.write(self.eth_type[t]['val'].eth_type_fn(self.eth_type[t]['proto'], t, self))
1851            fx.write('\n')
1852        if (len(self.eth_hfpdu_ord)):
1853            fx.write('/*--- PDUs ---*/\n\n')
1854            for f in self.eth_hfpdu_ord:
1855                if (self.eth_hf[f]['pdu']):
1856                    if (f in self.emitted_pdu):
1857                        fx.write("  /* %s already emitted */\n" % (f))
1858                    else:
1859                        fx.write(out_pdu(f))
1860                        self.emitted_pdu[f] = True
1861            fx.write('\n')
1862        fempty = pos == fx.tell()
1863        self.output.file_close(fx, discard=fempty)
1864
1865    #--- eth_output_dis_hnd -----------------------------------------------------
1866    def eth_output_dis_hnd(self):
1867        fx = self.output.file_open('dis-hnd')
1868        fempty = True
1869        for f in self.eth_hfpdu_ord:
1870            pdu = self.eth_hf[f]['pdu']
1871            if (pdu and pdu['reg'] and not pdu['hidden']):
1872                dis = self.proto
1873                if (pdu['reg'] != '.'):
1874                    dis += '.' + pdu['reg']
1875                fx.write('static dissector_handle_t %s_handle;\n' % (asn2c(dis)))
1876                fempty = False
1877        fx.write('\n')
1878        self.output.file_close(fx, discard=fempty)
1879
1880    #--- eth_output_dis_reg -----------------------------------------------------
1881    def eth_output_dis_reg(self):
1882        fx = self.output.file_open('dis-reg')
1883        fempty = True
1884        for f in self.eth_hfpdu_ord:
1885            pdu = self.eth_hf[f]['pdu']
1886            if (pdu and pdu['reg']):
1887                new_prefix = ''
1888                if (pdu['new']): new_prefix = 'new_'
1889                dis = self.proto
1890                if (pdu['reg'] != '.'): dis += '.' + pdu['reg']
1891                fx.write('  %sregister_dissector("%s", dissect_%s, proto_%s);\n' % (new_prefix, dis, f, self.eproto))
1892                if (not pdu['hidden']):
1893                    fx.write('  %s_handle = find_dissector("%s");\n' % (asn2c(dis), dis))
1894                fempty = False
1895        fx.write('\n')
1896        self.output.file_close(fx, discard=fempty)
1897
1898    #--- eth_output_dis_tab -----------------------------------------------------
1899    def eth_output_dis_tab(self):
1900        fx = self.output.file_open('dis-tab')
1901        fempty = True
1902        for k in self.conform.get_order('REGISTER'):
1903            reg = self.conform.use_item('REGISTER', k)
1904            if reg['pdu'] not in self.field: continue
1905            f = self.field[reg['pdu']]['ethname']
1906            pdu = self.eth_hf[f]['pdu']
1907            new_prefix = ''
1908            if (pdu['new']): new_prefix = 'new_'
1909            if (reg['rtype'] in ('NUM', 'STR')):
1910                rstr = ''
1911                if (reg['rtype'] == 'STR'):
1912                    rstr = 'string'
1913                else:
1914                    rstr = 'uint'
1915                if (pdu['reg']):
1916                    dis = self.proto
1917                    if (pdu['reg'] != '.'): dis += '.' + pdu['reg']
1918                    if  (not pdu['hidden']):
1919                        hnd = '%s_handle' % (asn2c(dis))
1920                    else:
1921                        hnd = 'find_dissector("%s")' % (dis)
1922                else:
1923                    hnd = '%screate_dissector_handle(dissect_%s, proto_%s)' % (new_prefix, f, self.eproto)
1924                rport = self.value_get_eth(reg['rport'])
1925                fx.write('  dissector_add_%s("%s", %s, %s);\n' % (rstr, reg['rtable'], rport, hnd))
1926            elif (reg['rtype'] in ('BER', 'PER', 'OER')):
1927                roid = self.value_get_eth(reg['roid'])
1928                fx.write('  %sregister_%s_oid_dissector(%s, dissect_%s, proto_%s, %s);\n' % (new_prefix, reg['rtype'].lower(), roid, f, self.eproto, reg['roidname']))
1929            fempty = False
1930        fx.write('\n')
1931        self.output.file_close(fx, discard=fempty)
1932
1933    #--- eth_output_syn_reg -----------------------------------------------------
1934    def eth_output_syn_reg(self):
1935        fx = self.output.file_open('syn-reg')
1936        fempty = True
1937        first_decl = True
1938        for k in self.conform.get_order('SYNTAX'):
1939            reg = self.conform.use_item('SYNTAX', k)
1940            if reg['pdu'] not in self.field: continue
1941            f = self.field[reg['pdu']]['ethname']
1942            pdu = self.eth_hf[f]['pdu']
1943            new_prefix = ''
1944            if (pdu['new']): new_prefix = 'new_'
1945            if first_decl:
1946                fx.write('  /*--- Syntax registrations ---*/\n')
1947                first_decl = False
1948            fx.write('  %sregister_ber_syntax_dissector(%s, proto_%s, dissect_%s_PDU);\n' % (new_prefix, k, self.eproto, reg['pdu']));
1949            fempty=False
1950        self.output.file_close(fx, discard=fempty)
1951
1952    #--- eth_output_tables -----------------------------------------------------
1953    def eth_output_tables(self):
1954        for num in list(self.conform.report.keys()):
1955            fx = self.output.file_open('table' + num)
1956            for rep in self.conform.report[num]:
1957                self.eth_output_table(fx, rep)
1958            self.output.file_close(fx)
1959
1960    #--- eth_output_table -----------------------------------------------------
1961    def eth_output_table(self, fx, rep):
1962        if rep['type'] == 'HDR':
1963            fx.write('\n')
1964        if rep['var']:
1965            var = rep['var']
1966            var_list = var.split('.', 1)
1967            cls = var_list[0]
1968            del var_list[0]
1969            flds = []
1970            not_flds = []
1971            sort_flds = []
1972            for f in var_list:
1973                if f[0] == '!':
1974                    not_flds.append(f[1:])
1975                    continue
1976                if f[0] == '#':
1977                    flds.append(f[1:])
1978                    sort_flds.append(f)
1979                    continue
1980                if f[0] == '@':
1981                    flds.append(f[1:])
1982                    sort_flds.append(f[1:])
1983                    continue
1984                flds.append(f)
1985            objs = {}
1986            objs_ord = []
1987            if (cls in self.oassign_cls):
1988                for ident in self.oassign_cls[cls]:
1989                    obj = self.get_obj_repr(ident, flds, not_flds)
1990                    if not obj:
1991                        continue
1992                    obj['_LOOP'] = var
1993                    obj['_DICT'] = str(obj)
1994                    objs[ident] = obj
1995                    objs_ord.append(ident)
1996                if (sort_flds):
1997                    # Sort identifiers according to the matching object in objs.
1998                    # The order is determined by sort_flds, keys prefixed by a
1999                    # '#' are compared numerically.
2000                    def obj_key_fn(name):
2001                        obj = objs[name]
2002                        return list(
2003                            int(obj[f[1:]]) if f[0] == '#' else obj[f]
2004                            for f in sort_flds
2005                        )
2006                    objs_ord.sort(key=obj_key_fn)
2007                for ident in objs_ord:
2008                    obj = objs[ident]
2009                    try:
2010                        text = rep['text'] % obj
2011                    except (KeyError):
2012                        raise sys.exc_info()[0]("%s:%s invalid key %s for information object %s of %s" % (rep['fn'], rep['lineno'], sys.exc_info()[1], ident, var))
2013                    fx.write(text)
2014            else:
2015                fx.write("/* Unknown or empty loop list %s */\n" % (var))
2016        else:
2017            fx.write(rep['text'])
2018        if rep['type'] == 'FTR':
2019            fx.write('\n')
2020
2021    #--- dupl_report -----------------------------------------------------
2022    def dupl_report(self):
2023        # types
2024        tmplist = sorted(self.eth_type_dupl.keys())
2025        for t in tmplist:
2026            msg = "The same type names for different types. Explicit type renaming is recommended.\n"
2027            msg += t + "\n"
2028            for tt in self.eth_type_dupl[t]:
2029                msg += " %-20s %s\n" % (self.type[tt]['ethname'], tt)
2030            warnings.warn_explicit(msg, UserWarning, '', 0)
2031        # fields
2032        tmplist = list(self.eth_hf_dupl.keys())
2033        tmplist.sort()
2034        for f in tmplist:
2035            msg = "The same field names for different types. Explicit field renaming is recommended.\n"
2036            msg += f + "\n"
2037            for tt in list(self.eth_hf_dupl[f].keys()):
2038                msg += " %-20s %-20s " % (self.eth_hf_dupl[f][tt], tt)
2039                msg += ", ".join(self.eth_hf[self.eth_hf_dupl[f][tt]]['ref'])
2040                msg += "\n"
2041            warnings.warn_explicit(msg, UserWarning, '', 0)
2042
2043    #--- eth_do_output ------------------------------------------------------------
2044    def eth_do_output(self):
2045        if self.dbg('a'):
2046            print("\n# Assignments")
2047            for a in self.assign_ord:
2048                v = ' '
2049                if (self.assign[a]['virt']): v = '*'
2050                print('{} {}'.format(v, a))
2051            print("\n# Value assignments")
2052            for a in self.vassign_ord:
2053                print(' {}'.format(a))
2054            print("\n# Information object assignments")
2055            for a in self.oassign_ord:
2056                print(" %-12s (%s)" % (a, self.oassign[a].cls))
2057        if self.dbg('t'):
2058            print("\n# Imported Types")
2059            print("%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol"))
2060            print("-" * 100)
2061            for t in self.type_imp:
2062                print("%-40s %-24s %-24s" % (t, self.type[t]['import'], self.type[t]['proto']))
2063            print("\n# Imported Values")
2064            print("%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol"))
2065            print("-" * 100)
2066            for t in self.value_imp:
2067                print("%-40s %-24s %-24s" % (t, self.value[t]['import'], self.value[t]['proto']))
2068            print("\n# Imported Object Classes")
2069            print("%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol"))
2070            print("-" * 100)
2071            for t in self.objectclass_imp:
2072                print("%-40s %-24s %-24s" % (t, self.objectclass[t]['import'], self.objectclass[t]['proto']))
2073            print("\n# Exported Types")
2074            print("%-31s %s" % ("Wireshark type", "Export Flag"))
2075            print("-" * 100)
2076            for t in self.eth_export_ord:
2077                print("%-31s 0x%02X" % (t, self.eth_type[t]['export']))
2078            print("\n# Exported Values")
2079            print("%-40s %s" % ("Wireshark name", "Value"))
2080            print("-" * 100)
2081            for v in self.eth_vexport_ord:
2082                vv = self.eth_value[v]['value']
2083                if isinstance (vv, Value):
2084                    vv = vv.to_str(self)
2085                print("%-40s %s" % (v, vv))
2086            print("\n# ASN.1 Object Classes")
2087            print("%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol"))
2088            print("-" * 100)
2089            for t in self.objectclass_ord:
2090                print("%-40s " % (t))
2091            print("\n# ASN.1 Types")
2092            print("%-49s %-24s %-24s" % ("ASN.1 unique name", "'tname'", "Wireshark type"))
2093            print("-" * 100)
2094            for t in self.type_ord:
2095                print("%-49s %-24s %-24s" % (t, self.type[t]['tname'], self.type[t]['ethname']))
2096            print("\n# Wireshark Types")
2097            print("Wireshark type                   References (ASN.1 types)")
2098            print("-" * 100)
2099            for t in self.eth_type_ord:
2100                sys.stdout.write("%-31s %d" % (t, len(self.eth_type[t]['ref'])))
2101                print(', '.join(self.eth_type[t]['ref']))
2102            print("\n# ASN.1 Values")
2103            print("%-40s %-18s %-20s %s" % ("ASN.1 unique name", "Type", "Value", "Wireshark value"))
2104            print("-" * 100)
2105            for v in self.value_ord:
2106                vv = self.value[v]['value']
2107                if isinstance (vv, Value):
2108                    vv = vv.to_str(self)
2109                print("%-40s %-18s %-20s %s" % (v, self.value[v]['type'].eth_tname(), vv, self.value[v]['ethname']))
2110            #print "\n# Wireshark Values"
2111            #print "%-40s %s" % ("Wireshark name", "Value")
2112            #print "-" * 100
2113            #for v in self.eth_value_ord:
2114            #  vv = self.eth_value[v]['value']
2115            #  if isinstance (vv, Value):
2116            #    vv = vv.to_str(self)
2117            #  print "%-40s %s" % (v, vv)
2118            print("\n# ASN.1 Fields")
2119            print("ASN.1 unique name                        Wireshark name        ASN.1 type")
2120            print("-" * 100)
2121            for f in (self.pdu_ord + self.field_ord):
2122                print("%-40s %-20s %s" % (f, self.field[f]['ethname'], self.field[f]['type']))
2123            print("\n# Wireshark Fields")
2124            print("Wireshark name                  Wireshark type        References (ASN.1 fields)")
2125            print("-" * 100)
2126            for f in (self.eth_hfpdu_ord + self.eth_hf_ord):
2127                sys.stdout.write("%-30s %-20s %s" % (f, self.eth_hf[f]['ethtype'], len(self.eth_hf[f]['ref'])))
2128                print(', '.join(self.eth_hf[f]['ref']))
2129            #print "\n# Order after dependencies"
2130            #print '\n'.join(self.eth_type_ord1)
2131            print("\n# Cyclic dependencies")
2132            for c in self.eth_dep_cycle:
2133                print(' -> '.join(c))
2134        self.dupl_report()
2135        self.output.outnm = self.outnm_opt
2136        if (not self.output.outnm):
2137            self.output.outnm = self.proto
2138            self.output.outnm = self.output.outnm.replace('.', '-')
2139        if not self.justexpcnf:
2140            self.eth_output_hf()
2141            self.eth_output_ett()
2142            self.eth_output_types()
2143            self.eth_output_hf_arr()
2144            self.eth_output_ett_arr()
2145            self.eth_output_export()
2146            self.eth_output_val()
2147            self.eth_output_valexp()
2148            self.eth_output_dis_hnd()
2149            self.eth_output_dis_reg()
2150            self.eth_output_dis_tab()
2151            self.eth_output_syn_reg()
2152            self.eth_output_tables()
2153        if self.expcnf:
2154            self.eth_output_expcnf()
2155
2156    def dbg_modules(self):
2157        def print_mod(m):
2158            sys.stdout.write("%-30s " % (m))
2159            dep = self.module[m][:]
2160            for i in range(len(dep)):
2161                if dep[i] not in self.module:
2162                    dep[i] = '*' + dep[i]
2163            print(', '.join(dep))
2164        # end of print_mod()
2165        (mod_ord, mod_cyc) = dependency_compute(self.module_ord, self.module, ignore_fn = lambda t: t not in self.module)
2166        print("\n# ASN.1 Moudules")
2167        print("Module name                     Dependency")
2168        print("-" * 100)
2169        new_ord = False
2170        for m in (self.module_ord):
2171            print_mod(m)
2172            new_ord = new_ord or (self.module_ord.index(m) != mod_ord.index(m))
2173        if new_ord:
2174            print("\n# ASN.1 Moudules - in dependency order")
2175            print("Module name                     Dependency")
2176            print("-" * 100)
2177            for m in (mod_ord):
2178                print_mod(m)
2179        if mod_cyc:
2180            print("\nCyclic dependencies:")
2181            for i in (list(range(len(mod_cyc)))):
2182                print("%02d: %s" % (i + 1, str(mod_cyc[i])))
2183
2184
2185#--- EthCnf -------------------------------------------------------------------
2186class EthCnf:
2187    def __init__(self):
2188        self.ectx = None
2189        self.tblcfg = {}
2190        self.table = {}
2191        self.order = {}
2192        self.fn = {}
2193        self.report = {}
2194        self.suppress_line = False
2195        self.include_path = []
2196        self.proto_root_name = None
2197        #                                   Value name             Default value       Duplicity check   Usage check
2198        self.tblcfg['EXPORTS']         = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
2199        self.tblcfg['MAKE_ENUM']       = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
2200        self.tblcfg['USE_VALS_EXT']    = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
2201        self.tblcfg['PDU']             = { 'val_nm' : 'attr',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2202        self.tblcfg['SYNTAX']             = { 'val_nm' : 'attr',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2203        self.tblcfg['REGISTER']        = { 'val_nm' : 'attr',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2204        self.tblcfg['USER_DEFINED']    = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
2205        self.tblcfg['NO_EMIT']         = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
2206        self.tblcfg['MODULE']          = { 'val_nm' : 'proto',    'val_dflt' : None,  'chk_dup' : True, 'chk_use' : False }
2207        self.tblcfg['OMIT_ASSIGNMENT'] = { 'val_nm' : 'omit',     'val_dflt' : False, 'chk_dup' : True, 'chk_use' : True }
2208        self.tblcfg['NO_OMIT_ASSGN']   = { 'val_nm' : 'omit',     'val_dflt' : True,  'chk_dup' : True, 'chk_use' : True }
2209        self.tblcfg['VIRTUAL_ASSGN']   = { 'val_nm' : 'name',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2210        self.tblcfg['SET_TYPE']        = { 'val_nm' : 'type',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2211        self.tblcfg['TYPE_RENAME']     = { 'val_nm' : 'eth_name', 'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2212        self.tblcfg['FIELD_RENAME']    = { 'val_nm' : 'eth_name', 'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
2213        self.tblcfg['IMPORT_TAG']      = { 'val_nm' : 'ttag',     'val_dflt' : (),    'chk_dup' : True, 'chk_use' : False }
2214        self.tblcfg['FN_PARS']         = { 'val_nm' : 'pars',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : True }
2215        self.tblcfg['TYPE_ATTR']       = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : False }
2216        self.tblcfg['ETYPE_ATTR']      = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : False }
2217        self.tblcfg['FIELD_ATTR']      = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : True }
2218        self.tblcfg['EFIELD_ATTR']     = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : True }
2219        self.tblcfg['ASSIGNED_ID']     = { 'val_nm' : 'ids',      'val_dflt' : {},    'chk_dup' : False,'chk_use' : False }
2220        self.tblcfg['ASSIGN_VALUE_TO_TYPE'] = { 'val_nm' : 'name', 'val_dflt' : None, 'chk_dup' : True, 'chk_use' : True }
2221
2222        for k in list(self.tblcfg.keys()) :
2223            self.table[k] = {}
2224            self.order[k] = []
2225
2226    def add_item(self, table, key, fn, lineno, **kw):
2227        if self.tblcfg[table]['chk_dup'] and key in self.table[table]:
2228            warnings.warn_explicit("Duplicated %s for %s. Previous one is at %s:%d" %
2229                                   (table, key, self.table[table][key]['fn'], self.table[table][key]['lineno']),
2230                                   UserWarning, fn, lineno)
2231            return
2232        self.table[table][key] = {'fn' : fn, 'lineno' : lineno, 'used' : False}
2233        self.table[table][key].update(kw)
2234        self.order[table].append(key)
2235
2236    def update_item(self, table, key, fn, lineno, **kw):
2237        if key not in self.table[table]:
2238            self.table[table][key] = {'fn' : fn, 'lineno' : lineno, 'used' : False}
2239            self.order[table].append(key)
2240            self.table[table][key][self.tblcfg[table]['val_nm']] = {}
2241        self.table[table][key][self.tblcfg[table]['val_nm']].update(kw[self.tblcfg[table]['val_nm']])
2242
2243    def get_order(self, table):
2244        return self.order[table]
2245
2246    def check_item(self, table, key):
2247        return key in self.table[table]
2248
2249    def copy_item(self, table, dst_key, src_key):
2250        if (src_key in self.table[table]):
2251            self.table[table][dst_key] = self.table[table][src_key]
2252
2253    def check_item_value(self, table, key, **kw):
2254        return key in self.table[table] and kw.get('val_nm', self.tblcfg[table]['val_nm']) in self.table[table][key]
2255
2256    def use_item(self, table, key, **kw):
2257        vdflt = kw.get('val_dflt', self.tblcfg[table]['val_dflt'])
2258        if key not in self.table[table]: return vdflt
2259        vname = kw.get('val_nm', self.tblcfg[table]['val_nm'])
2260        #print "use_item() - set used for %s %s" % (table, key)
2261        self.table[table][key]['used'] = True
2262        return self.table[table][key].get(vname, vdflt)
2263
2264    def omit_assignment(self, type, ident, module):
2265        if self.ectx.conform.use_item('OMIT_ASSIGNMENT', ident):
2266            return True
2267        if self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*') or \
2268           self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*'+type) or \
2269           self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*/'+module) or \
2270           self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*'+type+'/'+module):
2271            return self.ectx.conform.use_item('NO_OMIT_ASSGN', ident)
2272        return False
2273
2274    def add_fn_line(self, name, ctx, line, fn, lineno):
2275        if name not in self.fn:
2276            self.fn[name] = {'FN_HDR' : None, 'FN_FTR' : None, 'FN_BODY' : None}
2277        if (self.fn[name][ctx]):
2278            self.fn[name][ctx]['text'] += line
2279        else:
2280            self.fn[name][ctx] = {'text' : line, 'used' : False,
2281                                   'fn' : fn, 'lineno' : lineno}
2282    def get_fn_presence(self, name):
2283        #print "get_fn_presence('%s'):%s" % (name, str(self.fn.has_key(name)))
2284        #if self.fn.has_key(name): print self.fn[name]
2285        return name in self.fn
2286    def get_fn_body_presence(self, name):
2287        return name in self.fn and self.fn[name]['FN_BODY']
2288    def get_fn_text(self, name, ctx):
2289        if (name not in self.fn):
2290            return '';
2291        if (not self.fn[name][ctx]):
2292            return '';
2293        self.fn[name][ctx]['used'] = True
2294        out = self.fn[name][ctx]['text']
2295        if (not self.suppress_line):
2296            out = '#line %u "%s"\n%s\n' % (self.fn[name][ctx]['lineno'], rel_dissector_path(self.fn[name][ctx]['fn']), out);
2297        return out
2298
2299    def add_pdu(self, par, fn, lineno):
2300        #print "add_pdu(par=%s, %s, %d)" % (str(par), fn, lineno)
2301        (reg, hidden) = (None, False)
2302        if (len(par) > 1): reg = par[1]
2303        if (reg and reg[0]=='@'): (reg, hidden) = (reg[1:], True)
2304        attr = {'new' : False, 'reg' : reg, 'hidden' : hidden, 'need_decl' : False, 'export' : False}
2305        self.add_item('PDU', par[0], attr=attr, fn=fn, lineno=lineno)
2306        return
2307
2308    def add_syntax(self, par, fn, lineno):
2309        #print "add_syntax(par=%s, %s, %d)" % (str(par), fn, lineno)
2310        if( (len(par) >=2)):
2311            name = par[1]
2312        else:
2313            name = '"'+par[0]+'"'
2314        attr = { 'pdu' : par[0] }
2315        self.add_item('SYNTAX', name, attr=attr, fn=fn, lineno=lineno)
2316        return
2317
2318    def add_register(self, pdu, par, fn, lineno):
2319        #print "add_register(pdu=%s, par=%s, %s, %d)" % (pdu, str(par), fn, lineno)
2320        if (par[0] in ('N', 'NUM')):   rtype = 'NUM'; (pmin, pmax) = (2, 2)
2321        elif (par[0] in ('S', 'STR')): rtype = 'STR'; (pmin, pmax) = (2, 2)
2322        elif (par[0] in ('B', 'BER')): rtype = 'BER'; (pmin, pmax) = (1, 2)
2323        elif (par[0] in ('P', 'PER')): rtype = 'PER'; (pmin, pmax) = (1, 2)
2324        elif (par[0] in ('O', 'OER')): rtype = 'OER'; (pmin, pmax) = (1, 2)
2325        else: warnings.warn_explicit("Unknown registration type '%s'" % (par[2]), UserWarning, fn, lineno); return
2326        if ((len(par)-1) < pmin):
2327            warnings.warn_explicit("Too few parameters for %s registration type. At least %d parameters are required" % (rtype, pmin), UserWarning, fn, lineno)
2328            return
2329        if ((len(par)-1) > pmax):
2330            warnings.warn_explicit("Too many parameters for %s registration type. Only %d parameters are allowed" % (rtype, pmax), UserWarning, fn, lineno)
2331        attr = {'pdu' : pdu, 'rtype' : rtype}
2332        if (rtype in ('NUM', 'STR')):
2333            attr['rtable'] = par[1]
2334            attr['rport'] = par[2]
2335            rkey = '/'.join([rtype, attr['rtable'], attr['rport']])
2336        elif (rtype in ('BER', 'PER', 'OER')):
2337            attr['roid'] = par[1]
2338            attr['roidname'] = '""'
2339            if (len(par)>=3):
2340                attr['roidname'] = par[2]
2341            elif attr['roid'][0] != '"':
2342                attr['roidname'] = '"' + attr['roid'] + '"'
2343            rkey = '/'.join([rtype, attr['roid']])
2344        self.add_item('REGISTER', rkey, attr=attr, fn=fn, lineno=lineno)
2345
2346    def check_par(self, par, pmin, pmax, fn, lineno):
2347        for i in range(len(par)):
2348            if par[i] == '-':
2349                par[i] = None
2350                continue
2351            if par[i][0] == '#':
2352                par[i:] = []
2353                break
2354        if len(par) < pmin:
2355            warnings.warn_explicit("Too few parameters. At least %d parameters are required" % (pmin), UserWarning, fn, lineno)
2356            return None
2357        if (pmax >= 0) and (len(par) > pmax):
2358            warnings.warn_explicit("Too many parameters. Only %d parameters are allowed" % (pmax), UserWarning, fn, lineno)
2359            return par[0:pmax]
2360        return par
2361
2362    def read(self, fn):
2363        def get_par(line, pmin, pmax, fn, lineno):
2364            par = line.split(None, pmax)
2365            par = self.check_par(par, pmin, pmax, fn, lineno)
2366            return par
2367
2368        def get_par_nm(line, pmin, pmax, fn, lineno):
2369            if pmax:
2370                par = line.split(None, pmax)
2371            else:
2372                par = [line,]
2373            for i in range(len(par)):
2374                if par[i][0] == '#':
2375                    par[i:] = []
2376                    break
2377            if len(par) < pmin:
2378                warnings.warn_explicit("Too few parameters. At least %d parameters are required" % (pmin), UserWarning, fn, lineno)
2379                return None
2380            if len(par) > pmax:
2381                nmpar = par[pmax]
2382            else:
2383                nmpar = ''
2384            nmpars = {}
2385            nmpar_first = re.compile(r'^\s*(?P<attr>[_A-Z][_A-Z0-9]*)\s*=\s*')
2386            nmpar_next = re.compile(r'\s+(?P<attr>[_A-Z][_A-Z0-9]*)\s*=\s*')
2387            nmpar_end = re.compile(r'\s*$')
2388            result = nmpar_first.search(nmpar)
2389            pos = 0
2390            while result:
2391                k = result.group('attr')
2392                pos = result.end()
2393                result = nmpar_next.search(nmpar, pos)
2394                p1 = pos
2395                if result:
2396                    p2 = result.start()
2397                else:
2398                    p2 = nmpar_end.search(nmpar, pos).start()
2399                v = nmpar[p1:p2]
2400                nmpars[k] = v
2401            if len(par) > pmax:
2402                par[pmax] = nmpars
2403            return par
2404
2405        f = open(fn, "r")
2406        lineno = 0
2407        is_import = False
2408        directive = re.compile(r'^\s*#\.(?P<name>[A-Z_][A-Z_0-9]*)(\s+|$)')
2409        cdirective = re.compile(r'^\s*##')
2410        report = re.compile(r'^TABLE(?P<num>\d*)_(?P<type>HDR|BODY|FTR)$')
2411        comment = re.compile(r'^\s*#[^.#]')
2412        empty = re.compile(r'^\s*$')
2413        ctx = None
2414        name = ''
2415        default_flags = 0x00
2416        stack = []
2417        while True:
2418            if not f.closed:
2419                line = f.readline()
2420                lineno += 1
2421            else:
2422                line = None
2423            if not line:
2424                if not f.closed:
2425                    f.close()
2426                if stack:
2427                    frec = stack.pop()
2428                    fn, f, lineno, is_import = frec['fn'], frec['f'], frec['lineno'], frec['is_import']
2429                    continue
2430                else:
2431                    break
2432            if comment.search(line): continue
2433            result = directive.search(line)
2434            if result:  # directive
2435                rep_result = report.search(result.group('name'))
2436                if result.group('name') == 'END_OF_CNF':
2437                    f.close()
2438                elif result.group('name') == 'OPT':
2439                    ctx = result.group('name')
2440                    par = get_par(line[result.end():], 0, -1, fn=fn, lineno=lineno)
2441                    if not par: continue
2442                    self.set_opt(par[0], par[1:], fn, lineno)
2443                    ctx = None
2444                elif result.group('name') in ('PDU', 'REGISTER',
2445                                            'MODULE', 'MODULE_IMPORT',
2446                                            'OMIT_ASSIGNMENT', 'NO_OMIT_ASSGN',
2447                                            'VIRTUAL_ASSGN', 'SET_TYPE', 'ASSIGN_VALUE_TO_TYPE',
2448                                            'TYPE_RENAME', 'FIELD_RENAME', 'TF_RENAME', 'IMPORT_TAG',
2449                                            'TYPE_ATTR', 'ETYPE_ATTR', 'FIELD_ATTR', 'EFIELD_ATTR',
2450                                            'SYNTAX'):
2451                    ctx = result.group('name')
2452                elif result.group('name') in ('OMIT_ALL_ASSIGNMENTS', 'OMIT_ASSIGNMENTS_EXCEPT',
2453                                              'OMIT_ALL_TYPE_ASSIGNMENTS', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT',
2454                                              'OMIT_ALL_VALUE_ASSIGNMENTS', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
2455                    ctx = result.group('name')
2456                    key = '*'
2457                    if ctx in ('OMIT_ALL_TYPE_ASSIGNMENTS', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT'):
2458                        key += 'T'
2459                    if ctx in ('OMIT_ALL_VALUE_ASSIGNMENTS', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
2460                        key += 'V'
2461                    par = get_par(line[result.end():], 0, 1, fn=fn, lineno=lineno)
2462                    if par:
2463                        key += '/' + par[0]
2464                    self.add_item('OMIT_ASSIGNMENT', key, omit=True, fn=fn, lineno=lineno)
2465                    if ctx in ('OMIT_ASSIGNMENTS_EXCEPT', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
2466                        ctx = 'NO_OMIT_ASSGN'
2467                    else:
2468                        ctx = None
2469                elif result.group('name') in ('EXPORTS', 'MODULE_EXPORTS', 'USER_DEFINED', 'NO_EMIT'):
2470                    ctx = result.group('name')
2471                    default_flags = EF_TYPE|EF_VALS
2472                    if ctx == 'MODULE_EXPORTS':
2473                        ctx = 'EXPORTS'
2474                        default_flags |= EF_MODULE
2475                    if ctx == 'EXPORTS':
2476                        par = get_par(line[result.end():], 0, 5, fn=fn, lineno=lineno)
2477                    else:
2478                        par = get_par(line[result.end():], 0, 1, fn=fn, lineno=lineno)
2479                    if not par: continue
2480                    p = 1
2481                    if (par[0] == 'WITH_VALS'):      default_flags |= EF_TYPE|EF_VALS
2482                    elif (par[0] == 'WITHOUT_VALS'): default_flags |= EF_TYPE; default_flags &= ~EF_VALS
2483                    elif (par[0] == 'ONLY_VALS'):    default_flags &= ~EF_TYPE; default_flags |= EF_VALS
2484                    elif (ctx == 'EXPORTS'): p = 0
2485                    else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[0]), UserWarning, fn, lineno)
2486                    for i in range(p, len(par)):
2487                        if (par[i] == 'ONLY_ENUM'):   default_flags &= ~(EF_TYPE|EF_VALS); default_flags |= EF_ENUM
2488                        elif (par[i] == 'WITH_ENUM'): default_flags |= EF_ENUM
2489                        elif (par[i] == 'VALS_WITH_TABLE'):  default_flags |= EF_TABLE
2490                        elif (par[i] == 'WS_DLL'):    default_flags |= EF_WS_DLL
2491                        elif (par[i] == 'EXTERN'):    default_flags |= EF_EXTERN
2492                        elif (par[i] == 'NO_PROT_PREFIX'): default_flags |= EF_NO_PROT
2493                        else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
2494                elif result.group('name') in ('MAKE_ENUM', 'MAKE_DEFINES'):
2495                    ctx = result.group('name')
2496                    default_flags = EF_ENUM
2497                    if ctx == 'MAKE_ENUM': default_flags |= EF_NO_PROT|EF_NO_TYPE
2498                    if ctx == 'MAKE_DEFINES': default_flags |= EF_DEFINE|EF_UCASE|EF_NO_TYPE
2499                    par = get_par(line[result.end():], 0, 3, fn=fn, lineno=lineno)
2500                    for i in range(0, len(par)):
2501                        if (par[i] == 'NO_PROT_PREFIX'):   default_flags |= EF_NO_PROT
2502                        elif (par[i] == 'PROT_PREFIX'):    default_flags &= ~ EF_NO_PROT
2503                        elif (par[i] == 'NO_TYPE_PREFIX'): default_flags |= EF_NO_TYPE
2504                        elif (par[i] == 'TYPE_PREFIX'):    default_flags &= ~ EF_NO_TYPE
2505                        elif (par[i] == 'UPPER_CASE'):     default_flags |= EF_UCASE
2506                        elif (par[i] == 'NO_UPPER_CASE'):  default_flags &= ~EF_UCASE
2507                        else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
2508                elif result.group('name') == 'USE_VALS_EXT':
2509                    ctx = result.group('name')
2510                    default_flags = 0xFF
2511                elif result.group('name') == 'FN_HDR':
2512                    minp = 1
2513                    if (ctx in ('FN_PARS',)) and name: minp = 0
2514                    par = get_par(line[result.end():], minp, 1, fn=fn, lineno=lineno)
2515                    if (not par) and (minp > 0): continue
2516                    ctx = result.group('name')
2517                    if par: name = par[0]
2518                elif result.group('name') == 'FN_FTR':
2519                    minp = 1
2520                    if (ctx in ('FN_PARS','FN_HDR')) and name: minp = 0
2521                    par = get_par(line[result.end():], minp, 1, fn=fn, lineno=lineno)
2522                    if (not par) and (minp > 0): continue
2523                    ctx = result.group('name')
2524                    if par: name = par[0]
2525                elif result.group('name') == 'FN_BODY':
2526                    par = get_par_nm(line[result.end():], 1, 1, fn=fn, lineno=lineno)
2527                    if not par: continue
2528                    ctx = result.group('name')
2529                    name = par[0]
2530                    if len(par) > 1:
2531                        self.add_item('FN_PARS', name, pars=par[1], fn=fn, lineno=lineno)
2532                elif result.group('name') == 'FN_PARS':
2533                    par = get_par_nm(line[result.end():], 0, 1, fn=fn, lineno=lineno)
2534                    ctx = result.group('name')
2535                    if not par:
2536                        name = None
2537                    elif len(par) == 1:
2538                        name = par[0]
2539                        self.add_item(ctx, name, pars={}, fn=fn, lineno=lineno)
2540                    elif len(par) > 1:
2541                        self.add_item(ctx, par[0], pars=par[1], fn=fn, lineno=lineno)
2542                        ctx = None
2543                elif result.group('name') == 'CLASS':
2544                    par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
2545                    if not par: continue
2546                    ctx = result.group('name')
2547                    name = par[0]
2548                    add_class_ident(name)
2549                    if not name.split('$')[-1].isupper():
2550                        warnings.warn_explicit("No lower-case letters shall be included in information object class name (%s)" % (name),
2551                                                UserWarning, fn, lineno)
2552                elif result.group('name') == 'ASSIGNED_OBJECT_IDENTIFIER':
2553                    par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
2554                    if not par: continue
2555                    self.update_item('ASSIGNED_ID', 'OBJECT_IDENTIFIER', ids={par[0] : par[0]}, fn=fn, lineno=lineno)
2556                elif rep_result:  # Reports
2557                    num = rep_result.group('num')
2558                    type = rep_result.group('type')
2559                    if type == 'BODY':
2560                        par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
2561                        if not par: continue
2562                    else:
2563                        par = get_par(line[result.end():], 0, 0, fn=fn, lineno=lineno)
2564                    rep = { 'type' : type, 'var' : None, 'text' : '', 'fn' : fn, 'lineno' : lineno }
2565                    if len(par) > 0:
2566                        rep['var'] = par[0]
2567                    self.report.setdefault(num, []).append(rep)
2568                    ctx = 'TABLE'
2569                    name = num
2570                elif result.group('name') in ('INCLUDE', 'IMPORT') :
2571                    is_imp = result.group('name') == 'IMPORT'
2572                    par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
2573                    if not par:
2574                        warnings.warn_explicit("%s requires parameter" % (result.group('name'),), UserWarning, fn, lineno)
2575                        continue
2576                    fname = par[0]
2577                    #print "Try include: %s" % (fname)
2578                    if (not os.path.exists(fname)):
2579                        fname = os.path.join(os.path.split(fn)[0], par[0])
2580                    #print "Try include: %s" % (fname)
2581                    i = 0
2582                    while not os.path.exists(fname) and (i < len(self.include_path)):
2583                        fname = os.path.join(self.include_path[i], par[0])
2584                        #print "Try include: %s" % (fname)
2585                        i += 1
2586                    if (not os.path.exists(fname)):
2587                        if is_imp:
2588                            continue  # just ignore
2589                        else:
2590                            fname = par[0]  # report error
2591                    fnew = open(fname, "r")
2592                    stack.append({'fn' : fn, 'f' : f, 'lineno' : lineno, 'is_import' : is_import})
2593                    fn, f, lineno, is_import = par[0], fnew, 0, is_imp
2594                elif result.group('name') == 'END':
2595                    ctx = None
2596                else:
2597                    warnings.warn_explicit("Unknown directive '%s'" % (result.group('name')), UserWarning, fn, lineno)
2598                continue
2599            if not ctx:
2600                if not empty.match(line):
2601                    warnings.warn_explicit("Non-empty line in empty context", UserWarning, fn, lineno)
2602            elif ctx == 'OPT':
2603                if empty.match(line): continue
2604                par = get_par(line, 1, -1, fn=fn, lineno=lineno)
2605                if not par: continue
2606                self.set_opt(par[0], par[1:], fn, lineno)
2607            elif ctx in ('EXPORTS', 'USER_DEFINED', 'NO_EMIT'):
2608                if empty.match(line): continue
2609                if ctx == 'EXPORTS':
2610                    par = get_par(line, 1, 6, fn=fn, lineno=lineno)
2611                else:
2612                    par = get_par(line, 1, 2, fn=fn, lineno=lineno)
2613                if not par: continue
2614                flags = default_flags
2615                p = 2
2616                if (len(par)>=2):
2617                    if (par[1] == 'WITH_VALS'):      flags |= EF_TYPE|EF_VALS
2618                    elif (par[1] == 'WITHOUT_VALS'): flags |= EF_TYPE; flags &= ~EF_VALS
2619                    elif (par[1] == 'ONLY_VALS'):    flags &= ~EF_TYPE; flags |= EF_VALS
2620                    elif (ctx == 'EXPORTS'): p = 1
2621                    else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[1]), UserWarning, fn, lineno)
2622                for i in range(p, len(par)):
2623                    if (par[i] == 'ONLY_ENUM'):        flags &= ~(EF_TYPE|EF_VALS); flags |= EF_ENUM
2624                    elif (par[i] == 'WITH_ENUM'):      flags |= EF_ENUM
2625                    elif (par[i] == 'VALS_WITH_TABLE'):  flags |= EF_TABLE
2626                    elif (par[i] == 'WS_DLL'):         flags |= EF_WS_DLL
2627                    elif (par[i] == 'EXTERN'):         flags |= EF_EXTERN
2628                    elif (par[i] == 'NO_PROT_PREFIX'): flags |= EF_NO_PROT
2629                    else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
2630                self.add_item(ctx, par[0], flag=flags, fn=fn, lineno=lineno)
2631            elif ctx in ('MAKE_ENUM', 'MAKE_DEFINES'):
2632                if empty.match(line): continue
2633                par = get_par(line, 1, 4, fn=fn, lineno=lineno)
2634                if not par: continue
2635                flags = default_flags
2636                for i in range(1, len(par)):
2637                    if (par[i] == 'NO_PROT_PREFIX'):   flags |= EF_NO_PROT
2638                    elif (par[i] == 'PROT_PREFIX'):    flags &= ~ EF_NO_PROT
2639                    elif (par[i] == 'NO_TYPE_PREFIX'): flags |= EF_NO_TYPE
2640                    elif (par[i] == 'TYPE_PREFIX'):    flags &= ~ EF_NO_TYPE
2641                    elif (par[i] == 'UPPER_CASE'):     flags |= EF_UCASE
2642                    elif (par[i] == 'NO_UPPER_CASE'):  flags &= ~EF_UCASE
2643                    else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
2644                self.add_item('MAKE_ENUM', par[0], flag=flags, fn=fn, lineno=lineno)
2645            elif ctx == 'USE_VALS_EXT':
2646                if empty.match(line): continue
2647                par = get_par(line, 1, 1, fn=fn, lineno=lineno)
2648                if not par: continue
2649                flags = default_flags
2650                self.add_item('USE_VALS_EXT', par[0], flag=flags, fn=fn, lineno=lineno)
2651            elif ctx == 'PDU':
2652                if empty.match(line): continue
2653                par = get_par(line, 1, 5, fn=fn, lineno=lineno)
2654                if not par: continue
2655                self.add_pdu(par[0:2], fn, lineno)
2656                if (len(par)>=3):
2657                    self.add_register(par[0], par[2:5], fn, lineno)
2658            elif ctx == 'SYNTAX':
2659                if empty.match(line): continue
2660                par = get_par(line, 1, 2, fn=fn, lineno=lineno)
2661                if not par: continue
2662                if not self.check_item('PDU', par[0]):
2663                    self.add_pdu(par[0:1], fn, lineno)
2664                self.add_syntax(par, fn, lineno)
2665            elif ctx == 'REGISTER':
2666                if empty.match(line): continue
2667                par = get_par(line, 3, 4, fn=fn, lineno=lineno)
2668                if not par: continue
2669                if not self.check_item('PDU', par[0]):
2670                    self.add_pdu(par[0:1], fn, lineno)
2671                self.add_register(par[0], par[1:4], fn, lineno)
2672            elif ctx in ('MODULE', 'MODULE_IMPORT'):
2673                if empty.match(line): continue
2674                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2675                if not par: continue
2676                self.add_item('MODULE', par[0], proto=par[1], fn=fn, lineno=lineno)
2677            elif ctx == 'IMPORT_TAG':
2678                if empty.match(line): continue
2679                par = get_par(line, 3, 3, fn=fn, lineno=lineno)
2680                if not par: continue
2681                self.add_item(ctx, par[0], ttag=(par[1], par[2]), fn=fn, lineno=lineno)
2682            elif ctx == 'OMIT_ASSIGNMENT':
2683                if empty.match(line): continue
2684                par = get_par(line, 1, 1, fn=fn, lineno=lineno)
2685                if not par: continue
2686                self.add_item(ctx, par[0], omit=True, fn=fn, lineno=lineno)
2687            elif ctx == 'NO_OMIT_ASSGN':
2688                if empty.match(line): continue
2689                par = get_par(line, 1, 1, fn=fn, lineno=lineno)
2690                if not par: continue
2691                self.add_item(ctx, par[0], omit=False, fn=fn, lineno=lineno)
2692            elif ctx == 'VIRTUAL_ASSGN':
2693                if empty.match(line): continue
2694                par = get_par(line, 2, -1, fn=fn, lineno=lineno)
2695                if not par: continue
2696                if (len(par[1].split('/')) > 1) and not self.check_item('SET_TYPE', par[1]):
2697                    self.add_item('SET_TYPE', par[1], type=par[0], fn=fn, lineno=lineno)
2698                self.add_item('VIRTUAL_ASSGN', par[1], name=par[0], fn=fn, lineno=lineno)
2699                for nm in par[2:]:
2700                    self.add_item('SET_TYPE', nm, type=par[0], fn=fn, lineno=lineno)
2701                if not par[0][0].isupper():
2702                    warnings.warn_explicit("Virtual assignment should have uppercase name (%s)" % (par[0]),
2703                                            UserWarning, fn, lineno)
2704            elif ctx == 'SET_TYPE':
2705                if empty.match(line): continue
2706                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2707                if not par: continue
2708                if not self.check_item('VIRTUAL_ASSGN', par[0]):
2709                    self.add_item('SET_TYPE', par[0], type=par[1], fn=fn, lineno=lineno)
2710                if not par[1][0].isupper():
2711                    warnings.warn_explicit("Set type should have uppercase name (%s)" % (par[1]),
2712                                            UserWarning, fn, lineno)
2713            elif ctx == 'ASSIGN_VALUE_TO_TYPE':
2714                if empty.match(line): continue
2715                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2716                if not par: continue
2717                self.add_item(ctx, par[0], name=par[1], fn=fn, lineno=lineno)
2718            elif ctx == 'TYPE_RENAME':
2719                if empty.match(line): continue
2720                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2721                if not par: continue
2722                self.add_item('TYPE_RENAME', par[0], eth_name=par[1], fn=fn, lineno=lineno)
2723                if not par[1][0].isupper():
2724                    warnings.warn_explicit("Type should be renamed to uppercase name (%s)" % (par[1]),
2725                                            UserWarning, fn, lineno)
2726            elif ctx == 'FIELD_RENAME':
2727                if empty.match(line): continue
2728                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2729                if not par: continue
2730                self.add_item('FIELD_RENAME', par[0], eth_name=par[1], fn=fn, lineno=lineno)
2731                if not par[1][0].islower():
2732                    warnings.warn_explicit("Field should be renamed to lowercase name (%s)" % (par[1]),
2733                                            UserWarning, fn, lineno)
2734            elif ctx == 'TF_RENAME':
2735                if empty.match(line): continue
2736                par = get_par(line, 2, 2, fn=fn, lineno=lineno)
2737                if not par: continue
2738                tmpu = par[1][0].upper() + par[1][1:]
2739                tmpl = par[1][0].lower() + par[1][1:]
2740                self.add_item('TYPE_RENAME', par[0], eth_name=tmpu, fn=fn, lineno=lineno)
2741                if not tmpu[0].isupper():
2742                    warnings.warn_explicit("Type should be renamed to uppercase name (%s)" % (par[1]),
2743                                            UserWarning, fn, lineno)
2744                self.add_item('FIELD_RENAME', par[0], eth_name=tmpl, fn=fn, lineno=lineno)
2745                if not tmpl[0].islower():
2746                    warnings.warn_explicit("Field should be renamed to lowercase name (%s)" % (par[1]),
2747                                            UserWarning, fn, lineno)
2748            elif ctx in ('TYPE_ATTR', 'ETYPE_ATTR', 'FIELD_ATTR', 'EFIELD_ATTR'):
2749                if empty.match(line): continue
2750                par = get_par_nm(line, 1, 1, fn=fn, lineno=lineno)
2751                if not par: continue
2752                self.add_item(ctx, par[0], attr=par[1], fn=fn, lineno=lineno)
2753            elif ctx == 'FN_PARS':
2754                if empty.match(line): continue
2755                if name:
2756                    par = get_par_nm(line, 0, 0, fn=fn, lineno=lineno)
2757                else:
2758                    par = get_par_nm(line, 1, 1, fn=fn, lineno=lineno)
2759                if not par: continue
2760                if name:
2761                    self.update_item(ctx, name, pars=par[0], fn=fn, lineno=lineno)
2762                else:
2763                    self.add_item(ctx, par[0], pars=par[1], fn=fn, lineno=lineno)
2764            elif ctx in ('FN_HDR', 'FN_FTR', 'FN_BODY'):
2765                result = cdirective.search(line)
2766                if result:  # directive
2767                    line = '#' + line[result.end():]
2768                self.add_fn_line(name, ctx, line, fn=fn, lineno=lineno)
2769            elif ctx == 'CLASS':
2770                if empty.match(line): continue
2771                par = get_par(line, 1, 3, fn=fn, lineno=lineno)
2772                if not par: continue
2773                if not set_type_to_class(name, par[0], par[1:]):
2774                    warnings.warn_explicit("Could not set type of class member %s.&%s to %s" % (name, par[0], par[1]),
2775                                            UserWarning, fn, lineno)
2776            elif ctx == 'TABLE':
2777                self.report[name][-1]['text'] += line
2778
2779    def set_opt(self, opt, par, fn, lineno):
2780        #print("set_opt: %s, %s" % (opt, par))
2781        if opt in ("-I",):
2782            par = self.check_par(par, 1, 1, fn, lineno)
2783            if not par: return
2784            self.include_path.append(relpath(par[0]))
2785        elif opt in ("-b", "BER", "CER", "DER"):
2786            par = self.check_par(par, 0, 0, fn, lineno)
2787            self.ectx.encoding = 'ber'
2788        elif opt in ("PER",):
2789            par = self.check_par(par, 0, 0, fn, lineno)
2790            self.ectx.encoding = 'per'
2791        elif opt in ("OER",):
2792            par = self.check_par(par, 0, 0, fn, lineno)
2793            self.ectx.encoding = 'oer'
2794        elif opt in ("-p", "PROTO"):
2795            par = self.check_par(par, 1, 1, fn, lineno)
2796            if not par: return
2797            self.ectx.proto_opt = par[0]
2798            self.ectx.merge_modules = True
2799        elif opt in ("ALIGNED",):
2800            par = self.check_par(par, 0, 0, fn, lineno)
2801            self.ectx.aligned = True
2802        elif opt in ("-u", "UNALIGNED"):
2803            par = self.check_par(par, 0, 0, fn, lineno)
2804            self.ectx.aligned = False
2805        elif opt in ("PROTO_ROOT_NAME"):
2806            par = self.check_par(par, 1, 1, fn, lineno)
2807            if not par: return
2808            self.proto_root_name = par[0]
2809        elif opt in ("-d",):
2810            par = self.check_par(par, 1, 1, fn, lineno)
2811            if not par: return
2812            self.ectx.dbgopt = par[0]
2813        elif opt in ("-e",):
2814            par = self.check_par(par, 0, 0, fn, lineno)
2815            self.ectx.expcnf = True
2816        elif opt in ("-S",):
2817            par = self.check_par(par, 0, 0, fn, lineno)
2818            self.ectx.merge_modules = True
2819        elif opt in ("GROUP_BY_PROT",):
2820            par = self.check_par(par, 0, 0, fn, lineno)
2821            self.ectx.group_by_prot = True
2822        elif opt in ("-o",):
2823            par = self.check_par(par, 1, 1, fn, lineno)
2824            if not par: return
2825            self.ectx.outnm_opt = par[0]
2826        elif opt in ("-O",):
2827            par = self.check_par(par, 1, 1, fn, lineno)
2828            if not par: return
2829            self.ectx.output.outdir = relpath(par[0])
2830        elif opt in ("-s",):
2831            par = self.check_par(par, 1, 1, fn, lineno)
2832            if not par: return
2833            self.ectx.output.single_file = relpath(par[0])
2834        elif opt in ("-k",):
2835            par = self.check_par(par, 0, 0, fn, lineno)
2836            self.ectx.output.keep = True
2837        elif opt in ("-L",):
2838            par = self.check_par(par, 0, 0, fn, lineno)
2839            self.suppress_line = True
2840        elif opt in ("EMBEDDED_PDV_CB",):
2841            par = self.check_par(par, 1, 1, fn, lineno)
2842            if not par: return
2843            self.ectx.default_embedded_pdv_cb = par[0]
2844        elif opt in ("EXTERNAL_TYPE_CB",):
2845            par = self.check_par(par, 1, 1, fn, lineno)
2846            if not par: return
2847            self.ectx.default_external_type_cb = par[0]
2848        elif opt in ("-r",):
2849            par = self.check_par(par, 1, 1, fn, lineno)
2850            if not par: return
2851            self.ectx.remove_prefix = par[0]
2852        else:
2853            warnings.warn_explicit("Unknown option %s" % (opt),
2854                                   UserWarning, fn, lineno)
2855
2856    def dbg_print(self):
2857        print("\n# Conformance values")
2858        print("%-15s %-4s %-15s %-20s %s" % ("File", "Line", "Table", "Key", "Value"))
2859        print("-" * 100)
2860        tbls = sorted(self.table.keys())
2861        for t in tbls:
2862            keys = sorted(self.table[t].keys())
2863            for k in keys:
2864                print("%-15s %4s %-15s %-20s %s" % (
2865                      self.table[t][k]['fn'], self.table[t][k]['lineno'], t, k, str(self.table[t][k][self.tblcfg[t]['val_nm']])))
2866
2867    def unused_report(self):
2868        tbls = sorted(self.table.keys())
2869        for t in tbls:
2870            if not self.tblcfg[t]['chk_use']: continue
2871            keys = sorted(self.table[t].keys())
2872            for k in keys:
2873                if not self.table[t][k]['used']:
2874                    warnings.warn_explicit("Unused %s for %s" % (t, k),
2875                                            UserWarning, self.table[t][k]['fn'], self.table[t][k]['lineno'])
2876        fnms = list(self.fn.keys())
2877        fnms.sort()
2878        for f in fnms:
2879            keys = sorted(self.fn[f].keys())
2880            for k in keys:
2881                if not self.fn[f][k]: continue
2882                if not self.fn[f][k]['used']:
2883                    warnings.warn_explicit("Unused %s for %s" % (k, f),
2884                                            UserWarning, self.fn[f][k]['fn'], self.fn[f][k]['lineno'])
2885
2886#--- EthOut -------------------------------------------------------------------
2887class EthOut:
2888    def __init__(self):
2889        self.ectx = None
2890        self.outnm = None
2891        self.outdir = '.'
2892        self.single_file = None
2893        self.created_files = {}
2894        self.created_files_ord = []
2895        self.keep = False
2896
2897    def outcomment(self, ln, comment=None):
2898        if comment:
2899            return '%s %s\n' % (comment, ln)
2900        else:
2901            return '/* %-74s */\n' % (ln)
2902
2903    def created_file_add(self, name, keep_anyway):
2904        name = os.path.normcase(os.path.abspath(name))
2905        if name not in self.created_files:
2906            self.created_files_ord.append(name)
2907            self.created_files[name] = keep_anyway
2908        else:
2909            self.created_files[name] = self.created_files[name] or keep_anyway
2910
2911    def created_file_exists(self, name):
2912        name = os.path.normcase(os.path.abspath(name))
2913        return name in self.created_files
2914
2915    #--- output_fname -------------------------------------------------------
2916    def output_fname(self, ftype, ext='c'):
2917        fn = ''
2918        if not ext in ('cnf',):
2919            fn += 'packet-'
2920        fn += self.outnm
2921        if (ftype):
2922            fn += '-' + ftype
2923        fn += '.' + ext
2924        return fn
2925    #--- file_open -------------------------------------------------------
2926    def file_open(self, ftype, ext='c'):
2927        fn = self.output_fname(ftype, ext=ext)
2928        if self.created_file_exists(fn):
2929            fx = open(fn, 'a')
2930        else:
2931            fx = open(fn, 'w')
2932        comment = None
2933        if ext in ('cnf',):
2934            comment = '#'
2935            fx.write(self.fhdr(fn, comment = comment))
2936        else:
2937            if (not self.single_file and not self.created_file_exists(fn)):
2938                fx.write(self.fhdr(fn))
2939        if not self.ectx.merge_modules:
2940            fx.write('\n')
2941            mstr = "--- "
2942            if self.ectx.groups():
2943                mstr += "Module"
2944                if (len(self.ectx.modules) > 1):
2945                    mstr += "s"
2946                for (m, p) in self.ectx.modules:
2947                    mstr += " %s" % (m)
2948            else:
2949                mstr += "Module %s" % (self.ectx.Module())
2950            mstr += " --- --- ---"
2951            fx.write(self.outcomment(mstr, comment))
2952            fx.write('\n')
2953        return fx
2954    #--- file_close -------------------------------------------------------
2955    def file_close(self, fx, discard=False, keep_anyway=False):
2956        fx.close()
2957        if discard and not self.created_file_exists(fx.name):
2958            os.unlink(fx.name)
2959        else:
2960            self.created_file_add(fx.name, keep_anyway)
2961    #--- fhdr -------------------------------------------------------
2962    def fhdr(self, fn, comment=None):
2963        out = ''
2964        out += self.outcomment('Do not modify this file. Changes will be overwritten.', comment)
2965        out += self.outcomment('Generated automatically by the ASN.1 to Wireshark dissector compiler', comment)
2966        out += self.outcomment(os.path.basename(fn), comment)
2967        out += self.outcomment(' '.join(['asn2wrs.py'] + sys.argv[1:]), comment)
2968        out += '\n'
2969        # Make Windows path separator look like Unix path separator
2970        out = out.replace('\\', '/')
2971        # Change absolute paths and relative paths generated outside
2972        # source directory to paths relative to asn1/<proto> subdir.
2973        out = re.sub(r'(\s)[./A-Z]\S*/dissectors\b', r'\1../..', out)
2974        out = re.sub(r'(\s)[./A-Z]\S*/asn1/\S*?([\s/])', r'\1.\2', out)
2975        return out
2976
2977    #--- dbg_print -------------------------------------------------------
2978    def dbg_print(self):
2979        print("\n# Output files")
2980        print("\n".join(self.created_files_ord))
2981        print("\n")
2982
2983    #--- make_single_file -------------------------------------------------------
2984    def make_single_file(self):
2985        if (not self.single_file): return
2986        in_nm = self.single_file + '.c'
2987        out_nm = os.path.join(self.outdir, self.output_fname(''))
2988        self.do_include(out_nm, in_nm)
2989        in_nm = self.single_file + '.h'
2990        if (os.path.exists(in_nm)):
2991            out_nm = os.path.join(self.outdir, self.output_fname('', ext='h'))
2992            self.do_include(out_nm, in_nm)
2993        if (not self.keep):
2994            for fn in self.created_files_ord:
2995                if not self.created_files[fn]:
2996                    os.unlink(fn)
2997
2998    #--- do_include -------------------------------------------------------
2999    def do_include(self, out_nm, in_nm):
3000        def check_file(fn, fnlist):
3001            fnfull = os.path.normcase(os.path.abspath(fn))
3002            if (fnfull in fnlist and os.path.exists(fnfull)):
3003                return os.path.normpath(fn)
3004            return None
3005        fin = open(in_nm, "r")
3006        fout = open(out_nm, "w")
3007        fout.write(self.fhdr(out_nm))
3008        fout.write('/* Input file: ' + os.path.basename(in_nm) +' */\n')
3009        fout.write('\n')
3010        fout.write('#line %u "%s"\n' % (1, rel_dissector_path(in_nm)))
3011
3012        include = re.compile(r'^\s*#\s*include\s+[<"](?P<fname>[^>"]+)[>"]', re.IGNORECASE)
3013
3014        cont_linenum = 0;
3015
3016        while (True):
3017            cont_linenum = cont_linenum + 1;
3018            line = fin.readline()
3019            if (line == ''): break
3020            ifile = None
3021            result = include.search(line)
3022            #if (result): print os.path.normcase(os.path.abspath(result.group('fname')))
3023            if (result):
3024                ifile = check_file(os.path.join(os.path.split(in_nm)[0], result.group('fname')), self.created_files)
3025                if (not ifile):
3026                    ifile = check_file(os.path.join(self.outdir, result.group('fname')), self.created_files)
3027                if (not ifile):
3028                    ifile = check_file(result.group('fname'), self.created_files)
3029            if (ifile):
3030                fout.write('\n')
3031                fout.write('/*--- Included file: ' + ifile + ' ---*/\n')
3032                fout.write('#line %u "%s"\n' % (1, rel_dissector_path(ifile)))
3033                finc = open(ifile, "r")
3034                fout.write(finc.read())
3035                fout.write('\n')
3036                fout.write('/*--- End of included file: ' + ifile + ' ---*/\n')
3037                fout.write('#line %u "%s"\n' % (cont_linenum+1, rel_dissector_path(in_nm)) )
3038                finc.close()
3039            else:
3040                fout.write(line)
3041
3042        fout.close()
3043        fin.close()
3044
3045
3046#--- Node ---------------------------------------------------------------------
3047class Node:
3048    def __init__(self,*args, **kw):
3049        if len (args) == 0:
3050            self.type = self.__class__.__name__
3051        else:
3052            assert (len(args) == 1)
3053            self.type = args[0]
3054        self.__dict__.update (kw)
3055    def str_child (self, key, child, depth):
3056        indent = " " * (2 * depth)
3057        keystr = indent + key + ": "
3058        if key == 'type': # already processed in str_depth
3059            return ""
3060        if isinstance (child, Node): # ugh
3061            return keystr + "\n" + child.str_depth (depth+1)
3062        if isinstance(child, type ([])):
3063            l = []
3064            for x in child:
3065                if isinstance (x, Node):
3066                    l.append (x.str_depth (depth+1))
3067                else:
3068                    l.append (indent + "  " + str(x) + "\n")
3069            return keystr + "[\n" + ''.join(l) + indent + "]\n"
3070        else:
3071            return keystr + str (child) + "\n"
3072    def str_depth (self, depth): # ugh
3073        indent = " " * (2 * depth)
3074        l = ["%s%s" % (indent, self.type)]
3075        l.append ("".join ([self.str_child (k_v[0], k_v[1], depth + 1) for k_v in list(self.__dict__.items ())]))
3076        return "\n".join (l)
3077    def __repr__(self):
3078        return "\n" + self.str_depth (0)
3079    def to_python (self, ctx):
3080        return self.str_depth (ctx.indent_lev)
3081
3082    def eth_reg(self, ident, ectx):
3083        pass
3084
3085    def fld_obj_repr(self, ectx):
3086        return "/* TO DO %s */" % (str(self))
3087
3088
3089#--- ValueAssignment -------------------------------------------------------------
3090class ValueAssignment (Node):
3091    def __init__(self,*args, **kw) :
3092        Node.__init__ (self,*args, **kw)
3093
3094    def eth_reg(self, ident, ectx):
3095        if ectx.conform.omit_assignment('V', self.ident, ectx.Module()): return # Assignment to omit
3096        ectx.eth_reg_vassign(self)
3097        ectx.eth_reg_value(self.ident, self.typ, self.val)
3098
3099#--- ObjectAssignment -------------------------------------------------------------
3100class ObjectAssignment (Node):
3101    def __init__(self,*args, **kw) :
3102        Node.__init__ (self,*args, **kw)
3103
3104    def __eq__(self, other):
3105        if self.cls != other.cls:
3106            return False
3107        if len(self.val) != len(other.val):
3108            return False
3109        for f in (list(self.val.keys())):
3110            if f not in other.val:
3111                return False
3112            if isinstance(self.val[f], Node) and isinstance(other.val[f], Node):
3113                if not self.val[f].fld_obj_eq(other.val[f]):
3114                    return False
3115            else:
3116                if str(self.val[f]) != str(other.val[f]):
3117                    return False
3118        return True
3119
3120    def eth_reg(self, ident, ectx):
3121        def make_virtual_type(cls, field, prefix):
3122            if isinstance(self.val, str): return
3123            if field in self.val and not isinstance(self.val[field], Type_Ref):
3124                vnm = prefix + '-' + self.ident
3125                virtual_tr = Type_Ref(val = vnm)
3126                t = self.val[field]
3127                self.val[field] = virtual_tr
3128                ectx.eth_reg_assign(vnm, t, virt=True)
3129                ectx.eth_reg_type(vnm, t)
3130                t.eth_reg_sub(vnm, ectx)
3131            if field in self.val and ectx.conform.check_item('PDU', cls + '.' + field):
3132                ectx.eth_reg_field(self.val[field].val, self.val[field].val, impl=self.val[field].HasImplicitTag(ectx), pdu=ectx.conform.use_item('PDU', cls + '.' + field))
3133            return
3134        # end of make_virtual_type()
3135        if ectx.conform.omit_assignment('V', self.ident, ectx.Module()): return # Assignment to omit
3136        self.module = ectx.Module()
3137        ectx.eth_reg_oassign(self)
3138        if (self.cls == 'TYPE-IDENTIFIER') or (self.cls == 'ABSTRACT-SYNTAX'):
3139            make_virtual_type(self.cls, '&Type', 'TYPE')
3140        if (self.cls == 'OPERATION'):
3141            make_virtual_type(self.cls, '&ArgumentType', 'ARG')
3142            make_virtual_type(self.cls, '&ResultType', 'RES')
3143        if (self.cls == 'ERROR'):
3144            make_virtual_type(self.cls, '&ParameterType', 'PAR')
3145
3146
3147#--- Type ---------------------------------------------------------------------
3148class Type (Node):
3149    def __init__(self,*args, **kw) :
3150        self.name = None
3151        self.constr = None
3152        self.tags = []
3153        self.named_list = None
3154        Node.__init__ (self,*args, **kw)
3155
3156    def IsNamed(self):
3157        if self.name is None :
3158            return False
3159        else:
3160            return True
3161
3162    def HasConstraint(self):
3163        if self.constr is None :
3164            return False
3165        else :
3166            return True
3167
3168    def HasSizeConstraint(self):
3169        return self.HasConstraint() and self.constr.IsSize()
3170
3171    def HasValueConstraint(self):
3172        return self.HasConstraint() and self.constr.IsValue()
3173
3174    def HasPermAlph(self):
3175        return self.HasConstraint() and self.constr.IsPermAlph()
3176
3177    def HasContentsConstraint(self):
3178        return self.HasConstraint() and self.constr.IsContents()
3179
3180    def HasOwnTag(self):
3181        return len(self.tags) > 0
3182
3183    def HasImplicitTag(self, ectx):
3184        return (self.HasOwnTag() and self.tags[0].IsImplicit(ectx))
3185
3186    def IndetermTag(self, ectx):
3187        return False
3188
3189    def AddTag(self, tag):
3190        self.tags[0:0] = [tag]
3191
3192    def GetTag(self, ectx):
3193        #print "GetTag(%s)\n" % self.name;
3194        if (self.HasOwnTag()):
3195            return self.tags[0].GetTag(ectx)
3196        else:
3197            return self.GetTTag(ectx)
3198
3199    def GetTTag(self, ectx):
3200        print("#Unhandled  GetTTag() in %s" % (self.type))
3201        print(self.str_depth(1))
3202        return ('BER_CLASS_unknown', 'TAG_unknown')
3203
3204    def SetName(self, name):
3205        self.name = name
3206
3207    def AddConstraint(self, constr):
3208        if not self.HasConstraint():
3209            self.constr = constr
3210        else:
3211            self.constr = Constraint(type = 'Intersection', subtype = [self.constr, constr])
3212
3213    def eth_tname(self):
3214        return '#' + self.type + '_' + str(id(self))
3215
3216    def eth_ftype(self, ectx):
3217        return ('FT_NONE', 'BASE_NONE')
3218
3219    def eth_strings(self):
3220        return 'NULL'
3221
3222    def eth_omit_field(self):
3223        return False
3224
3225    def eth_need_tree(self):
3226        return False
3227
3228    def eth_has_vals(self):
3229        return False
3230
3231    def eth_has_enum(self, tname, ectx):
3232        return self.eth_has_vals() and (ectx.eth_type[tname]['enum'] & EF_ENUM)
3233
3234    def eth_need_pdu(self, ectx):
3235        return None
3236
3237    def eth_named_bits(self):
3238        return None
3239
3240    def eth_reg_sub(self, ident, ectx):
3241        pass
3242
3243    def get_components(self, ectx):
3244        print("#Unhandled  get_components() in %s" % (self.type))
3245        print(self.str_depth(1))
3246        return []
3247
3248    def sel_req(self, sel, ectx):
3249        print("#Selection '%s' required for non-CHOICE type %s" % (sel, self.type))
3250        print(self.str_depth(1))
3251
3252    def fld_obj_eq(self, other):
3253        return isinstance(other, Type) and (self.eth_tname() == other.eth_tname())
3254
3255    def eth_reg(self, ident, ectx, tstrip=0, tagflag=False, selflag=False, idx='', parent=None):
3256        #print "eth_reg(): %s, ident=%s, tstrip=%d, tagflag=%s, selflag=%s, parent=%s" %(self.type, ident, tstrip, str(tagflag), str(selflag), str(parent))
3257        #print " ", self
3258        if (ectx.NeedTags() and (len(self.tags) > tstrip)):
3259            tagged_type = self
3260            for i in range(len(self.tags)-1, tstrip-1, -1):
3261                tagged_type = TaggedType(val=tagged_type, tstrip=i)
3262                tagged_type.AddTag(self.tags[i])
3263            if not tagflag:  # 1st tagged level
3264                if self.IsNamed() and not selflag:
3265                    tagged_type.SetName(self.name)
3266            tagged_type.eth_reg(ident, ectx, tstrip=1, tagflag=tagflag, idx=idx, parent=parent)
3267            return
3268        nm = ''
3269        if ident and self.IsNamed() and not tagflag and not selflag:
3270            nm = ident + '/' + self.name
3271        elif ident:
3272            nm = ident
3273        elif self.IsNamed():
3274            nm = self.name
3275        if not ident and ectx.conform.omit_assignment('T', nm, ectx.Module()): return # Assignment to omit
3276        if not ident:  # Assignment
3277            ectx.eth_reg_assign(nm, self)
3278            if self.type == 'Type_Ref' and not self.tr_need_own_fn(ectx):
3279                ectx.eth_reg_type(nm, self)
3280        virtual_tr = Type_Ref(val=ectx.conform.use_item('SET_TYPE', nm))
3281        if (self.type == 'Type_Ref') or ectx.conform.check_item('SET_TYPE', nm):
3282            if ident and (ectx.conform.check_item('TYPE_RENAME', nm) or ectx.conform.get_fn_presence(nm) or selflag):
3283                if ectx.conform.check_item('SET_TYPE', nm):
3284                    ectx.eth_reg_type(nm, virtual_tr)  # dummy Type Reference
3285                else:
3286                    ectx.eth_reg_type(nm, self)  # new type
3287                trnm = nm
3288            elif ectx.conform.check_item('SET_TYPE', nm):
3289                trnm = ectx.conform.use_item('SET_TYPE', nm)
3290            elif (self.type == 'Type_Ref') and self.tr_need_own_fn(ectx):
3291                ectx.eth_reg_type(nm, self)  # need own function, e.g. for constraints
3292                trnm = nm
3293            else:
3294                trnm = self.val
3295        else:
3296            ectx.eth_reg_type(nm, self, mod = ectx.Module())
3297            trnm = nm
3298        if ectx.conform.check_item('VIRTUAL_ASSGN', nm):
3299            vnm = ectx.conform.use_item('VIRTUAL_ASSGN', nm)
3300            ectx.eth_reg_assign(vnm, self, virt=True)
3301            ectx.eth_reg_type(vnm, self)
3302            self.eth_reg_sub(vnm, ectx)
3303        if parent and (ectx.type[parent]['val'].type == 'TaggedType'):
3304            ectx.type[parent]['val'].eth_set_val_name(parent, trnm, ectx)
3305        if ident and not tagflag and not self.eth_omit_field():
3306            ectx.eth_reg_field(nm, trnm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx))
3307        if ectx.conform.check_item('SET_TYPE', nm):
3308            virtual_tr.eth_reg_sub(nm, ectx)
3309        else:
3310            self.eth_reg_sub(nm, ectx)
3311
3312    def eth_get_size_constr(self, ectx):
3313        (minv, maxv, ext) = ('MIN', 'MAX', False)
3314        if self.HasSizeConstraint():
3315            if self.constr.IsSize():
3316                (minv, maxv, ext) = self.constr.GetSize(ectx)
3317            if (self.constr.type == 'Intersection'):
3318                if self.constr.subtype[0].IsSize():
3319                    (minv, maxv, ext) = self.constr.subtype[0].GetSize(ectx)
3320                elif self.constr.subtype[1].IsSize():
3321                    (minv, maxv, ext) = self.constr.subtype[1].GetSize(ectx)
3322        if minv == 'MIN': minv = 'NO_BOUND'
3323        if maxv == 'MAX': maxv = 'NO_BOUND'
3324        if (ext): ext = 'TRUE'
3325        else: ext = 'FALSE'
3326        return (minv, maxv, ext)
3327
3328    def eth_get_value_constr(self, ectx):
3329        (minv, maxv, ext) = ('MIN', 'MAX', False)
3330        if self.HasValueConstraint():
3331            (minv, maxv, ext) = self.constr.GetValue(ectx)
3332        if minv == 'MIN': minv = 'NO_BOUND'
3333        if maxv == 'MAX': maxv = 'NO_BOUND'
3334        if str(minv).isdigit():
3335            minv += 'U'
3336        elif (str(minv)[0] == "-") and str(minv)[1:].isdigit():
3337            if (int(minv) == -(2**31)):
3338                minv = "G_MININT32"
3339            elif (int(minv) < -(2**31)):
3340                minv = "G_GINT64_CONSTANT(%s)" % (str(minv))
3341        if str(maxv).isdigit():
3342            if (int(maxv) >= 2**32):
3343                maxv = "G_GUINT64_CONSTANT(%s)" % (str(maxv))
3344            else:
3345                maxv += 'U'
3346        if (ext): ext = 'TRUE'
3347        else: ext = 'FALSE'
3348        return (minv, maxv, ext)
3349
3350    def eth_get_alphabet_constr(self, ectx):
3351        (alph, alphlen) = ('NULL', '0')
3352        if self.HasPermAlph():
3353            alph = self.constr.GetPermAlph(ectx)
3354            if not alph:
3355                alph = 'NULL'
3356            if (alph != 'NULL'):
3357                if (((alph[0] + alph[-1]) == '""') and (not alph.count('"', 1, -1))):
3358                    alphlen = str(len(alph) - 2)
3359                else:
3360                    alphlen = 'strlen(%s)' % (alph)
3361        return (alph, alphlen)
3362
3363    def eth_type_vals(self, tname, ectx):
3364        if self.eth_has_vals():
3365            print("#Unhandled  eth_type_vals('%s') in %s" % (tname, self.type))
3366            print(self.str_depth(1))
3367        return ''
3368
3369    def eth_type_enum(self, tname, ectx):
3370        if self.eth_has_enum(tname, ectx):
3371            print("#Unhandled  eth_type_enum('%s') in %s" % (tname, self.type))
3372            print(self.str_depth(1))
3373        return ''
3374
3375    def eth_type_default_table(self, ectx, tname):
3376        return ''
3377
3378    def eth_type_default_body(self, ectx):
3379        print("#Unhandled  eth_type_default_body() in %s" % (self.type))
3380        print(self.str_depth(1))
3381        return ''
3382
3383    def eth_type_default_pars(self, ectx, tname):
3384        pars = {
3385          'TNAME' : tname,
3386          'ER' : ectx.encp(),
3387          'FN_VARIANT' : '',
3388          'TREE' : 'tree',
3389          'TVB' : 'tvb',
3390          'OFFSET' : 'offset',
3391          'ACTX' : 'actx',
3392          'HF_INDEX' : 'hf_index',
3393          'VAL_PTR' : 'NULL',
3394          'IMPLICIT_TAG' : 'implicit_tag',
3395        }
3396        if (ectx.eth_type[tname]['tree']):
3397            pars['ETT_INDEX'] = ectx.eth_type[tname]['tree']
3398        if (ectx.merge_modules):
3399            pars['PROTOP'] = ''
3400        else:
3401            pars['PROTOP'] = ectx.eth_type[tname]['proto'] + '_'
3402        return pars
3403
3404    def eth_type_fn(self, proto, tname, ectx):
3405        body = self.eth_type_default_body(ectx, tname)
3406        pars = self.eth_type_default_pars(ectx, tname)
3407        if ectx.conform.check_item('FN_PARS', tname):
3408            pars.update(ectx.conform.use_item('FN_PARS', tname))
3409        elif ectx.conform.check_item('FN_PARS', ectx.eth_type[tname]['ref'][0]):
3410            pars.update(ectx.conform.use_item('FN_PARS', ectx.eth_type[tname]['ref'][0]))
3411        pars['DEFAULT_BODY'] = body
3412        for i in range(4):
3413            for k in list(pars.keys()):
3414                try:
3415                    pars[k] = pars[k] % pars
3416                except (ValueError,TypeError):
3417                    raise sys.exc_info()[0]("%s\n%s" % (str(pars), sys.exc_info()[1]))
3418        out = '\n'
3419        out += self.eth_type_default_table(ectx, tname) % pars
3420        out += ectx.eth_type_fn_hdr(tname)
3421        out += ectx.eth_type_fn_body(tname, body, pars=pars)
3422        out += ectx.eth_type_fn_ftr(tname)
3423        return out
3424
3425#--- Value --------------------------------------------------------------------
3426class Value (Node):
3427    def __init__(self,*args, **kw) :
3428        self.name = None
3429        Node.__init__ (self,*args, **kw)
3430
3431    def SetName(self, name) :
3432        self.name = name
3433
3434    def to_str(self, ectx):
3435        return str(self.val)
3436
3437    def get_dep(self):
3438        return None
3439
3440    def fld_obj_repr(self, ectx):
3441        return self.to_str(ectx)
3442
3443#--- Value_Ref -----------------------------------------------------------------
3444class Value_Ref (Value):
3445    def to_str(self, ectx):
3446        return asn2c(self.val)
3447
3448#--- ObjectClass ---------------------------------------------------------------------
3449class ObjectClass (Node):
3450    def __init__(self,*args, **kw) :
3451        self.name = None
3452        Node.__init__ (self,*args, **kw)
3453
3454    def SetName(self, name):
3455        self.name = name
3456        add_class_ident(self.name)
3457
3458    def eth_reg(self, ident, ectx):
3459        if ectx.conform.omit_assignment('C', self.name, ectx.Module()): return # Assignment to omit
3460        ectx.eth_reg_objectclass(self.name, self)
3461
3462#--- Class_Ref -----------------------------------------------------------------
3463class Class_Ref (ObjectClass):
3464    pass
3465
3466#--- ObjectClassDefn ---------------------------------------------------------------------
3467class ObjectClassDefn (ObjectClass):
3468    def reg_types(self):
3469        for fld in self.fields:
3470            repr = fld.fld_repr()
3471            set_type_to_class(self.name, repr[0], repr[1:])
3472
3473
3474#--- Tag ---------------------------------------------------------------
3475class Tag (Node):
3476    def to_python (self, ctx):
3477        return 'asn1.TYPE(%s,%s)' % (mk_tag_str (ctx, self.tag.cls,
3478                                                    self.tag_typ,
3479                                                    self.tag.num),
3480                                        self.typ.to_python (ctx))
3481    def IsImplicit(self, ectx):
3482        return ((self.mode == 'IMPLICIT') or ((self.mode == 'default') and (ectx.tag_def != 'EXPLICIT')))
3483
3484    def GetTag(self, ectx):
3485        tc = ''
3486        if (self.cls == 'UNIVERSAL'): tc = 'BER_CLASS_UNI'
3487        elif (self.cls == 'APPLICATION'): tc = 'BER_CLASS_APP'
3488        elif (self.cls == 'CONTEXT'): tc = 'BER_CLASS_CON'
3489        elif (self.cls == 'PRIVATE'): tc = 'BER_CLASS_PRI'
3490        return (tc, self.num)
3491
3492    def eth_tname(self):
3493        n = ''
3494        if (self.cls == 'UNIVERSAL'): n = 'U'
3495        elif (self.cls == 'APPLICATION'): n = 'A'
3496        elif (self.cls == 'CONTEXT'): n = 'C'
3497        elif (self.cls == 'PRIVATE'): n = 'P'
3498        return n + str(self.num)
3499
3500#--- Constraint ---------------------------------------------------------------
3501constr_cnt = 0
3502class Constraint (Node):
3503    def to_python (self, ctx):
3504        print("Ignoring constraint:", self.type)
3505        return self.subtype.typ.to_python (ctx)
3506    def __str__ (self):
3507        return "Constraint: type=%s, subtype=%s" % (self.type, self.subtype)
3508
3509    def eth_tname(self):
3510        return '#' + self.type + '_' + str(id(self))
3511
3512    def IsSize(self):
3513        return (self.type == 'Size' and self.subtype.IsValue()) \
3514               or (self.type == 'Intersection' and (self.subtype[0].IsSize() or self.subtype[1].IsSize())) \
3515
3516    def GetSize(self, ectx):
3517        (minv, maxv, ext) = ('MIN', 'MAX', False)
3518        if self.IsSize():
3519            if self.type == 'Size':
3520                (minv, maxv, ext) = self.subtype.GetValue(ectx)
3521                ext = ext or (hasattr(self, 'ext') and self.ext)
3522            elif self.type == 'Intersection':
3523                if self.subtype[0].IsSize() and not self.subtype[1].IsSize():
3524                    (minv, maxv, ext) = self.subtype[0].GetSize(ectx)
3525                elif not self.subtype[0].IsSize() and self.subtype[1].IsSize():
3526                    (minv, maxv, ext) = self.subtype[1].GetSize(ectx)
3527        return (minv, maxv, ext)
3528
3529    def IsValue(self):
3530        return self.type == 'SingleValue' \
3531               or self.type == 'ValueRange' \
3532               or (self.type == 'Intersection' and (self.subtype[0].IsValue() or self.subtype[1].IsValue())) \
3533               or (self.type == 'Union' and (self.subtype[0].IsValue() and self.subtype[1].IsValue()))
3534
3535    def GetValue(self, ectx):
3536        (minv, maxv, ext) = ('MIN', 'MAX', False)
3537        if self.IsValue():
3538            if self.type == 'SingleValue':
3539                minv = ectx.value_get_eth(self.subtype)
3540                maxv = ectx.value_get_eth(self.subtype)
3541                ext = hasattr(self, 'ext') and self.ext
3542            elif self.type == 'ValueRange':
3543                minv = ectx.value_get_eth(self.subtype[0])
3544                maxv = ectx.value_get_eth(self.subtype[1])
3545                ext = hasattr(self, 'ext') and self.ext
3546            elif self.type == 'Intersection':
3547                if self.subtype[0].IsValue() and not self.subtype[1].IsValue():
3548                    (minv, maxv, ext) = self.subtype[0].GetValue(ectx)
3549                elif not self.subtype[0].IsValue() and self.subtype[1].IsValue():
3550                    (minv, maxv, ext) = self.subtype[1].GetValue(ectx)
3551                elif self.subtype[0].IsValue() and self.subtype[1].IsValue():
3552                    v0 = self.subtype[0].GetValue(ectx)
3553                    v1 = self.subtype[1].GetValue(ectx)
3554                    (minv, maxv, ext) = (ectx.value_max(v0[0],v1[0]), ectx.value_min(v0[1],v1[1]), v0[2] and v1[2])
3555            elif self.type == 'Union':
3556                if self.subtype[0].IsValue() and self.subtype[1].IsValue():
3557                    v0 = self.subtype[0].GetValue(ectx)
3558                    v1 = self.subtype[1].GetValue(ectx)
3559                    (minv, maxv, ext) = (ectx.value_min(v0[0],v1[0]), ectx.value_max(v0[1],v1[1]), hasattr(self, 'ext') and self.ext)
3560        return (minv, maxv, ext)
3561
3562    def IsAlphabet(self):
3563        return self.type == 'SingleValue' \
3564               or self.type == 'ValueRange' \
3565               or (self.type == 'Intersection' and (self.subtype[0].IsAlphabet() or self.subtype[1].IsAlphabet())) \
3566               or (self.type == 'Union' and (self.subtype[0].IsAlphabet() and self.subtype[1].IsAlphabet()))
3567
3568    def GetAlphabet(self, ectx):
3569        alph = None
3570        if self.IsAlphabet():
3571            if self.type == 'SingleValue':
3572                alph = ectx.value_get_eth(self.subtype)
3573            elif self.type == 'ValueRange':
3574                if ((len(self.subtype[0]) == 3) and ((self.subtype[0][0] + self.subtype[0][-1]) == '""') \
3575                    and (len(self.subtype[1]) == 3) and ((self.subtype[1][0] + self.subtype[1][-1]) == '""')):
3576                    alph = '"'
3577                    for c in range(ord(self.subtype[0][1]), ord(self.subtype[1][1]) + 1):
3578                        alph += chr(c)
3579                    alph += '"'
3580            elif self.type == 'Union':
3581                if self.subtype[0].IsAlphabet() and self.subtype[1].IsAlphabet():
3582                    a0 = self.subtype[0].GetAlphabet(ectx)
3583                    a1 = self.subtype[1].GetAlphabet(ectx)
3584                    if (((a0[0] + a0[-1]) == '""') and not a0.count('"', 1, -1) \
3585                        and ((a1[0] + a1[-1]) == '""') and not a1.count('"', 1, -1)):
3586                        alph = '"' + a0[1:-1] + a1[1:-1] + '"'
3587                    else:
3588                        alph = a0 + ' ' + a1
3589        return alph
3590
3591    def IsPermAlph(self):
3592        return self.type == 'From' and self.subtype.IsAlphabet() \
3593               or (self.type == 'Intersection' and (self.subtype[0].IsPermAlph() or self.subtype[1].IsPermAlph())) \
3594
3595    def GetPermAlph(self, ectx):
3596        alph = None
3597        if self.IsPermAlph():
3598            if self.type == 'From':
3599                alph = self.subtype.GetAlphabet(ectx)
3600            elif self.type == 'Intersection':
3601                if self.subtype[0].IsPermAlph() and not self.subtype[1].IsPermAlph():
3602                    alph = self.subtype[0].GetPermAlph(ectx)
3603                elif not self.subtype[0].IsPermAlph() and self.subtype[1].IsPermAlph():
3604                    alph = self.subtype[1].GetPermAlph(ectx)
3605        return alph
3606
3607    def IsContents(self):
3608        return self.type == 'Contents' \
3609               or (self.type == 'Intersection' and (self.subtype[0].IsContents() or self.subtype[1].IsContents())) \
3610
3611    def GetContents(self, ectx):
3612        contents = None
3613        if self.IsContents():
3614            if self.type == 'Contents':
3615                if self.subtype.type == 'Type_Ref':
3616                    contents = self.subtype.val
3617            elif self.type == 'Intersection':
3618                if self.subtype[0].IsContents() and not self.subtype[1].IsContents():
3619                    contents = self.subtype[0].GetContents(ectx)
3620                elif not self.subtype[0].IsContents() and self.subtype[1].IsContents():
3621                    contents = self.subtype[1].GetContents(ectx)
3622        return contents
3623
3624    def IsNegativ(self):
3625        def is_neg(sval):
3626            return isinstance(sval, str) and (sval[0] == '-')
3627        if self.type == 'SingleValue':
3628            return is_neg(self.subtype)
3629        elif self.type == 'ValueRange':
3630            if self.subtype[0] == 'MIN': return True
3631            return is_neg(self.subtype[0])
3632        return False
3633
3634    def eth_constrname(self):
3635        def int2str(val):
3636            if isinstance(val, Value_Ref):
3637                return asn2c(val.val)
3638            try:
3639                if (int(val) < 0):
3640                    return 'M' + str(-int(val))
3641                else:
3642                    return str(int(val))
3643            except (ValueError, TypeError):
3644                return asn2c(str(val))
3645
3646        ext = ''
3647        if hasattr(self, 'ext') and self.ext:
3648            ext = '_'
3649        if self.type == 'SingleValue':
3650            return int2str(self.subtype) + ext
3651        elif self.type == 'ValueRange':
3652            return int2str(self.subtype[0]) + '_' + int2str(self.subtype[1]) + ext
3653        elif self.type == 'Size':
3654            return 'SIZE_' + self.subtype.eth_constrname() + ext
3655        else:
3656            if (not hasattr(self, 'constr_num')):
3657                global constr_cnt
3658                constr_cnt += 1
3659                self.constr_num = constr_cnt
3660            return 'CONSTR%03d%s' % (self.constr_num, ext)
3661
3662    def Needs64b(self, ectx):
3663        (minv, maxv, ext) = self.GetValue(ectx)
3664        if ((str(minv).isdigit() or ((str(minv)[0] == "-") and str(minv)[1:].isdigit())) \
3665        and str(maxv).isdigit() and (abs(int(maxv) - int(minv)) >= 2**32)) \
3666        or (maxv == 'MAX') or (minv == 'MIN'):
3667            return True
3668        return False
3669
3670class Module (Node):
3671    def to_python (self, ctx):
3672        ctx.tag_def = self.tag_def.dfl_tag
3673        return """#%s
3674    %s""" % (self.ident, self.body.to_python (ctx))
3675
3676    def get_name(self):
3677        return self.ident.val
3678
3679    def get_proto(self, ectx):
3680        if (ectx.proto):
3681            prot = ectx.proto
3682        else:
3683            prot = ectx.conform.use_item('MODULE', self.get_name(), val_dflt=self.get_name())
3684        return prot
3685
3686    def to_eth(self, ectx):
3687        ectx.tags_def = 'EXPLICIT' # default = explicit
3688        ectx.proto = self.get_proto(ectx)
3689        ectx.tag_def = self.tag_def.dfl_tag
3690        ectx.eth_reg_module(self)
3691        self.body.to_eth(ectx)
3692
3693class Module_Body (Node):
3694    def to_python (self, ctx):
3695        # XXX handle exports, imports.
3696        l = [x.to_python (ctx) for x in self.assign_list]
3697        l = [a for a in l if a != '']
3698        return "\n".join (l)
3699
3700    def to_eth(self, ectx):
3701        # Exports
3702        ectx.eth_exports(self.exports)
3703        # Imports
3704        for i in self.imports:
3705            mod = i.module.val
3706            proto = ectx.conform.use_item('MODULE', mod, val_dflt=mod)
3707            ectx.eth_module_dep_add(ectx.Module(), mod)
3708            for s in i.symbol_list:
3709                if isinstance(s, Type_Ref):
3710                    ectx.eth_import_type(s.val, mod, proto)
3711                elif isinstance(s, Value_Ref):
3712                    ectx.eth_import_value(s.val, mod, proto)
3713                elif isinstance(s, Class_Ref):
3714                    ectx.eth_import_class(s.val, mod, proto)
3715                else:
3716                    msg = 'Unknown kind of imported symbol %s from %s' % (str(s), mod)
3717                    warnings.warn_explicit(msg, UserWarning, '', 0)
3718        # AssignmentList
3719        for a in self.assign_list:
3720            a.eth_reg('', ectx)
3721
3722class Default_Tags (Node):
3723    def to_python (self, ctx): # not to be used directly
3724        assert (0)
3725
3726# XXX should just calculate dependencies as we go along.
3727def calc_dependencies (node, dict, trace = 0):
3728    if not hasattr (node, '__dict__'):
3729        if trace: print("#returning, node=", node)
3730        return
3731    if isinstance (node, Type_Ref):
3732        dict [node.val] = 1
3733        if trace: print("#Setting", node.val)
3734        return
3735    for (a, val) in list(node.__dict__.items ()):
3736        if trace: print("# Testing node ", node, "attr", a, " val", val)
3737        if a[0] == '_':
3738            continue
3739        elif isinstance (val, Node):
3740            calc_dependencies (val, dict, trace)
3741        elif isinstance (val, type ([])):
3742            for v in val:
3743                calc_dependencies (v, dict, trace)
3744
3745
3746class Type_Assign (Node):
3747    def __init__ (self, *args, **kw):
3748        Node.__init__ (self, *args, **kw)
3749        if isinstance (self.val, Tag): # XXX replace with generalized get_typ_ignoring_tag (no-op for Node, override in Tag)
3750            to_test = self.val.typ
3751        else:
3752            to_test = self.val
3753        if isinstance (to_test, SequenceType):
3754            to_test.sequence_name = self.name.name
3755
3756    def to_python (self, ctx):
3757        dep_dict = {}
3758        calc_dependencies (self.val, dep_dict, 0)
3759        depend_list = list(dep_dict.keys ())
3760        return ctx.register_assignment (self.name.name,
3761                                        self.val.to_python (ctx),
3762                                        depend_list)
3763
3764class PyQuote (Node):
3765    def to_python (self, ctx):
3766        return ctx.register_pyquote (self.val)
3767
3768#--- Type_Ref -----------------------------------------------------------------
3769class Type_Ref (Type):
3770    def to_python (self, ctx):
3771        return self.val
3772
3773    def eth_reg_sub(self, ident, ectx):
3774        ectx.eth_dep_add(ident, self.val)
3775
3776    def eth_tname(self):
3777        if self.HasSizeConstraint():
3778            return asn2c(self.val) + '_' + self.constr.eth_constrname()
3779        else:
3780            return asn2c(self.val)
3781
3782    def tr_need_own_fn(self, ectx):
3783        return (ectx.Per() or ectx.Oer()) and self.HasSizeConstraint()
3784
3785    def fld_obj_repr(self, ectx):
3786        return self.val
3787
3788    def get_components(self, ectx):
3789        if self.val not in ectx.type or ectx.type[self.val]['import']:
3790            msg = "Can not get COMPONENTS OF %s which is imported type" % (self.val)
3791            warnings.warn_explicit(msg, UserWarning, '', 0)
3792            return []
3793        else:
3794            return ectx.type[self.val]['val'].get_components(ectx)
3795
3796    def GetTTag(self, ectx):
3797        #print "GetTTag(%s)\n" % self.val;
3798        if (ectx.type[self.val]['import']):
3799            if 'ttag' not in ectx.type[self.val]:
3800                ttag = ectx.get_ttag_from_all(self.val, ectx.type[self.val]['import'])
3801                if not ttag and not ectx.conform.check_item('IMPORT_TAG', self.val):
3802                    msg = 'Missing tag information for imported type %s from %s (%s)' % (self.val, ectx.type[self.val]['import'], ectx.type[self.val]['proto'])
3803                    warnings.warn_explicit(msg, UserWarning, '', 0)
3804                    ttag = ('-1/*imported*/', '-1/*imported*/')
3805                ectx.type[self.val]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.val, val_dflt=ttag)
3806            return ectx.type[self.val]['ttag']
3807        else:
3808            return ectx.type[self.val]['val'].GetTag(ectx)
3809
3810    def IndetermTag(self, ectx):
3811        if (ectx.type[self.val]['import']):
3812            return False
3813        else:
3814            return ectx.type[self.val]['val'].IndetermTag(ectx)
3815
3816    def eth_type_default_pars(self, ectx, tname):
3817        if tname:
3818            pars = Type.eth_type_default_pars(self, ectx, tname)
3819        else:
3820            pars = {}
3821        t = ectx.type[self.val]['ethname']
3822        pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
3823        pars['TYPE_REF_TNAME'] = t
3824        pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
3825        if self.HasSizeConstraint():
3826            (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
3827        return pars
3828
3829    def eth_type_default_body(self, ectx, tname):
3830        if (ectx.Ber()):
3831            body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
3832                                    par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
3833        elif (ectx.Per() or ectx.Oer()):
3834            if self.HasSizeConstraint():
3835                body = ectx.eth_fn_call('dissect_%(ER)s_size_constrained_type', ret='offset',
3836                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),
3837                                             ('"%(TYPE_REF_TNAME)s"', '%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),))
3838            else:
3839                body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
3840                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
3841        else:
3842            body = '#error Can not decode %s' % (tname)
3843        return body
3844
3845#--- SelectionType ------------------------------------------------------------
3846class SelectionType (Type):
3847    def to_python (self, ctx):
3848        return self.val
3849
3850    def sel_of_typeref(self):
3851        return self.typ.type == 'Type_Ref'
3852
3853    def eth_reg_sub(self, ident, ectx):
3854        if not self.sel_of_typeref():
3855            self.seltype = ''
3856            return
3857        self.seltype = ectx.eth_sel_req(self.typ.val, self.sel)
3858        ectx.eth_dep_add(ident, self.seltype)
3859
3860    def eth_ftype(self, ectx):
3861        (ftype, display) = ('FT_NONE', 'BASE_NONE')
3862        if self.sel_of_typeref() and not ectx.type[self.seltype]['import']:
3863            (ftype, display) = ectx.type[self.typ.val]['val'].eth_ftype_sel(self.sel, ectx)
3864        return (ftype, display)
3865
3866    def GetTTag(self, ectx):
3867        #print "GetTTag(%s)\n" % self.seltype;
3868        if (ectx.type[self.seltype]['import']):
3869            if 'ttag' not in ectx.type[self.seltype]:
3870                if not ectx.conform.check_item('IMPORT_TAG', self.seltype):
3871                    msg = 'Missing tag information for imported type %s from %s (%s)' % (self.seltype, ectx.type[self.seltype]['import'], ectx.type[self.seltype]['proto'])
3872                    warnings.warn_explicit(msg, UserWarning, '', 0)
3873                ectx.type[self.seltype]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.seltype, val_dflt=('-1 /*imported*/', '-1 /*imported*/'))
3874            return ectx.type[self.seltype]['ttag']
3875        else:
3876            return ectx.type[self.typ.val]['val'].GetTTagSel(self.sel, ectx)
3877
3878    def eth_type_default_pars(self, ectx, tname):
3879        pars = Type.eth_type_default_pars(self, ectx, tname)
3880        if self.sel_of_typeref():
3881            t = ectx.type[self.seltype]['ethname']
3882            pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
3883            pars['TYPE_REF_TNAME'] = t
3884            pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
3885        return pars
3886
3887    def eth_type_default_body(self, ectx, tname):
3888        if not self.sel_of_typeref():
3889            body = '#error Can not decode %s' % (tname)
3890        elif (ectx.Ber()):
3891            body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
3892                                    par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
3893        elif (ectx.Per() or ectx.Oer()):
3894            body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
3895                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
3896        else:
3897            body = '#error Can not decode %s' % (tname)
3898        return body
3899
3900#--- TaggedType -----------------------------------------------------------------
3901class TaggedType (Type):
3902    def eth_tname(self):
3903        tn = ''
3904        for i in range(self.tstrip, len(self.val.tags)):
3905            tn += self.val.tags[i].eth_tname()
3906            tn += '_'
3907        tn += self.val.eth_tname()
3908        return tn
3909
3910    def eth_set_val_name(self, ident, val_name, ectx):
3911        #print "TaggedType::eth_set_val_name(): ident=%s, val_name=%s" % (ident, val_name)
3912        self.val_name = val_name
3913        ectx.eth_dep_add(ident, self.val_name)
3914
3915    def eth_reg_sub(self, ident, ectx):
3916        self.val_name = ident + '/' + UNTAG_TYPE_NAME
3917        self.val.eth_reg(self.val_name, ectx, tstrip=self.tstrip+1, tagflag=True, parent=ident)
3918
3919    def GetTTag(self, ectx):
3920        #print "GetTTag(%s)\n" % self.seltype;
3921        return self.GetTag(ectx)
3922
3923    def eth_ftype(self, ectx):
3924        return self.val.eth_ftype(ectx)
3925
3926    def eth_type_default_pars(self, ectx, tname):
3927        pars = Type.eth_type_default_pars(self, ectx, tname)
3928        t = ectx.type[self.val_name]['ethname']
3929        pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
3930        pars['TYPE_REF_TNAME'] = t
3931        pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
3932        (pars['TAG_CLS'], pars['TAG_TAG']) = self.GetTag(ectx)
3933        if self.HasImplicitTag(ectx):
3934            pars['TAG_IMPL'] = 'TRUE'
3935        else:
3936            pars['TAG_IMPL'] = 'FALSE'
3937        return pars
3938
3939    def eth_type_default_body(self, ectx, tname):
3940        if (ectx.Ber()):
3941            body = ectx.eth_fn_call('dissect_%(ER)s_tagged_type', ret='offset',
3942                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
3943                                         ('%(HF_INDEX)s', '%(TAG_CLS)s', '%(TAG_TAG)s', '%(TAG_IMPL)s', '%(TYPE_REF_FN)s',),))
3944        else:
3945            body = '#error Can not decode %s' % (tname)
3946        return body
3947
3948#--- SqType -----------------------------------------------------------
3949class SqType (Type):
3950    def out_item(self, f, val, optional, ext, ectx):
3951        if (val.eth_omit_field()):
3952            t = ectx.type[val.ident]['ethname']
3953            fullname = ectx.dummy_eag_field
3954        else:
3955            ef = ectx.field[f]['ethname']
3956            t = ectx.eth_hf[ef]['ethtype']
3957            fullname = ectx.eth_hf[ef]['fullname']
3958        if (ectx.Ber()):
3959            #print "optional=%s, e.val.HasOwnTag()=%s, e.val.IndetermTag()=%s" % (str(e.optional), str(e.val.HasOwnTag()), str(e.val.IndetermTag(ectx)))
3960            #print val.str_depth(1)
3961            opt = ''
3962            if (optional):
3963                opt = 'BER_FLAGS_OPTIONAL'
3964            if (not val.HasOwnTag()):
3965                if (opt): opt += '|'
3966                opt += 'BER_FLAGS_NOOWNTAG'
3967            elif (val.HasImplicitTag(ectx)):
3968                if (opt): opt += '|'
3969                opt += 'BER_FLAGS_IMPLTAG'
3970            if (val.IndetermTag(ectx)):
3971                if (opt): opt += '|'
3972                opt += 'BER_FLAGS_NOTCHKTAG'
3973            if (not opt): opt = '0'
3974        else:
3975            if optional:
3976                opt = 'ASN1_OPTIONAL'
3977            else:
3978                opt = 'ASN1_NOT_OPTIONAL'
3979        if (ectx.Ber()):
3980            (tc, tn) = val.GetTag(ectx)
3981            out = '  { %-24s, %-13s, %s, %s, dissect_%s_%s },\n' \
3982                  % ('&'+fullname, tc, tn, opt, ectx.eth_type[t]['proto'], t)
3983        elif (ectx.Per() or ectx.Oer()):
3984            out = '  { %-24s, %-23s, %-17s, dissect_%s_%s },\n' \
3985                  % ('&'+fullname, ext, opt, ectx.eth_type[t]['proto'], t)
3986        else:
3987            out = ''
3988        return out
3989
3990#--- SeqType -----------------------------------------------------------
3991class SeqType (SqType):
3992
3993    def all_components(self):
3994        lst = self.elt_list[:]
3995        if hasattr(self, 'ext_list'):
3996            lst.extend(self.ext_list)
3997        if hasattr(self, 'elt_list2'):
3998            lst.extend(self.elt_list2)
3999        return lst
4000
4001    def need_components(self):
4002        lst = self.all_components()
4003        for e in (lst):
4004            if e.type == 'components_of':
4005                return True
4006        return False
4007
4008    def expand_components(self, ectx):
4009        while self.need_components():
4010            for i in range(len(self.elt_list)):
4011                if self.elt_list[i].type == 'components_of':
4012                    comp = self.elt_list[i].typ.get_components(ectx)
4013                    self.elt_list[i:i+1] = comp
4014                    break
4015            if hasattr(self, 'ext_list'):
4016                for i in range(len(self.ext_list)):
4017                    if self.ext_list[i].type == 'components_of':
4018                        comp = self.ext_list[i].typ.get_components(ectx)
4019                        self.ext_list[i:i+1] = comp
4020                        break
4021            if hasattr(self, 'elt_list2'):
4022                for i in range(len(self.elt_list2)):
4023                    if self.elt_list2[i].type == 'components_of':
4024                        comp = self.elt_list2[i].typ.get_components(ectx)
4025                        self.elt_list2[i:i+1] = comp
4026                        break
4027
4028    def get_components(self, ectx):
4029        lst = self.elt_list[:]
4030        if hasattr(self, 'elt_list2'):
4031            lst.extend(self.elt_list2)
4032        return lst
4033
4034    def eth_reg_sub(self, ident, ectx, components_available=False):
4035        # check if autotag is required
4036        autotag = False
4037        if (ectx.NeedTags() and (ectx.tag_def == 'AUTOMATIC')):
4038            autotag = True
4039            lst = self.all_components()
4040            for e in (self.elt_list):
4041                if e.val.HasOwnTag(): autotag = False; break;
4042        # expand COMPONENTS OF
4043        if self.need_components():
4044            if components_available:
4045                self.expand_components(ectx)
4046            else:
4047                ectx.eth_comp_req(ident)
4048                return
4049        # extension addition groups
4050        if hasattr(self, 'ext_list'):
4051            if (ectx.Per() or ectx.Oer()):  # add names
4052                eag_num = 1
4053                for e in (self.ext_list):
4054                    if isinstance(e.val, ExtensionAdditionGroup):
4055                        e.val.parent_ident = ident
4056                        e.val.parent_tname = ectx.type[ident]['tname']
4057                        if (e.val.ver):
4058                            e.val.SetName("eag_v%s" % (e.val.ver))
4059                        else:
4060                            e.val.SetName("eag_%d" % (eag_num))
4061                            eag_num += 1;
4062            else:  # expand
4063                new_ext_list = []
4064                for e in (self.ext_list):
4065                    if isinstance(e.val, ExtensionAdditionGroup):
4066                        new_ext_list.extend(e.val.elt_list)
4067                    else:
4068                        new_ext_list.append(e)
4069                self.ext_list = new_ext_list
4070        # do autotag
4071        if autotag:
4072            atag = 0
4073            for e in (self.elt_list):
4074                e.val.AddTag(Tag(cls = 'CONTEXT', num = str(atag), mode = 'IMPLICIT'))
4075                atag += 1
4076            if autotag and hasattr(self, 'elt_list2'):
4077                for e in (self.elt_list2):
4078                    e.val.AddTag(Tag(cls = 'CONTEXT', num = str(atag), mode = 'IMPLICIT'))
4079                    atag += 1
4080            if autotag and hasattr(self, 'ext_list'):
4081                for e in (self.ext_list):
4082                    e.val.AddTag(Tag(cls = 'CONTEXT', num = str(atag), mode = 'IMPLICIT'))
4083                    atag += 1
4084        # register components
4085        for e in (self.elt_list):
4086            e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
4087        if hasattr(self, 'ext_list'):
4088            for e in (self.ext_list):
4089                e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
4090        if hasattr(self, 'elt_list2'):
4091            for e in (self.elt_list2):
4092                e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
4093
4094    def eth_type_default_table(self, ectx, tname):
4095        #print ("eth_type_default_table(tname='%s')" % (tname))
4096        fname = ectx.eth_type[tname]['ref'][0]
4097        table = "static const %(ER)s_sequence_t %(TABLE)s[] = {\n"
4098        if hasattr(self, 'ext_list'):
4099            ext = 'ASN1_EXTENSION_ROOT'
4100        else:
4101            ext = 'ASN1_NO_EXTENSIONS'
4102        empty_ext_flag = '0'
4103        if (len(self.elt_list)==0) and hasattr(self, 'ext_list') and (len(self.ext_list)==0) and (not hasattr(self, 'elt_list2') or (len(self.elt_list2)==0)):
4104            empty_ext_flag = ext
4105        for e in (self.elt_list):
4106            f = fname + '/' + e.val.name
4107            table += self.out_item(f, e.val, e.optional, ext, ectx)
4108        if hasattr(self, 'ext_list'):
4109            for e in (self.ext_list):
4110                f = fname + '/' + e.val.name
4111                table += self.out_item(f, e.val, e.optional, 'ASN1_NOT_EXTENSION_ROOT', ectx)
4112        if hasattr(self, 'elt_list2'):
4113            for e in (self.elt_list2):
4114                f = fname + '/' + e.val.name
4115                table += self.out_item(f, e.val, e.optional, ext, ectx)
4116        if (ectx.Ber()):
4117            table += "  { NULL, 0, 0, 0, NULL }\n};\n"
4118        else:
4119            table += "  { NULL, %s, 0, NULL }\n};\n" % (empty_ext_flag)
4120        return table
4121
4122#--- SeqOfType -----------------------------------------------------------
4123class SeqOfType (SqType):
4124    def eth_type_default_table(self, ectx, tname):
4125        #print "eth_type_default_table(tname='%s')" % (tname)
4126        fname = ectx.eth_type[tname]['ref'][0]
4127        if self.val.IsNamed ():
4128            f = fname + '/' + self.val.name
4129        else:
4130            f = fname + '/' + ITEM_FIELD_NAME
4131        table = "static const %(ER)s_sequence_t %(TABLE)s[1] = {\n"
4132        table += self.out_item(f, self.val, False, 'ASN1_NO_EXTENSIONS', ectx)
4133        table += "};\n"
4134        return table
4135
4136#--- SequenceOfType -----------------------------------------------------------
4137class SequenceOfType (SeqOfType):
4138    def to_python (self, ctx):
4139        # name, tag (None for no tag, EXPLICIT() for explicit), typ)
4140        # or '' + (1,) for optional
4141        sizestr = ''
4142        if self.size_constr is not None:
4143            print("#Ignoring size constraint:", self.size_constr.subtype)
4144        return "%sasn1.SEQUENCE_OF (%s%s)" % (ctx.spaces (),
4145                                              self.val.to_python (ctx),
4146                                              sizestr)
4147
4148    def eth_reg_sub(self, ident, ectx):
4149        itmnm = ident
4150        if not self.val.IsNamed ():
4151            itmnm += '/' + ITEM_FIELD_NAME
4152        self.val.eth_reg(itmnm, ectx, tstrip=1, idx='[##]', parent=ident)
4153
4154    def eth_tname(self):
4155        if self.val.type != 'Type_Ref':
4156            return '#' + self.type + '_' + str(id(self))
4157        if not self.HasConstraint():
4158            return "SEQUENCE_OF_" + self.val.eth_tname()
4159        elif self.constr.IsSize():
4160            return 'SEQUENCE_' + self.constr.eth_constrname() + '_OF_' + self.val.eth_tname()
4161        else:
4162            return '#' + self.type + '_' + str(id(self))
4163
4164    def eth_ftype(self, ectx):
4165        return ('FT_UINT32', 'BASE_DEC')
4166
4167    def eth_need_tree(self):
4168        return True
4169
4170    def GetTTag(self, ectx):
4171        return ('BER_CLASS_UNI', 'BER_UNI_TAG_SEQUENCE')
4172
4173    def eth_type_default_pars(self, ectx, tname):
4174        pars = Type.eth_type_default_pars(self, ectx, tname)
4175        (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
4176        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_sequence_of'
4177        return pars
4178
4179    def eth_type_default_body(self, ectx, tname):
4180        if (ectx.Ber()):
4181            if (ectx.constraints_check and self.HasSizeConstraint()):
4182                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_sequence_of', ret='offset',
4183                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4184                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4185            else:
4186                body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset',
4187                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4188                                             ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4189        elif ((ectx.Per() or ectx.Oer()) and not self.HasConstraint()):
4190            body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset',
4191                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4192                                         ('%(ETT_INDEX)s', '%(TABLE)s',),))
4193        elif ((ectx.Per() or ectx.Oer()) and self.constr.type == 'Size'):
4194            body = ectx.eth_fn_call('dissect_%(ER)s_constrained_sequence_of', ret='offset',
4195                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4196                                         ('%(ETT_INDEX)s', '%(TABLE)s',),
4197                                         ('%(MIN_VAL)s', '%(MAX_VAL)s','%(EXT)s'),))
4198        else:
4199            body = '#error Can not decode %s' % (tname)
4200        return body
4201
4202
4203#--- SetOfType ----------------------------------------------------------------
4204class SetOfType (SeqOfType):
4205    def eth_reg_sub(self, ident, ectx):
4206        itmnm = ident
4207        if not self.val.IsNamed ():
4208            itmnm += '/' + ITEM_FIELD_NAME
4209        self.val.eth_reg(itmnm, ectx, tstrip=1, idx='(##)', parent=ident)
4210
4211    def eth_tname(self):
4212        if self.val.type != 'Type_Ref':
4213            return '#' + self.type + '_' + str(id(self))
4214        if not self.HasConstraint():
4215            return "SET_OF_" + self.val.eth_tname()
4216        elif self.constr.IsSize():
4217            return 'SET_' + self.constr.eth_constrname() + '_OF_' + self.val.eth_tname()
4218        else:
4219            return '#' + self.type + '_' + str(id(self))
4220
4221    def eth_ftype(self, ectx):
4222        return ('FT_UINT32', 'BASE_DEC')
4223
4224    def eth_need_tree(self):
4225        return True
4226
4227    def GetTTag(self, ectx):
4228        return ('BER_CLASS_UNI', 'BER_UNI_TAG_SET')
4229
4230    def eth_type_default_pars(self, ectx, tname):
4231        pars = Type.eth_type_default_pars(self, ectx, tname)
4232        (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
4233        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_set_of'
4234        return pars
4235
4236    def eth_type_default_body(self, ectx, tname):
4237        if (ectx.Ber()):
4238            if (ectx.constraints_check and self.HasSizeConstraint()):
4239                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_set_of', ret='offset',
4240                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4241                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4242            else:
4243                body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset',
4244                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4245                                             ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4246        elif (ectx.Per() and not self.HasConstraint()):
4247            body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset',
4248                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4249                                         ('%(ETT_INDEX)s', '%(TABLE)s',),))
4250        elif (ectx.Per() and self.constr.type == 'Size'):
4251            body = ectx.eth_fn_call('dissect_%(ER)s_constrained_set_of', ret='offset',
4252                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4253                                         ('%(ETT_INDEX)s', '%(TABLE)s',),
4254                                         ('%(MIN_VAL)s', '%(MAX_VAL)s','%(EXT)s',),))
4255        else:
4256            body = '#error Can not decode %s' % (tname)
4257        return body
4258
4259def mk_tag_str (ctx, cls, typ, num):
4260
4261        # XXX should do conversion to int earlier!
4262    val = int (num)
4263    typ = typ.upper()
4264    if typ == 'DEFAULT':
4265        typ = ctx.tags_def
4266    return 'asn1.%s(%d,cls=asn1.%s_FLAG)' % (typ, val, cls) # XXX still ned
4267
4268#--- SequenceType -------------------------------------------------------------
4269class SequenceType (SeqType):
4270    def to_python (self, ctx):
4271            # name, tag (None for no tag, EXPLICIT() for explicit), typ)
4272            # or '' + (1,) for optional
4273            # XXX should also collect names for SEQUENCE inside SEQUENCE or
4274            # CHOICE or SEQUENCE_OF (where should the SEQUENCE_OF name come
4275            # from?  for others, element or arm name would be fine)
4276        seq_name = getattr (self, 'sequence_name', None)
4277        if seq_name is None:
4278            seq_name = 'None'
4279        else:
4280            seq_name = "'" + seq_name + "'"
4281        if 'ext_list' in self.__dict__:
4282            return "%sasn1.SEQUENCE ([%s], ext=[%s], seq_name = %s)" % (ctx.spaces (),
4283                                     self.elts_to_py (self.elt_list, ctx),
4284                                     self.elts_to_py (self.ext_list, ctx), seq_name)
4285        else:
4286            return "%sasn1.SEQUENCE ([%s]), seq_name = %s" % (ctx.spaces (),
4287                                     self.elts_to_py (self.elt_list, ctx), seq_name)
4288    def elts_to_py (self, list, ctx):
4289        # we have elt_type, val= named_type, maybe default=, optional=
4290        # named_type node: either ident = or typ =
4291        # need to dismember these in order to generate Python output syntax.
4292        ctx.indent ()
4293        def elt_to_py (e):
4294            assert (e.type == 'elt_type')
4295            nt = e.val
4296            optflag = e.optional
4297            #assert (not hasattr (e, 'default')) # XXX add support for DEFAULT!
4298            assert (nt.type == 'named_type')
4299            tagstr = 'None'
4300            identstr = nt.ident
4301            if hasattr (nt.typ, 'type') and nt.typ.type == 'tag': # ugh
4302                tagstr = mk_tag_str (ctx,nt.typ.tag.cls,
4303                                     nt.typ.tag.tag_typ,nt.typ.tag.num)
4304
4305
4306                nt = nt.typ
4307            return "('%s',%s,%s,%d)" % (identstr, tagstr,
4308                                      nt.typ.to_python (ctx), optflag)
4309        indentstr = ",\n" + ctx.spaces ()
4310        rv = indentstr.join ([elt_to_py (e) for e in list])
4311        ctx.outdent ()
4312        return rv
4313
4314    def eth_need_tree(self):
4315        return True
4316
4317    def GetTTag(self, ectx):
4318        return ('BER_CLASS_UNI', 'BER_UNI_TAG_SEQUENCE')
4319
4320    def eth_type_default_pars(self, ectx, tname):
4321        pars = Type.eth_type_default_pars(self, ectx, tname)
4322        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_sequence'
4323        return pars
4324
4325    def eth_type_default_body(self, ectx, tname):
4326        if (ectx.Ber()):
4327            body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset',
4328                                  par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4329                                       ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4330        elif (ectx.Per() or ectx.Oer()):
4331            body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset',
4332                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4333                                         ('%(ETT_INDEX)s', '%(TABLE)s',),))
4334        else:
4335            body = '#error Can not decode %s' % (tname)
4336        return body
4337
4338#--- ExtensionAdditionGroup ---------------------------------------------------
4339class ExtensionAdditionGroup (SeqType):
4340    def __init__(self,*args, **kw) :
4341        self.parent_ident = None
4342        self.parent_tname = None
4343        SeqType.__init__ (self,*args, **kw)
4344
4345    def eth_omit_field(self):
4346        return True
4347
4348    def eth_tname(self):
4349        if (self.parent_tname and self.IsNamed()):
4350            return self.parent_tname + "_" + self.name
4351        else:
4352            return SeqType.eth_tname(self)
4353
4354    def eth_reg_sub(self, ident, ectx):
4355        ectx.eth_dummy_eag_field_required()
4356        ectx.eth_dep_add(self.parent_ident, ident)
4357        SeqType.eth_reg_sub(self, ident, ectx)
4358
4359    def eth_type_default_pars(self, ectx, tname):
4360        pars = Type.eth_type_default_pars(self, ectx, tname)
4361        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_sequence'
4362        return pars
4363
4364    def eth_type_default_body(self, ectx, tname):
4365        if (ectx.Per()):
4366            body = ectx.eth_fn_call('dissect_%(ER)s_sequence_eag', ret='offset',
4367                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(TABLE)s',),))
4368        else:
4369            body = '#error Can not decode %s' % (tname)
4370        return body
4371
4372
4373#--- SetType ------------------------------------------------------------------
4374class SetType (SeqType):
4375
4376    def eth_need_tree(self):
4377        return True
4378
4379    def GetTTag(self, ectx):
4380        return ('BER_CLASS_UNI', 'BER_UNI_TAG_SET')
4381
4382    def eth_type_default_pars(self, ectx, tname):
4383        pars = Type.eth_type_default_pars(self, ectx, tname)
4384        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_set'
4385        return pars
4386
4387    def eth_type_default_body(self, ectx, tname):
4388        if (ectx.Ber()):
4389            body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset',
4390                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4391                                         ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
4392        elif (ectx.Per()):
4393            body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset',
4394                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4395                                         ('%(ETT_INDEX)s', '%(TABLE)s',),))
4396        else:
4397            body = '#error Can not decode %s' % (tname)
4398        return body
4399
4400#--- ChoiceType ---------------------------------------------------------------
4401class ChoiceType (Type):
4402    def to_python (self, ctx):
4403            # name, tag (None for no tag, EXPLICIT() for explicit), typ)
4404            # or '' + (1,) for optional
4405        if 'ext_list' in self.__dict__:
4406            return "%sasn1.CHOICE ([%s], ext=[%s])" % (ctx.spaces (),
4407                                   self.elts_to_py (self.elt_list, ctx),
4408                                   self.elts_to_py (self.ext_list, ctx))
4409        else:
4410            return "%sasn1.CHOICE ([%s])" % (ctx.spaces (), self.elts_to_py (self.elt_list, ctx))
4411    def elts_to_py (self, list, ctx):
4412        ctx.indent ()
4413        def elt_to_py (nt):
4414            assert (nt.type == 'named_type')
4415            tagstr = 'None'
4416            if hasattr (nt, 'ident'):
4417                identstr = nt.ident
4418            else:
4419                if hasattr (nt.typ, 'val'):
4420                    identstr = nt.typ.val # XXX, making up name
4421                elif hasattr (nt.typ, 'name'):
4422                    identstr = nt.typ.name
4423                else:
4424                    identstr = ctx.make_new_name ()
4425
4426            if hasattr (nt.typ, 'type') and nt.typ.type == 'tag': # ugh
4427                tagstr = mk_tag_str (ctx,nt.typ.tag.cls,
4428                                     nt.typ.tag.tag_typ,nt.typ.tag.num)
4429
4430
4431                nt = nt.typ
4432            return "('%s',%s,%s)" % (identstr, tagstr,
4433                                      nt.typ.to_python (ctx))
4434        indentstr = ",\n" + ctx.spaces ()
4435        rv =  indentstr.join ([elt_to_py (e) for e in list])
4436        ctx.outdent ()
4437        return rv
4438
4439    def eth_reg_sub(self, ident, ectx):
4440        #print "eth_reg_sub(ident='%s')" % (ident)
4441        # check if autotag is required
4442        autotag = False
4443        if (ectx.NeedTags() and (ectx.tag_def == 'AUTOMATIC')):
4444            autotag = True
4445            for e in (self.elt_list):
4446                if e.HasOwnTag(): autotag = False; break;
4447            if autotag and hasattr(self, 'ext_list'):
4448                for e in (self.ext_list):
4449                    if e.HasOwnTag(): autotag = False; break;
4450        # do autotag
4451        if autotag:
4452            atag = 0
4453            for e in (self.elt_list):
4454                e.AddTag(Tag(cls = 'CONTEXT', num = str(atag), mode = 'IMPLICIT'))
4455                atag += 1
4456            if autotag and hasattr(self, 'ext_list'):
4457                for e in (self.ext_list):
4458                    e.AddTag(Tag(cls = 'CONTEXT', num = str(atag), mode = 'IMPLICIT'))
4459                    atag += 1
4460        for e in (self.elt_list):
4461            e.eth_reg(ident, ectx, tstrip=1, parent=ident)
4462            if ectx.conform.check_item('EXPORTS', ident + '.' + e.name):
4463                ectx.eth_sel_req(ident, e.name)
4464        if hasattr(self, 'ext_list'):
4465            for e in (self.ext_list):
4466                e.eth_reg(ident, ectx, tstrip=1, parent=ident)
4467                if ectx.conform.check_item('EXPORTS', ident + '.' + e.name):
4468                    ectx.eth_sel_req(ident, e.name)
4469
4470    def sel_item(self, ident, sel, ectx):
4471        lst = self.elt_list[:]
4472        if hasattr(self, 'ext_list'):
4473            lst.extend(self.ext_list)
4474        ee = None
4475        for e in (self.elt_list):
4476            if e.IsNamed() and (e.name == sel):
4477                ee = e
4478                break
4479        if not ee:
4480            print("#CHOICE %s does not contain item %s" % (ident, sel))
4481        return ee
4482
4483    def sel_req(self, ident, sel, ectx):
4484        #print "sel_req(ident='%s', sel=%s)\n%s" % (ident, sel, str(self))
4485        ee = self.sel_item(ident, sel, ectx)
4486        if ee:
4487            ee.eth_reg(ident, ectx, tstrip=0, selflag=True)
4488
4489    def eth_ftype(self, ectx):
4490        return ('FT_UINT32', 'BASE_DEC')
4491
4492    def eth_ftype_sel(self, sel, ectx):
4493        ee = self.sel_item('', sel, ectx)
4494        if ee:
4495            return ee.eth_ftype(ectx)
4496        else:
4497            return ('FT_NONE', 'BASE_NONE')
4498
4499    def eth_strings(self):
4500        return '$$'
4501
4502    def eth_need_tree(self):
4503        return True
4504
4505    def eth_has_vals(self):
4506        return True
4507
4508    def GetTTag(self, ectx):
4509        lst = self.elt_list
4510        cls = 'BER_CLASS_ANY/*choice*/'
4511        #if hasattr(self, 'ext_list'):
4512        #  lst.extend(self.ext_list)
4513        #if (len(lst) > 0):
4514        #  cls = lst[0].GetTag(ectx)[0]
4515        #for e in (lst):
4516        #  if (e.GetTag(ectx)[0] != cls):
4517        #    cls = '-1/*choice*/'
4518        return (cls, '-1/*choice*/')
4519
4520    def GetTTagSel(self, sel, ectx):
4521        ee = self.sel_item('', sel, ectx)
4522        if ee:
4523            return ee.GetTag(ectx)
4524        else:
4525            return ('BER_CLASS_ANY/*unknown selection*/', '-1/*unknown selection*/')
4526
4527    def IndetermTag(self, ectx):
4528        #print "Choice IndetermTag()=%s" % (str(not self.HasOwnTag()))
4529        return not self.HasOwnTag()
4530
4531    def detect_tagval(self, ectx):
4532        tagval = False
4533        lst = self.elt_list[:]
4534        if hasattr(self, 'ext_list'):
4535            lst.extend(self.ext_list)
4536        if (len(lst) > 0) and (not (ectx.Per() or ectx.Oer()) or lst[0].HasOwnTag()):
4537            t = lst[0].GetTag(ectx)[0]
4538            tagval = True
4539        else:
4540            t = ''
4541            tagval = False
4542        if (t == 'BER_CLASS_UNI'):
4543            tagval = False
4544        for e in (lst):
4545            if not (ectx.Per() or ectx.Oer()) or e.HasOwnTag():
4546                tt = e.GetTag(ectx)[0]
4547            else:
4548                tt = ''
4549                tagval = False
4550            if (tt != t):
4551                tagval = False
4552        return tagval
4553
4554    def get_vals(self, ectx):
4555        tagval = self.detect_tagval(ectx)
4556        vals = []
4557        cnt = 0
4558        for e in (self.elt_list):
4559            if (tagval): val = e.GetTag(ectx)[1]
4560            else: val = str(cnt)
4561            vals.append((val, e.name))
4562            cnt += 1
4563        if hasattr(self, 'ext_list'):
4564            for e in (self.ext_list):
4565                if (tagval): val = e.GetTag(ectx)[1]
4566                else: val = str(cnt)
4567                vals.append((val, e.name))
4568                cnt += 1
4569        return vals
4570
4571    def eth_type_vals(self, tname, ectx):
4572        out = '\n'
4573        vals = self.get_vals(ectx)
4574        out += ectx.eth_vals(tname, vals)
4575        return out
4576
4577    def reg_enum_vals(self, tname, ectx):
4578        vals = self.get_vals(ectx)
4579        for (val, id) in vals:
4580            ectx.eth_reg_value(id, self, val, ethname=ectx.eth_enum_item(tname, id))
4581
4582    def eth_type_enum(self, tname, ectx):
4583        out = '\n'
4584        vals = self.get_vals(ectx)
4585        out += ectx.eth_enum(tname, vals)
4586        return out
4587
4588    def eth_type_default_pars(self, ectx, tname):
4589        pars = Type.eth_type_default_pars(self, ectx, tname)
4590        pars['TABLE'] = '%(PROTOP)s%(TNAME)s_choice'
4591        return pars
4592
4593    def eth_type_default_table(self, ectx, tname):
4594        def out_item(val, e, ext, ectx):
4595            has_enum = ectx.eth_type[tname]['enum'] & EF_ENUM
4596            if (has_enum):
4597                vval = ectx.eth_enum_item(tname, e.name)
4598            else:
4599                vval = val
4600            f = fname + '/' + e.name
4601            ef = ectx.field[f]['ethname']
4602            t = ectx.eth_hf[ef]['ethtype']
4603            if (ectx.Ber()):
4604                opt = ''
4605                if (not e.HasOwnTag()):
4606                    opt = 'BER_FLAGS_NOOWNTAG'
4607                elif (e.HasImplicitTag(ectx)):
4608                    if (opt): opt += '|'
4609                    opt += 'BER_FLAGS_IMPLTAG'
4610                if (not opt): opt = '0'
4611            if (ectx.Ber()):
4612                (tc, tn) = e.GetTag(ectx)
4613                out = '  { %3s, %-24s, %-13s, %s, %s, dissect_%s_%s },\n' \
4614                      % (vval, '&'+ectx.eth_hf[ef]['fullname'], tc, tn, opt, ectx.eth_type[t]['proto'], t)
4615            elif (ectx.Per() or ectx.Oer()):
4616                out = '  { %3s, %-24s, %-23s, dissect_%s_%s },\n' \
4617                      % (vval, '&'+ectx.eth_hf[ef]['fullname'], ext, ectx.eth_type[t]['proto'], t)
4618            else:
4619                out = ''
4620            return out
4621        # end out_item()
4622        #print "eth_type_default_table(tname='%s')" % (tname)
4623        fname = ectx.eth_type[tname]['ref'][0]
4624        tagval = self.detect_tagval(ectx)
4625        table = "static const %(ER)s_choice_t %(TABLE)s[] = {\n"
4626        cnt = 0
4627        if hasattr(self, 'ext_list'):
4628            ext = 'ASN1_EXTENSION_ROOT'
4629        else:
4630            ext = 'ASN1_NO_EXTENSIONS'
4631        empty_ext_flag = '0'
4632        if (len(self.elt_list)==0) and hasattr(self, 'ext_list') and (len(self.ext_list)==0):
4633            empty_ext_flag = ext
4634        for e in (self.elt_list):
4635            if (tagval): val = e.GetTag(ectx)[1]
4636            else: val = str(cnt)
4637            table += out_item(val, e, ext, ectx)
4638            cnt += 1
4639        if hasattr(self, 'ext_list'):
4640            for e in (self.ext_list):
4641                if (tagval): val = e.GetTag(ectx)[1]
4642                else: val = str(cnt)
4643                table += out_item(val, e, 'ASN1_NOT_EXTENSION_ROOT', ectx)
4644                cnt += 1
4645        if (ectx.Ber()):
4646            table += "  { 0, NULL, 0, 0, 0, NULL }\n};\n"
4647        else:
4648            table += "  { 0, NULL, %s, NULL }\n};\n" % (empty_ext_flag)
4649        return table
4650
4651    def eth_type_default_body(self, ectx, tname):
4652        if (ectx.Ber()):
4653            body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset',
4654                                    par=(('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4655                                         ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s'),
4656                                         ('%(VAL_PTR)s',),))
4657        elif (ectx.Per() or ectx.Oer()):
4658            body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset',
4659                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4660                                         ('%(ETT_INDEX)s', '%(TABLE)s',),
4661                                         ('%(VAL_PTR)s',),))
4662        else:
4663            body = '#error Can not decode %s' % (tname)
4664        return body
4665
4666#--- ChoiceValue ----------------------------------------------------
4667class ChoiceValue (Value):
4668    def to_str(self, ectx):
4669        return self.val.to_str(ectx)
4670
4671    def fld_obj_eq(self, other):
4672        return isinstance(other, ChoiceValue) and (self.choice == other.choice) and (str(self.val.val) == str(other.val.val))
4673
4674#--- EnumeratedType -----------------------------------------------------------
4675class EnumeratedType (Type):
4676    def to_python (self, ctx):
4677        def strify_one (named_num):
4678            return "%s=%s" % (named_num.ident, named_num.val)
4679        return "asn1.ENUM(%s)" % ",".join (map (strify_one, self.val))
4680
4681    def eth_ftype(self, ectx):
4682        return ('FT_UINT32', 'BASE_DEC')
4683
4684    def eth_strings(self):
4685        return '$$'
4686
4687    def eth_has_vals(self):
4688        return True
4689
4690    def GetTTag(self, ectx):
4691        return ('BER_CLASS_UNI', 'BER_UNI_TAG_ENUMERATED')
4692
4693    def get_vals_etc(self, ectx):
4694        vals = []
4695        lastv = 0
4696        used = {}
4697        maxv = 0
4698        root_num = 0
4699        ext_num = 0
4700        map_table = []
4701        for e in (self.val):
4702            if e.type == 'NamedNumber':
4703                used[int(e.val)] = True
4704        for e in (self.val):
4705            if e.type == 'NamedNumber':
4706                val = int(e.val)
4707            else:
4708                while lastv in used:
4709                    lastv += 1
4710                val = lastv
4711                used[val] = True
4712            vals.append((val, e.ident))
4713            map_table.append(val)
4714            root_num += 1
4715            if val > maxv:
4716                maxv = val
4717        if self.ext is not None:
4718            for e in (self.ext):
4719                if e.type == 'NamedNumber':
4720                    used[int(e.val)] = True
4721            for e in (self.ext):
4722                if e.type == 'NamedNumber':
4723                    val = int(e.val)
4724                else:
4725                    while lastv in used:
4726                        lastv += 1
4727                    val = lastv
4728                    used[val] = True
4729                vals.append((val, e.ident))
4730                map_table.append(val)
4731                ext_num += 1
4732                if val > maxv:
4733                    maxv = val
4734        need_map = False
4735        for i in range(len(map_table)):
4736            need_map = need_map or (map_table[i] != i)
4737        if (not need_map):
4738            map_table = None
4739        return (vals, root_num, ext_num, map_table)
4740
4741    def eth_type_vals(self, tname, ectx):
4742        out = '\n'
4743        vals = self.get_vals_etc(ectx)[0]
4744        out += ectx.eth_vals(tname, vals)
4745        return out
4746
4747    def reg_enum_vals(self, tname, ectx):
4748        vals = self.get_vals_etc(ectx)[0]
4749        for (val, id) in vals:
4750            ectx.eth_reg_value(id, self, val, ethname=ectx.eth_enum_item(tname, id))
4751
4752    def eth_type_enum(self, tname, ectx):
4753        out = '\n'
4754        vals = self.get_vals_etc(ectx)[0]
4755        out += ectx.eth_enum(tname, vals)
4756        return out
4757
4758    def eth_type_default_pars(self, ectx, tname):
4759        pars = Type.eth_type_default_pars(self, ectx, tname)
4760        (root_num, ext_num, map_table) = self.get_vals_etc(ectx)[1:]
4761        if self.ext is not None:
4762            ext = 'TRUE'
4763        else:
4764            ext = 'FALSE'
4765        pars['ROOT_NUM'] = str(root_num)
4766        pars['EXT'] = ext
4767        pars['EXT_NUM'] = str(ext_num)
4768        if (map_table):
4769            pars['TABLE'] = '%(PROTOP)s%(TNAME)s_value_map'
4770        else:
4771            pars['TABLE'] = 'NULL'
4772        return pars
4773
4774    def eth_type_default_table(self, ectx, tname):
4775        if (not ectx.Per() and not ectx.Oer()): return ''
4776        map_table = self.get_vals_etc(ectx)[3]
4777        if map_table is None: return ''
4778        table = "static guint32 %(TABLE)s[%(ROOT_NUM)s+%(EXT_NUM)s] = {"
4779        table += ", ".join([str(v) for v in map_table])
4780        table += "};\n"
4781        return table
4782
4783    def eth_type_default_body(self, ectx, tname):
4784        if (ectx.Ber()):
4785            if (ectx.constraints_check and self.HasValueConstraint()):
4786                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset',
4787                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
4788                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
4789            else:
4790                body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset',
4791                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
4792                                             ('%(VAL_PTR)s',),))
4793        elif (ectx.Per() or ectx.Oer()):
4794            body = ectx.eth_fn_call('dissect_%(ER)s_enumerated', ret='offset',
4795                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
4796                                         ('%(ROOT_NUM)s', '%(VAL_PTR)s', '%(EXT)s', '%(EXT_NUM)s', '%(TABLE)s',),))
4797        else:
4798            body = '#error Can not decode %s' % (tname)
4799        return body
4800
4801#--- EmbeddedPDVType -----------------------------------------------------------
4802class EmbeddedPDVType (Type):
4803    def eth_tname(self):
4804        return 'EMBEDDED_PDV'
4805
4806    def eth_ftype(self, ectx):
4807        return ('FT_NONE', 'BASE_NONE')
4808
4809    def GetTTag(self, ectx):
4810        return ('BER_CLASS_UNI', 'BER_UNI_TAG_EMBEDDED_PDV')
4811
4812    def eth_type_default_pars(self, ectx, tname):
4813        pars = Type.eth_type_default_pars(self, ectx, tname)
4814        if ectx.default_embedded_pdv_cb:
4815            pars['TYPE_REF_FN'] = ectx.default_embedded_pdv_cb
4816        else:
4817            pars['TYPE_REF_FN'] = 'NULL'
4818        return pars
4819
4820    def eth_type_default_body(self, ectx, tname):
4821        if (ectx.Ber()):
4822            body = ectx.eth_fn_call('dissect_%(ER)s_EmbeddedPDV_Type', ret='offset',
4823                                    par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4824        elif (ectx.Per()):
4825            body = ectx.eth_fn_call('dissect_%(ER)s_embedded_pdv', ret='offset',
4826                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4827        else:
4828            body = '#error Can not decode %s' % (tname)
4829        return body
4830
4831#--- ExternalType -----------------------------------------------------------
4832class ExternalType (Type):
4833    def eth_tname(self):
4834        return 'EXTERNAL'
4835
4836    def eth_ftype(self, ectx):
4837        return ('FT_NONE', 'BASE_NONE')
4838
4839    def GetTTag(self, ectx):
4840        return ('BER_CLASS_UNI', 'BER_UNI_TAG_EXTERNAL')
4841
4842    def eth_type_default_pars(self, ectx, tname):
4843        pars = Type.eth_type_default_pars(self, ectx, tname)
4844        if ectx.default_external_type_cb:
4845            pars['TYPE_REF_FN'] = ectx.default_external_type_cb
4846        else:
4847            pars['TYPE_REF_FN'] = 'NULL'
4848        return pars
4849
4850    def eth_type_default_body(self, ectx, tname):
4851        if (ectx.Ber()):
4852            body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
4853                                    par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4854        elif (ectx.Per()):
4855            body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
4856                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4857        else:
4858            body = '#error Can not decode %s' % (tname)
4859        return body
4860
4861#--- OpenType -----------------------------------------------------------
4862class OpenType (Type):
4863    def to_python (self, ctx):
4864        return "asn1.ANY"
4865
4866    def single_type(self):
4867        if (self.HasConstraint() and
4868            self.constr.type == 'Type' and
4869            self.constr.subtype.type == 'Type_Ref'):
4870            return self.constr.subtype.val
4871        return None
4872
4873    def eth_reg_sub(self, ident, ectx):
4874        t = self.single_type()
4875        if t:
4876            ectx.eth_dep_add(ident, t)
4877
4878    def eth_tname(self):
4879        t = self.single_type()
4880        if t:
4881            return 'OpenType_' + t
4882        else:
4883            return Type.eth_tname(self)
4884
4885    def eth_ftype(self, ectx):
4886        return ('FT_NONE', 'BASE_NONE')
4887
4888    def GetTTag(self, ectx):
4889        return ('BER_CLASS_ANY', '0')
4890
4891    def eth_type_default_pars(self, ectx, tname):
4892        pars = Type.eth_type_default_pars(self, ectx, tname)
4893        pars['FN_VARIANT'] = ectx.default_opentype_variant
4894        t = self.single_type()
4895        if t:
4896            t = ectx.type[t]['ethname']
4897            pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
4898            pars['TYPE_REF_TNAME'] = t
4899            pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
4900        else:
4901            pars['TYPE_REF_FN'] = 'NULL'
4902        return pars
4903
4904    def eth_type_default_body(self, ectx, tname):
4905        if (ectx.Per()):
4906            body = ectx.eth_fn_call('dissect_%(ER)s_open_type%(FN_VARIANT)s', ret='offset',
4907                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4908        else:
4909            body = '#error Can not decode %s' % (tname)
4910        return body
4911
4912#--- InstanceOfType -----------------------------------------------------------
4913class InstanceOfType (Type):
4914    def eth_tname(self):
4915        return 'INSTANCE_OF'
4916
4917    def eth_ftype(self, ectx):
4918        return ('FT_NONE', 'BASE_NONE')
4919
4920    def GetTTag(self, ectx):
4921        return ('BER_CLASS_UNI', 'BER_UNI_TAG_EXTERNAL')
4922
4923    def eth_type_default_pars(self, ectx, tname):
4924        pars = Type.eth_type_default_pars(self, ectx, tname)
4925        if ectx.default_external_type_cb:
4926            pars['TYPE_REF_FN'] = ectx.default_external_type_cb
4927        else:
4928            pars['TYPE_REF_FN'] = 'NULL'
4929        return pars
4930
4931    def eth_type_default_body(self, ectx, tname):
4932        if (ectx.Ber()):
4933            body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
4934                                    par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
4935        else:
4936            body = '#error Can not decode %s' % (tname)
4937        return body
4938
4939#--- AnyType -----------------------------------------------------------
4940class AnyType (Type):
4941    def to_python (self, ctx):
4942        return "asn1.ANY"
4943
4944    def eth_ftype(self, ectx):
4945        return ('FT_NONE', 'BASE_NONE')
4946
4947    def GetTTag(self, ectx):
4948        return ('BER_CLASS_ANY', '0')
4949
4950    def eth_type_default_body(self, ectx, tname):
4951        body = '#error Can not decode %s' % (tname)
4952        return body
4953
4954class Literal (Node):
4955    def to_python (self, ctx):
4956        return self.val
4957
4958#--- NullType -----------------------------------------------------------------
4959class NullType (Type):
4960    def to_python (self, ctx):
4961        return 'asn1.NULL'
4962
4963    def eth_tname(self):
4964        return 'NULL'
4965
4966    def GetTTag(self, ectx):
4967        return ('BER_CLASS_UNI', 'BER_UNI_TAG_NULL')
4968
4969    def eth_type_default_body(self, ectx, tname):
4970        if (ectx.Ber()):
4971            body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset',
4972                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
4973        elif (ectx.Per() or ectx.Oer()):
4974            body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset',
4975                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
4976        else:
4977            body = '#error Can not decode %s' % (tname)
4978        return body
4979
4980#--- NullValue ----------------------------------------------------
4981class NullValue (Value):
4982    def to_str(self, ectx):
4983        return 'NULL'
4984
4985#--- RealType -----------------------------------------------------------------
4986class RealType (Type):
4987    def to_python (self, ctx):
4988        return 'asn1.REAL'
4989
4990    def eth_tname(self):
4991        return 'REAL'
4992
4993    def GetTTag(self, ectx):
4994        return ('BER_CLASS_UNI', 'BER_UNI_TAG_REAL')
4995
4996    def eth_ftype(self, ectx):
4997        return ('FT_DOUBLE', 'BASE_NONE')
4998
4999    def eth_type_default_body(self, ectx, tname):
5000        if (ectx.Ber()):
5001            body = ectx.eth_fn_call('dissect_%(ER)s_real', ret='offset',
5002                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
5003                                         ('%(VAL_PTR)s',),))
5004        elif (ectx.Per()):
5005            body = ectx.eth_fn_call('dissect_%(ER)s_real', ret='offset',
5006                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5007        else:
5008            body = '#error Can not decode %s' % (tname)
5009        return body
5010
5011#--- BooleanType --------------------------------------------------------------
5012class BooleanType (Type):
5013    def to_python (self, ctx):
5014        return 'asn1.BOOLEAN'
5015
5016    def eth_tname(self):
5017        return 'BOOLEAN'
5018
5019    def GetTTag(self, ectx):
5020        return ('BER_CLASS_UNI', 'BER_UNI_TAG_BOOLEAN')
5021
5022    def eth_ftype(self, ectx):
5023        return ('FT_BOOLEAN', 'BASE_NONE')
5024
5025    def eth_type_default_body(self, ectx, tname):
5026        if (ectx.Ber()):
5027            body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset',
5028                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', '%(VAL_PTR)s'),))
5029        elif (ectx.Per()):
5030            body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset',
5031                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5032        elif (ectx.Oer()):
5033            body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset',
5034                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5035        else:
5036            body = '#error Can not decode %s' % (tname)
5037        return body
5038
5039#--- OctetStringType ----------------------------------------------------------
5040class OctetStringType (Type):
5041    def to_python (self, ctx):
5042        return 'asn1.OCTSTRING'
5043
5044    def eth_tname(self):
5045        if not self.HasConstraint():
5046            return 'OCTET_STRING'
5047        elif self.constr.type == 'Size':
5048            return 'OCTET_STRING' + '_' + self.constr.eth_constrname()
5049        else:
5050            return '#' + self.type + '_' + str(id(self))
5051
5052    def eth_ftype(self, ectx):
5053        return ('FT_BYTES', 'BASE_NONE')
5054
5055    def GetTTag(self, ectx):
5056        return ('BER_CLASS_UNI', 'BER_UNI_TAG_OCTETSTRING')
5057
5058    def eth_need_pdu(self, ectx):
5059        pdu = None
5060        if self.HasContentsConstraint():
5061            t = self.constr.GetContents(ectx)
5062            if t and (ectx.default_containing_variant in ('_pdu', '_pdu_new')):
5063                pdu = { 'type' : t,
5064                        'new' : ectx.default_containing_variant == '_pdu_new' }
5065        return pdu
5066
5067    def eth_type_default_pars(self, ectx, tname):
5068        pars = Type.eth_type_default_pars(self, ectx, tname)
5069        (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
5070        if self.HasContentsConstraint():
5071            pars['FN_VARIANT'] = ectx.default_containing_variant
5072            t = self.constr.GetContents(ectx)
5073            if t:
5074                if pars['FN_VARIANT'] in ('_pdu', '_pdu_new'):
5075                    t = ectx.field[t]['ethname']
5076                    pars['TYPE_REF_PROTO'] = ''
5077                    pars['TYPE_REF_TNAME'] = t
5078                    pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_TNAME)s'
5079                else:
5080                    t = ectx.type[t]['ethname']
5081                    pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
5082                    pars['TYPE_REF_TNAME'] = t
5083                    pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
5084            else:
5085                pars['TYPE_REF_FN'] = 'NULL'
5086        return pars
5087
5088    def eth_type_default_body(self, ectx, tname):
5089        if (ectx.Ber()):
5090            if (ectx.constraints_check and self.HasSizeConstraint()):
5091                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_octet_string', ret='offset',
5092                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
5093                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5094            else:
5095                body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset',
5096                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
5097                                             ('%(VAL_PTR)s',),))
5098        elif (ectx.Per() or ectx.Oer()):
5099            if self.HasContentsConstraint():
5100                body = ectx.eth_fn_call('dissect_%(ER)s_octet_string_containing%(FN_VARIANT)s', ret='offset',
5101                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5102                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(TYPE_REF_FN)s',),))
5103            else:
5104                body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset',
5105                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5106                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(VAL_PTR)s',),))
5107        else:
5108            body = '#error Can not decode %s' % (tname)
5109        return body
5110
5111#--- CharacterStringType ------------------------------------------------------
5112class CharacterStringType (Type):
5113    def eth_tname(self):
5114        if not self.HasConstraint():
5115            return self.eth_tsname()
5116        elif self.constr.type == 'Size':
5117            return self.eth_tsname() + '_' + self.constr.eth_constrname()
5118        else:
5119            return '#' + self.type + '_' + str(id(self))
5120
5121    def eth_ftype(self, ectx):
5122        return ('FT_STRING', 'BASE_NONE')
5123
5124class RestrictedCharacterStringType (CharacterStringType):
5125    def to_python (self, ctx):
5126        return 'asn1.' + self.eth_tsname()
5127
5128    def GetTTag(self, ectx):
5129        return ('BER_CLASS_UNI', 'BER_UNI_TAG_' + self.eth_tsname())
5130
5131    def eth_type_default_pars(self, ectx, tname):
5132        pars = Type.eth_type_default_pars(self, ectx, tname)
5133        (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
5134        (pars['STRING_TYPE'], pars['STRING_TAG']) = (self.eth_tsname(), self.GetTTag(ectx)[1])
5135        (pars['ALPHABET'], pars['ALPHABET_LEN']) = self.eth_get_alphabet_constr(ectx)
5136        return pars
5137
5138    def eth_type_default_body(self, ectx, tname):
5139        if (ectx.Ber()):
5140            if (ectx.constraints_check and self.HasSizeConstraint()):
5141                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_restricted_string', ret='offset',
5142                                        par=(('%(IMPLICIT_TAG)s', '%(STRING_TAG)s'),
5143                                             ('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
5144                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5145            else:
5146                body = ectx.eth_fn_call('dissect_%(ER)s_restricted_string', ret='offset',
5147                                        par=(('%(IMPLICIT_TAG)s', '%(STRING_TAG)s'),
5148                                             ('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
5149                                             ('%(VAL_PTR)s',),))
5150        elif (ectx.Per() and self.HasPermAlph()):
5151            body = ectx.eth_fn_call('dissect_%(ER)s_restricted_character_string', ret='offset',
5152                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5153                                         ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(ALPHABET)s', '%(ALPHABET_LEN)s'),
5154                                         ('%(VAL_PTR)s',),))
5155        elif (ectx.Per()):
5156            if (self.eth_tsname() == 'GeneralString'):
5157                body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
5158                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
5159            elif (self.eth_tsname() == 'GeneralizedTime' or self.eth_tsname() == 'UTCTime'):
5160                body = ectx.eth_fn_call('dissect_%(ER)s_VisibleString', ret='offset',
5161                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5162                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),))
5163            else:
5164                body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
5165                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5166                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),))
5167        elif (ectx.Oer()):
5168            body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
5169                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5170                                            ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s',),))
5171        else:
5172            body = '#error Can not decode %s' % (tname)
5173        return body
5174
5175class BMPStringType (RestrictedCharacterStringType):
5176    def eth_tsname(self):
5177        return 'BMPString'
5178
5179class GeneralStringType (RestrictedCharacterStringType):
5180    def eth_tsname(self):
5181        return 'GeneralString'
5182
5183class GraphicStringType (RestrictedCharacterStringType):
5184    def eth_tsname(self):
5185        return 'GraphicString'
5186
5187class IA5StringType (RestrictedCharacterStringType):
5188    def eth_tsname(self):
5189        return 'IA5String'
5190
5191class NumericStringType (RestrictedCharacterStringType):
5192    def eth_tsname(self):
5193        return 'NumericString'
5194
5195class PrintableStringType (RestrictedCharacterStringType):
5196    def eth_tsname(self):
5197        return 'PrintableString'
5198
5199class TeletexStringType (RestrictedCharacterStringType):
5200    def eth_tsname(self):
5201        return 'TeletexString'
5202
5203class T61StringType (RestrictedCharacterStringType):
5204    def eth_tsname(self):
5205        return 'T61String'
5206    def GetTTag(self, ectx):
5207        return ('BER_CLASS_UNI', 'BER_UNI_TAG_TeletexString')
5208
5209class UniversalStringType (RestrictedCharacterStringType):
5210    def eth_tsname(self):
5211        return 'UniversalString'
5212
5213class UTF8StringType (RestrictedCharacterStringType):
5214    def eth_tsname(self):
5215        return 'UTF8String'
5216
5217class VideotexStringType (RestrictedCharacterStringType):
5218    def eth_tsname(self):
5219        return 'VideotexString'
5220
5221class VisibleStringType (RestrictedCharacterStringType):
5222    def eth_tsname(self):
5223        return 'VisibleString'
5224
5225class ISO646StringType (RestrictedCharacterStringType):
5226    def eth_tsname(self):
5227        return 'ISO646String'
5228    def GetTTag(self, ectx):
5229        return ('BER_CLASS_UNI', 'BER_UNI_TAG_VisibleString')
5230
5231class UnrestrictedCharacterStringType (CharacterStringType):
5232    def to_python (self, ctx):
5233        return 'asn1.UnrestrictedCharacterString'
5234    def eth_tsname(self):
5235        return 'CHARACTER_STRING'
5236
5237#--- UsefulType ---------------------------------------------------------------
5238class GeneralizedTime (RestrictedCharacterStringType):
5239    def eth_tsname(self):
5240        return 'GeneralizedTime'
5241
5242    def eth_type_default_body(self, ectx, tname):
5243        if (ectx.Ber()):
5244            body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
5245                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
5246            return body
5247        else:
5248            return RestrictedCharacterStringType.eth_type_default_body(self, ectx, tname)
5249
5250class UTCTime (RestrictedCharacterStringType):
5251    def eth_tsname(self):
5252        return 'UTCTime'
5253
5254    def eth_type_default_body(self, ectx, tname):
5255        if (ectx.Ber()):
5256            body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
5257                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', 'NULL', 'NULL'),))
5258            return body
5259        else:
5260            return RestrictedCharacterStringType.eth_type_default_body(self, ectx, tname)
5261
5262class ObjectDescriptor (RestrictedCharacterStringType):
5263    def eth_tsname(self):
5264        return 'ObjectDescriptor'
5265
5266    def eth_type_default_body(self, ectx, tname):
5267        if (ectx.Ber()):
5268            body = RestrictedCharacterStringType.eth_type_default_body(self, ectx, tname)
5269        elif (ectx.Per()):
5270            body = ectx.eth_fn_call('dissect_%(ER)s_object_descriptor', ret='offset',
5271                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5272        else:
5273            body = '#error Can not decode %s' % (tname)
5274        return body
5275
5276#--- ObjectIdentifierType -----------------------------------------------------
5277class ObjectIdentifierType (Type):
5278    def to_python (self, ctx):
5279        return 'asn1.OBJECT_IDENTIFIER'
5280
5281    def eth_tname(self):
5282        return 'OBJECT_IDENTIFIER'
5283
5284    def eth_ftype(self, ectx):
5285        return ('FT_OID', 'BASE_NONE')
5286
5287    def GetTTag(self, ectx):
5288        return ('BER_CLASS_UNI', 'BER_UNI_TAG_OID')
5289
5290    def eth_type_default_pars(self, ectx, tname):
5291        pars = Type.eth_type_default_pars(self, ectx, tname)
5292        pars['FN_VARIANT'] = ectx.default_oid_variant
5293        return pars
5294
5295    def eth_type_default_body(self, ectx, tname):
5296        if (ectx.Ber()):
5297            body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier%(FN_VARIANT)s', ret='offset',
5298                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5299        elif (ectx.Per()):
5300            body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier%(FN_VARIANT)s', ret='offset',
5301                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5302        else:
5303            body = '#error Can not decode %s' % (tname)
5304        return body
5305
5306#--- ObjectIdentifierValue ----------------------------------------------------
5307class ObjectIdentifierValue (Value):
5308    def get_num(self, path, val):
5309        return str(oid_names.get(path + '/' + val, val))
5310
5311    def to_str(self, ectx):
5312        out = ''
5313        path = ''
5314        first = True
5315        sep = ''
5316        for v in self.comp_list:
5317            if isinstance(v, Node) and (v.type == 'name_and_number'):
5318                vstr = v.number
5319            elif v.isdigit():
5320                vstr = v
5321            else:
5322                vstr = self.get_num(path, v)
5323            if not first and not vstr.isdigit():
5324                vstr = ectx.value_get_val(vstr)
5325            if first:
5326                if vstr.isdigit():
5327                    out += '"' + vstr
5328                else:
5329                    out += ectx.value_get_eth(vstr) + '"'
5330            else:
5331                out += sep + vstr
5332            path += sep + vstr
5333            first = False
5334            sep = '.'
5335        out += '"'
5336        return out
5337
5338    def get_dep(self):
5339        v = self.comp_list[0]
5340        if isinstance(v, Node) and (v.type == 'name_and_number'):
5341            return None
5342        elif v.isdigit():
5343            return None
5344        else:
5345            vstr = self.get_num('', v)
5346        if vstr.isdigit():
5347            return None
5348        else:
5349            return vstr
5350
5351class NamedNumber(Node):
5352    def to_python (self, ctx):
5353        return "('%s',%s)" % (self.ident, self.val)
5354    def __lt__(self, other):
5355        return int(self.val) < int(other.val)
5356
5357class NamedNumListBase(Node):
5358    def to_python (self, ctx):
5359        return "asn1.%s_class ([%s])" % (self.asn1_typ,",".join (
5360            [x.to_python (ctx) for x in self.named_list]))
5361
5362#--- RelativeOIDType ----------------------------------------------------------
5363class RelativeOIDType (Type):
5364
5365    def eth_tname(self):
5366        return 'RELATIVE_OID'
5367
5368    def eth_ftype(self, ectx):
5369        return ('FT_REL_OID', 'BASE_NONE')
5370
5371    def GetTTag(self, ectx):
5372        return ('BER_CLASS_UNI', 'BER_UNI_TAG_RELATIVE_OID')
5373
5374    def eth_type_default_pars(self, ectx, tname):
5375        pars = Type.eth_type_default_pars(self, ectx, tname)
5376        pars['FN_VARIANT'] = ectx.default_oid_variant
5377        return pars
5378
5379    def eth_type_default_body(self, ectx, tname):
5380        if (ectx.Ber()):
5381            body = ectx.eth_fn_call('dissect_%(ER)s_relative_oid%(FN_VARIANT)s', ret='offset',
5382                                    par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5383        elif (ectx.Per()):
5384            body = ectx.eth_fn_call('dissect_%(ER)s_relative_oid%(FN_VARIANT)s', ret='offset',
5385                                    par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5386        else:
5387            body = '#error Can not decode %s' % (tname)
5388        return body
5389
5390
5391#--- IntegerType --------------------------------------------------------------
5392class IntegerType (Type):
5393    def to_python (self, ctx):
5394        return "asn1.INTEGER_class ([%s])" % (",".join (
5395            [x.to_python (ctx) for x in self.named_list]))
5396
5397    def add_named_value(self, ident, val):
5398        e = NamedNumber(ident = ident, val = val)
5399        if not self.named_list:
5400            self.named_list = []
5401        self.named_list.append(e)
5402
5403    def eth_tname(self):
5404        if self.named_list:
5405            return Type.eth_tname(self)
5406        if not self.HasConstraint():
5407            return 'INTEGER'
5408        elif self.constr.type == 'SingleValue' or self.constr.type == 'ValueRange':
5409            return 'INTEGER' + '_' + self.constr.eth_constrname()
5410        else:
5411            return 'INTEGER' + '_' + self.constr.eth_tname()
5412
5413    def GetTTag(self, ectx):
5414        return ('BER_CLASS_UNI', 'BER_UNI_TAG_INTEGER')
5415
5416
5417    def eth_ftype(self, ectx):
5418        if self.HasConstraint():
5419            if not self.constr.IsNegativ():
5420                if self.constr.Needs64b(ectx):
5421                    return ('FT_UINT64', 'BASE_DEC')
5422                else:
5423                    return ('FT_UINT32', 'BASE_DEC')
5424            if self.constr.Needs64b(ectx):
5425                return ('FT_INT64', 'BASE_DEC')
5426        return ('FT_INT32', 'BASE_DEC')
5427
5428    def eth_strings(self):
5429        if (self.named_list):
5430            return '$$'
5431        else:
5432            return 'NULL'
5433
5434    def eth_has_vals(self):
5435        if (self.named_list):
5436            return True
5437        else:
5438            return False
5439
5440    def get_vals(self, ectx):
5441        vals = []
5442        for e in (self.named_list):
5443            vals.append((int(e.val), e.ident))
5444        return vals
5445
5446    def eth_type_vals(self, tname, ectx):
5447        if not self.eth_has_vals(): return ''
5448        out = '\n'
5449        vals = self.get_vals(ectx)
5450        out += ectx.eth_vals(tname, vals)
5451        return out
5452
5453    def reg_enum_vals(self, tname, ectx):
5454        vals = self.get_vals(ectx)
5455        for (val, id) in vals:
5456            ectx.eth_reg_value(id, self, val, ethname=ectx.eth_enum_item(tname, id))
5457
5458    def eth_type_enum(self, tname, ectx):
5459        if not self.eth_has_enum(tname, ectx): return ''
5460        out = '\n'
5461        vals = self.get_vals(ectx)
5462        out += ectx.eth_enum(tname, vals)
5463        return out
5464
5465    def eth_type_default_pars(self, ectx, tname):
5466        pars = Type.eth_type_default_pars(self, ectx, tname)
5467        if self.HasValueConstraint():
5468            (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_value_constr(ectx)
5469            if (pars['FN_VARIANT'] == '') and self.constr.Needs64b(ectx):
5470                if ectx.Ber(): pars['FN_VARIANT'] = '64'
5471                else:
5472                    if (ectx.Oer() and pars['MAX_VAL'] == 'NO_BOUND'):
5473                        pars['FN_VARIANT'] = '_64b_no_ub'
5474                    else:
5475                        pars['FN_VARIANT'] = '_64b'
5476        return pars
5477
5478    def eth_type_default_body(self, ectx, tname):
5479        if (ectx.Ber()):
5480            if (ectx.constraints_check and self.HasValueConstraint()):
5481                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer%(FN_VARIANT)s', ret='offset',
5482                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
5483                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
5484            else:
5485                body = ectx.eth_fn_call('dissect_%(ER)s_integer%(FN_VARIANT)s', ret='offset',
5486                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
5487                                             ('%(VAL_PTR)s',),))
5488        elif (ectx.Per() or ectx.Oer()):
5489            if (self.HasValueConstraint()):
5490                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer%(FN_VARIANT)s', ret='offset',
5491                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5492                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s', '%(EXT)s'),))
5493            else:
5494                body = ectx.eth_fn_call('dissect_%(ER)s_integer%(FN_VARIANT)s', ret='offset',
5495                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s'),))
5496        else:
5497            body = '#error Can not decode %s' % (tname)
5498        return body
5499
5500#--- BitStringType ------------------------------------------------------------
5501class BitStringType (Type):
5502    def to_python (self, ctx):
5503        return "asn1.BITSTRING_class ([%s])" % (",".join (
5504            [x.to_python (ctx) for x in self.named_list]))
5505
5506    def eth_tname(self):
5507        if self.named_list:
5508            return Type.eth_tname(self)
5509        elif not self.HasConstraint():
5510            return 'BIT_STRING'
5511        elif self.constr.IsSize():
5512            return 'BIT_STRING' + '_' + self.constr.eth_constrname()
5513        else:
5514            return '#' + self.type + '_' + str(id(self))
5515
5516    def GetTTag(self, ectx):
5517        return ('BER_CLASS_UNI', 'BER_UNI_TAG_BITSTRING')
5518
5519    def eth_ftype(self, ectx):
5520            return ('FT_BYTES', 'BASE_NONE')
5521
5522    def eth_need_tree(self):
5523        return self.named_list
5524
5525    def eth_need_pdu(self, ectx):
5526        pdu = None
5527        if self.HasContentsConstraint():
5528            t = self.constr.GetContents(ectx)
5529            if t and (ectx.default_containing_variant in ('_pdu', '_pdu_new')):
5530                pdu = { 'type' : t,
5531                        'new' : ectx.default_containing_variant == '_pdu_new' }
5532        return pdu
5533
5534    def sortNamedBits(self):
5535        return self.named_list.val
5536
5537    def eth_named_bits(self):
5538        bits = []
5539        if (self.named_list):
5540            sorted_list = self.named_list
5541            sorted_list.sort()
5542            expected_bit_no = 0;
5543            for e in (sorted_list):
5544            # Fill the table with "spare_bit" for "un named bits"
5545                if (int(e.val) != 0) and (expected_bit_no != int(e.val)):
5546                        while ( expected_bit_no < int(e.val)):
5547                            bits.append((expected_bit_no, ("spare_bit%u" % (expected_bit_no))))
5548                            expected_bit_no = expected_bit_no + 1
5549                            #print ("Adding named bits to list %s bit no %d" % (e.ident, int (e.val)))
5550                bits.append((int(e.val), e.ident))
5551                expected_bit_no = int(e.val) + 1
5552        return bits
5553
5554    def eth_type_default_pars(self, ectx, tname):
5555        pars = Type.eth_type_default_pars(self, ectx, tname)
5556        pars['LEN_PTR'] = 'NULL'
5557        (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
5558        if 'ETT_INDEX' not in pars:
5559            pars['ETT_INDEX'] = '-1'
5560        pars['TABLE'] = 'NULL'
5561        if self.eth_named_bits():
5562            pars['TABLE'] = '%(PROTOP)s%(TNAME)s_bits'
5563        if self.HasContentsConstraint():
5564            pars['FN_VARIANT'] = ectx.default_containing_variant
5565            t = self.constr.GetContents(ectx)
5566            if t:
5567                if pars['FN_VARIANT'] in ('_pdu', '_pdu_new'):
5568                    t = ectx.field[t]['ethname']
5569                    pars['TYPE_REF_PROTO'] = ''
5570                    pars['TYPE_REF_TNAME'] = t
5571                    pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_TNAME)s'
5572                else:
5573                    t = ectx.type[t]['ethname']
5574                    pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
5575                    pars['TYPE_REF_TNAME'] = t
5576                    pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
5577            else:
5578                pars['TYPE_REF_FN'] = 'NULL'
5579        return pars
5580
5581    def eth_type_default_table(self, ectx, tname):
5582        #print ("eth_type_default_table(tname='%s')" % (tname))
5583        table = ''
5584        bits = self.eth_named_bits()
5585        if (bits):
5586            table = ectx.eth_bits(tname, bits)
5587        return table
5588
5589    def eth_type_default_body(self, ectx, tname):
5590        bits = self.eth_named_bits()
5591        if (ectx.Ber()):
5592            if (ectx.constraints_check and self.HasSizeConstraint()):
5593                body = ectx.eth_fn_call('dissect_%(ER)s_constrained_bitstring', ret='offset',
5594                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
5595                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(TABLE)s', '%s' %  len(bits),'%(HF_INDEX)s', '%(ETT_INDEX)s',),
5596                                             ('%(VAL_PTR)s',),))
5597            else:
5598                body = ectx.eth_fn_call('dissect_%(ER)s_bitstring', ret='offset',
5599                                        par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
5600                                             ('%(TABLE)s', '%s' % len(bits), '%(HF_INDEX)s', '%(ETT_INDEX)s',),
5601                                             ('%(VAL_PTR)s',),))
5602        elif (ectx.Per() or ectx.Oer()):
5603            if self.HasContentsConstraint():
5604                body = ectx.eth_fn_call('dissect_%(ER)s_bit_string_containing%(FN_VARIANT)s', ret='offset',
5605                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5606                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(TYPE_REF_FN)s'),))
5607            else:
5608                body = ectx.eth_fn_call('dissect_%(ER)s_bit_string', ret='offset',
5609                                        par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
5610                                             ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s','%(TABLE)s', '%s' %  len(bits), '%(VAL_PTR)s', '%(LEN_PTR)s'),))
5611        else:
5612            body = '#error Can not decode %s' % (tname)
5613        return body
5614
5615#--- BStringValue ------------------------------------------------------------
5616bstring_tab = {
5617  '0000' : '0',
5618  '0001' : '1',
5619  '0010' : '2',
5620  '0011' : '3',
5621  '0100' : '4',
5622  '0101' : '5',
5623  '0110' : '6',
5624  '0111' : '7',
5625  '1000' : '8',
5626  '1001' : '9',
5627  '1010' : 'A',
5628  '1011' : 'B',
5629  '1100' : 'C',
5630  '1101' : 'D',
5631  '1110' : 'E',
5632  '1111' : 'F',
5633}
5634class BStringValue (Value):
5635    def to_str(self, ectx):
5636        v = self.val[1:-2]
5637        if len(v) % 8:
5638            v += '0' * (8 - len(v) % 8)
5639        vv = '0x'
5640        for i in (list(range(0, len(v), 4))):
5641            vv += bstring_tab[v[i:i+4]]
5642        return vv
5643
5644#--- HStringValue ------------------------------------------------------------
5645class HStringValue (Value):
5646    def to_str(self, ectx):
5647        vv = '0x'
5648        vv += self.val[1:-2]
5649        return vv
5650    def __int__(self):
5651        return int(self.val[1:-2], 16)
5652
5653#--- FieldSpec ----------------------------------------------------------------
5654class FieldSpec (Node):
5655    def __init__(self,*args, **kw) :
5656        self.name = None
5657        Node.__init__ (self,*args, **kw)
5658
5659    def SetName(self, name):
5660        self.name = name
5661
5662    def get_repr(self):
5663        return ['#UNSUPPORTED_' + self.type]
5664
5665    def fld_repr(self):
5666        repr = [self.name]
5667        repr.extend(self.get_repr())
5668        return repr
5669
5670class TypeFieldSpec (FieldSpec):
5671    def get_repr(self):
5672        return []
5673
5674class FixedTypeValueFieldSpec (FieldSpec):
5675    def get_repr(self):
5676        if isinstance(self.typ, Type_Ref):
5677            repr = ['TypeReference', self.typ.val]
5678        else:
5679            repr = [self.typ.type]
5680        return repr
5681
5682class VariableTypeValueFieldSpec (FieldSpec):
5683    def get_repr(self):
5684        return ['_' + self.type]
5685
5686class FixedTypeValueSetFieldSpec (FieldSpec):
5687    def get_repr(self):
5688        return ['_' + self.type]
5689
5690class ObjectFieldSpec (FieldSpec):
5691    def get_repr(self):
5692        return ['ClassReference', self.cls.val]
5693
5694class ObjectSetFieldSpec (FieldSpec):
5695    def get_repr(self):
5696        return ['ClassReference', self.cls.val]
5697
5698#==============================================================================
5699
5700def p_module_list_1 (t):
5701    'module_list : module_list ModuleDefinition'
5702    t[0] = t[1] + [t[2]]
5703
5704def p_module_list_2 (t):
5705    'module_list : ModuleDefinition'
5706    t[0] = [t[1]]
5707
5708
5709#--- ITU-T Recommendation X.680 -----------------------------------------------
5710
5711
5712# 11 ASN.1 lexical items --------------------------------------------------------
5713
5714# 11.2 Type references
5715def p_type_ref (t):
5716    'type_ref : UCASE_IDENT'
5717    t[0] = Type_Ref(val=t[1])
5718
5719# 11.3 Identifiers
5720def p_identifier (t):
5721    'identifier : LCASE_IDENT'
5722    t[0] = t[1]
5723
5724# 11.4 Value references
5725# cause reduce/reduce conflict
5726#def p_valuereference (t):
5727#  'valuereference : LCASE_IDENT'
5728#  t[0] = Value_Ref(val=t[1])
5729
5730# 11.5 Module references
5731def p_modulereference (t):
5732    'modulereference : UCASE_IDENT'
5733    t[0] = t[1]
5734
5735
5736# 12 Module definition --------------------------------------------------------
5737
5738# 12.1
5739def p_ModuleDefinition (t):
5740    'ModuleDefinition : ModuleIdentifier DEFINITIONS TagDefault ASSIGNMENT ModuleBegin BEGIN ModuleBody END'
5741    t[0] = Module (ident = t[1], tag_def = t[3], body = t[7])
5742
5743def p_ModuleBegin (t):
5744    'ModuleBegin : '
5745    if t[-4].val == 'Remote-Operations-Information-Objects':
5746        x880_module_begin()
5747
5748def p_TagDefault_1 (t):
5749    '''TagDefault : EXPLICIT TAGS
5750                  | IMPLICIT TAGS
5751                  | AUTOMATIC TAGS '''
5752    t[0] = Default_Tags (dfl_tag = t[1])
5753
5754def p_TagDefault_2 (t):
5755    'TagDefault : '
5756    # 12.2 The "TagDefault" is taken as EXPLICIT TAGS if it is "empty".
5757    t[0] = Default_Tags (dfl_tag = 'EXPLICIT')
5758
5759def p_ModuleIdentifier_1 (t):
5760    'ModuleIdentifier : modulereference DefinitiveIdentifier' # name, oid
5761    t [0] = Node('module_ident', val = t[1], ident = t[2])
5762
5763def p_ModuleIdentifier_2 (t):
5764    'ModuleIdentifier : modulereference' # name, oid
5765    t [0] = Node('module_ident', val = t[1], ident = None)
5766
5767def p_DefinitiveIdentifier (t):
5768    'DefinitiveIdentifier : ObjectIdentifierValue'
5769    t[0] = t[1]
5770
5771#def p_module_ref (t):
5772#    'module_ref : UCASE_IDENT'
5773#    t[0] = t[1]
5774
5775def p_ModuleBody_1 (t):
5776    'ModuleBody : Exports Imports AssignmentList'
5777    t[0] = Module_Body (exports = t[1], imports = t[2], assign_list = t[3])
5778
5779def p_ModuleBody_2 (t):
5780    'ModuleBody : '
5781    t[0] = Node ('module_body', exports = [], imports = [], assign_list = [])
5782
5783def p_Exports_1 (t):
5784    'Exports : EXPORTS syms_exported SEMICOLON'
5785    t[0] = t[2]
5786
5787def p_Exports_2 (t):
5788    'Exports : EXPORTS ALL SEMICOLON'
5789    t[0] = [ 'ALL' ]
5790
5791def p_Exports_3 (t):
5792    'Exports : '
5793    t[0] = [ 'ALL' ]
5794
5795def p_syms_exported_1 (t):
5796    'syms_exported : exp_sym_list'
5797    t[0] = t[1]
5798
5799def p_syms_exported_2 (t):
5800    'syms_exported : '
5801    t[0] = []
5802
5803def p_exp_sym_list_1 (t):
5804    'exp_sym_list : Symbol'
5805    t[0] = [t[1]]
5806
5807def p_exp_sym_list_2 (t):
5808    'exp_sym_list : exp_sym_list COMMA Symbol'
5809    t[0] = t[1] + [t[3]]
5810
5811
5812def p_Imports_1 (t):
5813    'Imports : importsbegin IMPORTS SymbolsImported SEMICOLON'
5814    t[0] = t[3]
5815    global lcase_ident_assigned
5816    lcase_ident_assigned = {}
5817
5818def p_importsbegin (t):
5819    'importsbegin : '
5820    global lcase_ident_assigned
5821    global g_conform
5822    lcase_ident_assigned = {}
5823    lcase_ident_assigned.update(g_conform.use_item('ASSIGNED_ID', 'OBJECT_IDENTIFIER'))
5824
5825def p_Imports_2 (t):
5826    'Imports : '
5827    t[0] = []
5828
5829def p_SymbolsImported_1(t):
5830    'SymbolsImported : '
5831    t[0] = []
5832
5833def p_SymbolsImported_2 (t):
5834    'SymbolsImported : SymbolsFromModuleList'
5835    t[0] = t[1]
5836
5837def p_SymbolsFromModuleList_1 (t):
5838    'SymbolsFromModuleList : SymbolsFromModuleList SymbolsFromModule'
5839    t[0] = t[1] + [t[2]]
5840
5841def p_SymbolsFromModuleList_2 (t):
5842    'SymbolsFromModuleList : SymbolsFromModule'
5843    t[0] = [t[1]]
5844
5845def p_SymbolsFromModule (t):
5846    'SymbolsFromModule : SymbolList FROM GlobalModuleReference'
5847    t[0] = Node ('SymbolList', symbol_list = t[1], module = t[3])
5848    for s in (t[0].symbol_list):
5849        if (isinstance(s, Value_Ref)): lcase_ident_assigned[s.val] = t[3]
5850    import_symbols_from_module(t[0].module, t[0].symbol_list)
5851
5852def import_symbols_from_module(module, symbol_list):
5853    if module.val == 'Remote-Operations-Information-Objects':
5854        for i in range(len(symbol_list)):
5855            s = symbol_list[i]
5856            if isinstance(s, Type_Ref) or isinstance(s, Class_Ref):
5857                x880_import(s.val)
5858                if isinstance(s, Type_Ref) and is_class_ident(s.val):
5859                    symbol_list[i] = Class_Ref (val = s.val)
5860        return
5861    for i in range(len(symbol_list)):
5862        s = symbol_list[i]
5863        if isinstance(s, Type_Ref) and is_class_ident("$%s$%s" % (module.val, s.val)):
5864            import_class_from_module(module.val, s.val)
5865        if isinstance(s, Type_Ref) and is_class_ident(s.val):
5866            symbol_list[i] = Class_Ref (val = s.val)
5867
5868def p_GlobalModuleReference (t):
5869    'GlobalModuleReference : modulereference AssignedIdentifier'
5870    t [0] = Node('module_ident', val = t[1], ident = t[2])
5871
5872def p_AssignedIdentifier_1 (t):
5873    'AssignedIdentifier : ObjectIdentifierValue'
5874    t[0] = t[1]
5875
5876def p_AssignedIdentifier_2 (t):
5877    'AssignedIdentifier : LCASE_IDENT_ASSIGNED'
5878    t[0] = t[1]
5879
5880def p_AssignedIdentifier_3 (t):
5881    'AssignedIdentifier : '
5882    pass
5883
5884def p_SymbolList_1 (t):
5885    'SymbolList : Symbol'
5886    t[0] = [t[1]]
5887
5888def p_SymbolList_2 (t):
5889    'SymbolList : SymbolList COMMA Symbol'
5890    t[0] = t[1] + [t[3]]
5891
5892def p_Symbol (t):
5893    '''Symbol : Reference
5894              | ParameterizedReference'''
5895    t[0] = t[1]
5896
5897def p_Reference_1 (t):
5898    '''Reference : type_ref
5899                 | objectclassreference '''
5900    t[0] = t[1]
5901
5902def p_Reference_2 (t):
5903    '''Reference : LCASE_IDENT_ASSIGNED
5904                 | identifier '''  # instead of valuereference wich causes reduce/reduce conflict
5905    t[0] = Value_Ref(val=t[1])
5906
5907def p_AssignmentList_1 (t):
5908    'AssignmentList : AssignmentList Assignment'
5909    t[0] = t[1] + [t[2]]
5910
5911def p_AssignmentList_2 (t):
5912    'AssignmentList : Assignment SEMICOLON'
5913    t[0] = [t[1]]
5914
5915def p_AssignmentList_3 (t):
5916    'AssignmentList : Assignment'
5917    t[0] = [t[1]]
5918
5919def p_Assignment (t):
5920    '''Assignment : TypeAssignment
5921                  | ValueAssignment
5922                  | ValueSetTypeAssignment
5923                  | ObjectClassAssignment
5924                  | ObjectAssignment
5925                  | ObjectSetAssignment
5926                  | ParameterizedAssignment
5927                  | pyquote '''
5928    t[0] = t[1]
5929
5930
5931# 13 Referencing type and value definitions -----------------------------------
5932
5933# 13.1
5934def p_DefinedType (t):
5935    '''DefinedType : ExternalTypeReference
5936                   | type_ref
5937                   | ParameterizedType'''
5938    t[0] = t[1]
5939
5940def p_DefinedValue_1(t):
5941    '''DefinedValue : ExternalValueReference'''
5942    t[0] = t[1]
5943
5944def p_DefinedValue_2(t):
5945    '''DefinedValue : identifier '''  # instead of valuereference wich causes reduce/reduce conflict
5946    t[0] = Value_Ref(val=t[1])
5947
5948# 13.6
5949def p_ExternalTypeReference (t):
5950    'ExternalTypeReference : modulereference DOT type_ref'
5951    t[0] = Node ('ExternalTypeReference', module = t[1], typ = t[3])
5952
5953def p_ExternalValueReference (t):
5954    'ExternalValueReference : modulereference DOT identifier'
5955    t[0] = Node ('ExternalValueReference', module = t[1], ident = t[3])
5956
5957
5958# 15 Assigning types and values -----------------------------------------------
5959
5960# 15.1
5961def p_TypeAssignment (t):
5962    'TypeAssignment : UCASE_IDENT ASSIGNMENT Type'
5963    t[0] = t[3]
5964    t[0].SetName(t[1])
5965
5966# 15.2
5967def p_ValueAssignment (t):
5968    'ValueAssignment : LCASE_IDENT ValueType ASSIGNMENT Value'
5969    t[0] = ValueAssignment(ident = t[1], typ = t[2], val = t[4])
5970
5971# only "simple" types are supported to simplify grammer
5972def p_ValueType (t):
5973    '''ValueType : type_ref
5974                 | BooleanType
5975                 | IntegerType
5976                 | ObjectIdentifierType
5977                 | OctetStringType
5978                 | RealType '''
5979
5980    t[0] = t[1]
5981
5982# 15.6
5983def p_ValueSetTypeAssignment (t):
5984    'ValueSetTypeAssignment : UCASE_IDENT ValueType ASSIGNMENT ValueSet'
5985    t[0] = Node('ValueSetTypeAssignment', name=t[1], typ=t[2], val=t[4])
5986
5987# 15.7
5988def p_ValueSet (t):
5989    'ValueSet : lbraceignore rbraceignore'
5990    t[0] = None
5991
5992
5993# 16 Definition of types and values -------------------------------------------
5994
5995# 16.1
5996def p_Type (t):
5997    '''Type : BuiltinType
5998            | ReferencedType
5999            | ConstrainedType'''
6000    t[0] = t[1]
6001
6002# 16.2
6003def p_BuiltinType (t):
6004    '''BuiltinType : AnyType
6005                   | BitStringType
6006                   | BooleanType
6007                   | CharacterStringType
6008                   | ChoiceType
6009                   | EmbeddedPDVType
6010                   | EnumeratedType
6011                   | ExternalType
6012                   | InstanceOfType
6013                   | IntegerType
6014                   | NullType
6015                   | ObjectClassFieldType
6016                   | ObjectIdentifierType
6017                   | OctetStringType
6018                   | RealType
6019                   | RelativeOIDType
6020                   | SequenceType
6021                   | SequenceOfType
6022                   | SetType
6023                   | SetOfType
6024                   | TaggedType'''
6025    t[0] = t[1]
6026
6027# 16.3
6028def p_ReferencedType (t):
6029    '''ReferencedType : DefinedType
6030                      | UsefulType
6031                      | SelectionType'''
6032    t[0] = t[1]
6033
6034# 16.5
6035def p_NamedType (t):
6036    'NamedType : identifier Type'
6037    t[0] = t[2]
6038    t[0].SetName (t[1])
6039
6040# 16.7
6041def p_Value (t):
6042    '''Value : BuiltinValue
6043             | ReferencedValue
6044             | ObjectClassFieldValue'''
6045    t[0] = t[1]
6046
6047# 16.9
6048def p_BuiltinValue (t):
6049    '''BuiltinValue : BooleanValue
6050                    | ChoiceValue
6051                    | IntegerValue
6052                    | ObjectIdentifierValue
6053                    | RealValue
6054                    | SequenceValue
6055                    | hex_string
6056                    | binary_string
6057                    | char_string''' # XXX we don't support {data} here
6058    t[0] = t[1]
6059
6060# 16.11
6061def p_ReferencedValue (t):
6062    '''ReferencedValue : DefinedValue
6063                       | ValueFromObject'''
6064    t[0] = t[1]
6065
6066# 16.13
6067#def p_NamedValue (t):
6068#  'NamedValue : identifier Value'
6069#  t[0] = Node ('NamedValue', ident = t[1], value = t[2])
6070
6071
6072# 17 Notation for the boolean type --------------------------------------------
6073
6074# 17.1
6075def p_BooleanType (t):
6076    'BooleanType : BOOLEAN'
6077    t[0] = BooleanType ()
6078
6079# 17.2
6080def p_BooleanValue (t):
6081    '''BooleanValue : TRUE
6082                    | FALSE'''
6083    t[0] = t[1]
6084
6085
6086# 18 Notation for the integer type --------------------------------------------
6087
6088# 18.1
6089def p_IntegerType_1 (t):
6090    'IntegerType : INTEGER'
6091    t[0] = IntegerType (named_list = None)
6092
6093def p_IntegerType_2 (t):
6094    'IntegerType : INTEGER LBRACE NamedNumberList RBRACE'
6095    t[0] = IntegerType(named_list = t[3])
6096
6097def p_NamedNumberList_1 (t):
6098    'NamedNumberList : NamedNumber'
6099    t[0] = [t[1]]
6100
6101def p_NamedNumberList_2 (t):
6102    'NamedNumberList : NamedNumberList COMMA NamedNumber'
6103    t[0] = t[1] + [t[3]]
6104
6105def p_NamedNumber (t):
6106    '''NamedNumber : identifier LPAREN SignedNumber RPAREN
6107                   | identifier LPAREN DefinedValue RPAREN'''
6108    t[0] = NamedNumber(ident = t[1], val = t[3])
6109
6110def p_SignedNumber_1 (t):
6111    'SignedNumber : NUMBER'
6112    t[0] = t [1]
6113
6114def p_SignedNumber_2 (t):
6115    'SignedNumber : MINUS NUMBER'
6116    t[0] = '-' + t[2]
6117
6118# 18.9
6119def p_IntegerValue (t):
6120    'IntegerValue : SignedNumber'
6121    t[0] = t [1]
6122
6123# 19 Notation for the enumerated type -----------------------------------------
6124
6125# 19.1
6126def p_EnumeratedType (t):
6127    'EnumeratedType : ENUMERATED LBRACE Enumerations RBRACE'
6128    t[0] = EnumeratedType (val = t[3]['val'], ext = t[3]['ext'])
6129
6130def p_Enumerations_1 (t):
6131    'Enumerations : Enumeration'
6132    t[0] = { 'val' : t[1], 'ext' : None }
6133
6134def p_Enumerations_2 (t):
6135    'Enumerations : Enumeration COMMA ELLIPSIS ExceptionSpec'
6136    t[0] = { 'val' : t[1], 'ext' : [] }
6137
6138def p_Enumerations_3 (t):
6139    'Enumerations : Enumeration COMMA ELLIPSIS ExceptionSpec COMMA Enumeration'
6140    t[0] = { 'val' : t[1], 'ext' : t[6] }
6141
6142def p_Enumeration_1 (t):
6143    'Enumeration : EnumerationItem'
6144    t[0] = [t[1]]
6145
6146def p_Enumeration_2 (t):
6147    'Enumeration : Enumeration COMMA EnumerationItem'
6148    t[0] = t[1] + [t[3]]
6149
6150def p_EnumerationItem (t):
6151    '''EnumerationItem : Identifier
6152                       | NamedNumber'''
6153    t[0] = t[1]
6154
6155def p_Identifier (t):
6156    'Identifier : identifier'
6157    t[0] = Node ('Identifier', ident = t[1])
6158
6159
6160# 20 Notation for the real type -----------------------------------------------
6161
6162# 20.1
6163def p_RealType (t):
6164    'RealType : REAL'
6165    t[0] = RealType ()
6166
6167# 20.6
6168def p_RealValue (t):
6169    '''RealValue : REAL_NUMBER
6170                 | SpecialRealValue'''
6171    t[0] = t [1]
6172
6173def p_SpecialRealValue (t):
6174    '''SpecialRealValue : PLUS_INFINITY
6175                        | MINUS_INFINITY'''
6176    t[0] = t[1]
6177
6178
6179# 21 Notation for the bitstring type ------------------------------------------
6180
6181# 21.1
6182def p_BitStringType_1 (t):
6183    'BitStringType : BIT STRING'
6184    t[0] = BitStringType (named_list = None)
6185
6186def p_BitStringType_2 (t):
6187    'BitStringType : BIT STRING LBRACE NamedBitList RBRACE'
6188    t[0] = BitStringType (named_list = t[4])
6189
6190def p_NamedBitList_1 (t):
6191    'NamedBitList : NamedBit'
6192    t[0] = [t[1]]
6193
6194def p_NamedBitList_2 (t):
6195    'NamedBitList : NamedBitList COMMA NamedBit'
6196    t[0] = t[1] + [t[3]]
6197
6198def p_NamedBit (t):
6199    '''NamedBit : identifier LPAREN NUMBER RPAREN
6200                | identifier LPAREN DefinedValue RPAREN'''
6201    t[0] = NamedNumber (ident = t[1], val = t[3])
6202
6203
6204# 22 Notation for the octetstring type ----------------------------------------
6205
6206# 22.1
6207def p_OctetStringType (t):
6208    'OctetStringType : OCTET STRING'
6209    t[0] = OctetStringType ()
6210
6211
6212# 23 Notation for the null type -----------------------------------------------
6213
6214# 23.1
6215def p_NullType (t):
6216    'NullType : NULL'
6217    t[0] = NullType ()
6218
6219# 23.3
6220def p_NullValue (t):
6221    'NullValue : NULL'
6222    t[0] = NullValue ()
6223
6224
6225# 24 Notation for sequence types ----------------------------------------------
6226
6227# 24.1
6228def p_SequenceType_1 (t):
6229    'SequenceType : SEQUENCE LBRACE RBRACE'
6230    t[0] = SequenceType (elt_list = [])
6231
6232def p_SequenceType_2 (t):
6233    'SequenceType : SEQUENCE LBRACE ComponentTypeLists RBRACE'
6234    t[0] = SequenceType (elt_list = t[3]['elt_list'])
6235    if 'ext_list' in t[3]:
6236        t[0].ext_list = t[3]['ext_list']
6237    if 'elt_list2' in t[3]:
6238        t[0].elt_list2 = t[3]['elt_list2']
6239
6240def p_ExtensionAndException_1 (t):
6241    'ExtensionAndException : ELLIPSIS'
6242    t[0] = []
6243
6244def p_OptionalExtensionMarker_1 (t):
6245    'OptionalExtensionMarker : COMMA ELLIPSIS'
6246    t[0] = True
6247
6248def p_OptionalExtensionMarker_2 (t):
6249    'OptionalExtensionMarker : '
6250    t[0] = False
6251
6252def p_ComponentTypeLists_1 (t):
6253    'ComponentTypeLists : ComponentTypeList'
6254    t[0] = {'elt_list' : t[1]}
6255
6256def p_ComponentTypeLists_2 (t):
6257    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException OptionalExtensionMarker'
6258    t[0] = {'elt_list' : t[1], 'ext_list' : []}
6259
6260def p_ComponentTypeLists_3 (t):
6261    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionAdditionList OptionalExtensionMarker'
6262    t[0] = {'elt_list' : t[1], 'ext_list' : t[4]}
6263
6264def p_ComponentTypeLists_4 (t):
6265    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionEndMarker COMMA ComponentTypeList'
6266    t[0] = {'elt_list' : t[1], 'ext_list' : [], 'elt_list2' : t[6]}
6267
6268def p_ComponentTypeLists_5 (t):
6269    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionAdditionList ExtensionEndMarker COMMA ComponentTypeList'
6270    t[0] = {'elt_list' : t[1], 'ext_list' : t[4], 'elt_list2' : t[7]}
6271
6272def p_ComponentTypeLists_6 (t):
6273    'ComponentTypeLists : ExtensionAndException OptionalExtensionMarker'
6274    t[0] = {'elt_list' : [], 'ext_list' : []}
6275
6276def p_ComponentTypeLists_7 (t):
6277    'ComponentTypeLists : ExtensionAndException ExtensionAdditionList OptionalExtensionMarker'
6278    t[0] = {'elt_list' : [], 'ext_list' : t[2]}
6279
6280def p_ExtensionEndMarker (t):
6281    'ExtensionEndMarker : COMMA ELLIPSIS'
6282    pass
6283
6284def p_ExtensionAdditionList_1 (t):
6285    'ExtensionAdditionList : COMMA ExtensionAddition'
6286    t[0] = [t[2]]
6287
6288def p_ExtensionAdditionList_2 (t):
6289    'ExtensionAdditionList : ExtensionAdditionList COMMA ExtensionAddition'
6290    t[0] = t[1] + [t[3]]
6291
6292def p_ExtensionAddition_1 (t):
6293    'ExtensionAddition : ExtensionAdditionGroup'
6294    t[0] = Node ('elt_type', val = t[1], optional = 0)
6295
6296def p_ExtensionAddition_2 (t):
6297    'ExtensionAddition : ComponentType'
6298    t[0] = t[1]
6299
6300def p_ExtensionAdditionGroup (t):
6301    'ExtensionAdditionGroup : LVERBRACK VersionNumber ComponentTypeList RVERBRACK'
6302    t[0] = ExtensionAdditionGroup (ver = t[2], elt_list = t[3])
6303
6304def p_VersionNumber_1 (t):
6305    'VersionNumber : '
6306
6307def p_VersionNumber_2 (t):
6308    'VersionNumber : NUMBER COLON'
6309    t[0] = t[1]
6310
6311def p_ComponentTypeList_1 (t):
6312    'ComponentTypeList : ComponentType'
6313    t[0] = [t[1]]
6314
6315def p_ComponentTypeList_2 (t):
6316    'ComponentTypeList : ComponentTypeList COMMA ComponentType'
6317    t[0] = t[1] + [t[3]]
6318
6319def p_ComponentType_1 (t):
6320    'ComponentType : NamedType'
6321    t[0] = Node ('elt_type', val = t[1], optional = 0)
6322
6323def p_ComponentType_2 (t):
6324    'ComponentType : NamedType OPTIONAL'
6325    t[0] = Node ('elt_type', val = t[1], optional = 1)
6326
6327def p_ComponentType_3 (t):
6328    'ComponentType : NamedType DEFAULT DefaultValue'
6329    t[0] = Node ('elt_type', val = t[1], optional = 1, default = t[3])
6330
6331def p_ComponentType_4 (t):
6332    'ComponentType : COMPONENTS OF Type'
6333    t[0] = Node ('components_of', typ = t[3])
6334
6335def p_DefaultValue_1 (t):
6336    '''DefaultValue : ReferencedValue
6337                    | BooleanValue
6338                    | ChoiceValue
6339                    | IntegerValue
6340                    | RealValue
6341                    | hex_string
6342                    | binary_string
6343                    | char_string
6344                    | ObjectClassFieldValue'''
6345    t[0] = t[1]
6346
6347def p_DefaultValue_2 (t):
6348    'DefaultValue : lbraceignore rbraceignore'
6349    t[0] = ''
6350
6351# 24.17
6352def p_SequenceValue_1 (t):
6353    'SequenceValue : LBRACE RBRACE'
6354    t[0] = []
6355
6356
6357#def p_SequenceValue_2 (t):
6358#  'SequenceValue : LBRACE ComponentValueList RBRACE'
6359#  t[0] = t[2]
6360
6361#def p_ComponentValueList_1 (t):
6362#    'ComponentValueList : NamedValue'
6363#    t[0] = [t[1]]
6364
6365#def p_ComponentValueList_2 (t):
6366#    'ComponentValueList : ComponentValueList COMMA NamedValue'
6367#    t[0] = t[1] + [t[3]]
6368
6369
6370# 25 Notation for sequence-of types -------------------------------------------
6371
6372# 25.1
6373def p_SequenceOfType (t):
6374    '''SequenceOfType : SEQUENCE OF Type
6375                      | SEQUENCE OF NamedType'''
6376    t[0] = SequenceOfType (val = t[3], size_constr = None)
6377
6378
6379# 26 Notation for set types ---------------------------------------------------
6380
6381# 26.1
6382def p_SetType_1 (t):
6383    'SetType : SET LBRACE RBRACE'
6384    t[0] = SetType (elt_list = [])
6385
6386def p_SetType_2 (t):
6387    'SetType : SET LBRACE ComponentTypeLists RBRACE'
6388    t[0] = SetType (elt_list = t[3]['elt_list'])
6389    if 'ext_list' in t[3]:
6390        t[0].ext_list = t[3]['ext_list']
6391    if 'elt_list2' in t[3]:
6392        t[0].elt_list2 = t[3]['elt_list2']
6393
6394
6395# 27 Notation for set-of types ------------------------------------------------
6396
6397# 27.1
6398def p_SetOfType (t):
6399    '''SetOfType : SET OF Type
6400                 | SET OF NamedType'''
6401    t[0] = SetOfType (val = t[3])
6402
6403# 28 Notation for choice types ------------------------------------------------
6404
6405# 28.1
6406def p_ChoiceType (t):
6407    'ChoiceType : CHOICE LBRACE AlternativeTypeLists RBRACE'
6408    if 'ext_list' in t[3]:
6409        t[0] = ChoiceType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list'])
6410    else:
6411        t[0] = ChoiceType (elt_list = t[3]['elt_list'])
6412
6413def p_AlternativeTypeLists_1 (t):
6414    'AlternativeTypeLists : AlternativeTypeList'
6415    t[0] = {'elt_list' : t[1]}
6416
6417def p_AlternativeTypeLists_2 (t):
6418    'AlternativeTypeLists : AlternativeTypeList COMMA ExtensionAndException ExtensionAdditionAlternatives OptionalExtensionMarker'
6419    t[0] = {'elt_list' : t[1], 'ext_list' : t[4]}
6420
6421def p_ExtensionAdditionAlternatives_1 (t):
6422    'ExtensionAdditionAlternatives : ExtensionAdditionAlternativesList'
6423    t[0] = t[1]
6424
6425def p_ExtensionAdditionAlternatives_2 (t):
6426    'ExtensionAdditionAlternatives : '
6427    t[0] = []
6428
6429def p_ExtensionAdditionAlternativesList_1 (t):
6430    'ExtensionAdditionAlternativesList : COMMA ExtensionAdditionAlternative'
6431    t[0] = t[2]
6432
6433def p_ExtensionAdditionAlternativesList_2 (t):
6434    'ExtensionAdditionAlternativesList : ExtensionAdditionAlternativesList COMMA ExtensionAdditionAlternative'
6435    t[0] = t[1] + t[3]
6436
6437def p_ExtensionAdditionAlternative_1 (t):
6438    'ExtensionAdditionAlternative : NamedType'
6439    t[0] = [t[1]]
6440
6441def p_ExtensionAdditionAlternative_2 (t):
6442    'ExtensionAdditionAlternative : ExtensionAdditionAlternativesGroup'
6443    t[0] = t[1]
6444
6445def p_ExtensionAdditionAlternativesGroup (t):
6446    'ExtensionAdditionAlternativesGroup : LVERBRACK VersionNumber AlternativeTypeList RVERBRACK'
6447    t[0] = t[3]
6448
6449def p_AlternativeTypeList_1 (t):
6450    'AlternativeTypeList : NamedType'
6451    t[0] = [t[1]]
6452
6453def p_AlternativeTypeList_2 (t):
6454    'AlternativeTypeList : AlternativeTypeList COMMA NamedType'
6455    t[0] = t[1] + [t[3]]
6456
6457# 28.10
6458def p_ChoiceValue_1 (t):
6459    '''ChoiceValue : identifier COLON Value
6460                   | identifier COLON NullValue '''
6461    val = t[3]
6462    if not isinstance(val, Value):
6463        val = Value(val=val)
6464    t[0] = ChoiceValue (choice = t[1], val = val)
6465
6466# 29 Notation for selection types
6467
6468# 29.1
6469def p_SelectionType (t): #
6470    'SelectionType : identifier LT Type'
6471    t[0] = SelectionType (typ = t[3], sel = t[1])
6472
6473# 30 Notation for tagged types ------------------------------------------------
6474
6475# 30.1
6476def p_TaggedType_1 (t):
6477    'TaggedType : Tag Type'
6478    t[1].mode = 'default'
6479    t[0] = t[2]
6480    t[0].AddTag(t[1])
6481
6482def p_TaggedType_2 (t):
6483    '''TaggedType : Tag IMPLICIT Type
6484                  | Tag EXPLICIT Type'''
6485    t[1].mode = t[2]
6486    t[0] = t[3]
6487    t[0].AddTag(t[1])
6488
6489def p_Tag (t):
6490    'Tag : LBRACK Class ClassNumber RBRACK'
6491    t[0] = Tag(cls = t[2], num = t[3])
6492
6493def p_ClassNumber_1 (t):
6494    'ClassNumber : number'
6495    t[0] = t[1]
6496
6497def p_ClassNumber_2 (t):
6498    'ClassNumber : DefinedValue'
6499    t[0] = t[1]
6500
6501def p_Class_1 (t):
6502    '''Class : UNIVERSAL
6503             | APPLICATION
6504             | PRIVATE'''
6505    t[0] = t[1]
6506
6507def p_Class_2 (t):
6508    'Class :'
6509    t[0] = 'CONTEXT'
6510
6511
6512# 31 Notation for the object identifier type ----------------------------------
6513
6514# 31.1
6515def p_ObjectIdentifierType (t):
6516    'ObjectIdentifierType : OBJECT IDENTIFIER'
6517    t[0] = ObjectIdentifierType()
6518
6519# 31.3
6520def p_ObjectIdentifierValue (t):
6521    'ObjectIdentifierValue : LBRACE oid_comp_list RBRACE'
6522    t[0] = ObjectIdentifierValue (comp_list=t[2])
6523
6524def p_oid_comp_list_1 (t):
6525    'oid_comp_list : oid_comp_list ObjIdComponents'
6526    t[0] = t[1] + [t[2]]
6527
6528def p_oid_comp_list_2 (t):
6529    'oid_comp_list : ObjIdComponents'
6530    t[0] = [t[1]]
6531
6532def p_ObjIdComponents (t):
6533    '''ObjIdComponents : NameForm
6534                       | NumberForm
6535                       | NameAndNumberForm'''
6536    t[0] = t[1]
6537
6538def p_NameForm (t):
6539    '''NameForm : LCASE_IDENT
6540                | LCASE_IDENT_ASSIGNED'''
6541    t [0] = t[1]
6542
6543def p_NumberForm (t):
6544    '''NumberForm : NUMBER'''
6545#                | DefinedValue'''
6546    t [0] = t[1]
6547
6548def p_NameAndNumberForm (t):
6549    '''NameAndNumberForm : LCASE_IDENT_ASSIGNED LPAREN NumberForm RPAREN
6550                         | LCASE_IDENT LPAREN NumberForm RPAREN'''
6551    t[0] = Node('name_and_number', ident = t[1], number = t[3])
6552
6553# 32 Notation for the relative object identifier type -------------------------
6554
6555# 32.1
6556def p_RelativeOIDType (t):
6557    'RelativeOIDType : RELATIVE_OID'
6558    t[0] = RelativeOIDType()
6559
6560# 33 Notation for the embedded-pdv type ---------------------------------------
6561
6562# 33.1
6563def p_EmbeddedPDVType (t):
6564    'EmbeddedPDVType : EMBEDDED PDV'
6565    t[0] = EmbeddedPDVType()
6566
6567# 34 Notation for the external type -------------------------------------------
6568
6569# 34.1
6570def p_ExternalType (t):
6571    'ExternalType : EXTERNAL'
6572    t[0] = ExternalType()
6573
6574# 36 Notation for character string types --------------------------------------
6575
6576# 36.1
6577def p_CharacterStringType (t):
6578    '''CharacterStringType : RestrictedCharacterStringType
6579    | UnrestrictedCharacterStringType'''
6580    t[0] = t[1]
6581
6582
6583# 37 Definition of restricted character string types --------------------------
6584
6585def p_RestrictedCharacterStringType_1 (t):
6586    'RestrictedCharacterStringType : BMPString'
6587    t[0] = BMPStringType ()
6588def p_RestrictedCharacterStringType_2 (t):
6589    'RestrictedCharacterStringType : GeneralString'
6590    t[0] = GeneralStringType ()
6591def p_RestrictedCharacterStringType_3 (t):
6592    'RestrictedCharacterStringType : GraphicString'
6593    t[0] = GraphicStringType ()
6594def p_RestrictedCharacterStringType_4 (t):
6595    'RestrictedCharacterStringType : IA5String'
6596    t[0] = IA5StringType ()
6597def p_RestrictedCharacterStringType_5 (t):
6598    'RestrictedCharacterStringType : ISO646String'
6599    t[0] = ISO646StringType ()
6600def p_RestrictedCharacterStringType_6 (t):
6601    'RestrictedCharacterStringType : NumericString'
6602    t[0] = NumericStringType ()
6603def p_RestrictedCharacterStringType_7 (t):
6604    'RestrictedCharacterStringType : PrintableString'
6605    t[0] = PrintableStringType ()
6606def p_RestrictedCharacterStringType_8 (t):
6607    'RestrictedCharacterStringType : TeletexString'
6608    t[0] = TeletexStringType ()
6609def p_RestrictedCharacterStringType_9 (t):
6610    'RestrictedCharacterStringType : T61String'
6611    t[0] = T61StringType ()
6612def p_RestrictedCharacterStringType_10 (t):
6613    'RestrictedCharacterStringType : UniversalString'
6614    t[0] = UniversalStringType ()
6615def p_RestrictedCharacterStringType_11 (t):
6616    'RestrictedCharacterStringType : UTF8String'
6617    t[0] = UTF8StringType ()
6618def p_RestrictedCharacterStringType_12 (t):
6619    'RestrictedCharacterStringType : VideotexString'
6620    t[0] = VideotexStringType ()
6621def p_RestrictedCharacterStringType_13 (t):
6622    'RestrictedCharacterStringType : VisibleString'
6623    t[0] = VisibleStringType ()
6624
6625
6626# 40 Definition of unrestricted character string types ------------------------
6627
6628# 40.1
6629def p_UnrestrictedCharacterStringType (t):
6630    'UnrestrictedCharacterStringType : CHARACTER STRING'
6631    t[0] = UnrestrictedCharacterStringType ()
6632
6633
6634# 41 Notation for types defined in clauses 42 to 44 ---------------------------
6635
6636# 42 Generalized time ---------------------------------------------------------
6637
6638def p_UsefulType_1 (t):
6639    'UsefulType : GeneralizedTime'
6640    t[0] = GeneralizedTime()
6641
6642# 43 Universal time -----------------------------------------------------------
6643
6644def p_UsefulType_2 (t):
6645    'UsefulType : UTCTime'
6646    t[0] = UTCTime()
6647
6648# 44 The object descriptor type -----------------------------------------------
6649
6650def p_UsefulType_3 (t):
6651    'UsefulType : ObjectDescriptor'
6652    t[0] = ObjectDescriptor()
6653
6654
6655# 45 Constrained types --------------------------------------------------------
6656
6657# 45.1
6658def p_ConstrainedType_1 (t):
6659    'ConstrainedType : Type Constraint'
6660    t[0] = t[1]
6661    t[0].AddConstraint(t[2])
6662
6663def p_ConstrainedType_2 (t):
6664    'ConstrainedType : TypeWithConstraint'
6665    t[0] = t[1]
6666
6667# 45.5
6668def p_TypeWithConstraint_1 (t):
6669    '''TypeWithConstraint : SET Constraint OF Type
6670                          | SET SizeConstraint OF Type'''
6671    t[0] = SetOfType (val = t[4], constr = t[2])
6672
6673def p_TypeWithConstraint_2 (t):
6674    '''TypeWithConstraint : SEQUENCE Constraint OF Type
6675                          | SEQUENCE SizeConstraint OF Type'''
6676    t[0] = SequenceOfType (val = t[4], constr = t[2])
6677
6678def p_TypeWithConstraint_3 (t):
6679    '''TypeWithConstraint : SET Constraint OF NamedType
6680                          | SET SizeConstraint OF NamedType'''
6681    t[0] = SetOfType (val = t[4], constr = t[2])
6682
6683def p_TypeWithConstraint_4 (t):
6684    '''TypeWithConstraint : SEQUENCE Constraint OF NamedType
6685                          | SEQUENCE SizeConstraint OF NamedType'''
6686    t[0] = SequenceOfType (val = t[4], constr = t[2])
6687
6688# 45.6
6689# 45.7
6690def p_Constraint (t):
6691    'Constraint : LPAREN ConstraintSpec ExceptionSpec RPAREN'
6692    t[0] = t[2]
6693
6694def p_ConstraintSpec (t):
6695    '''ConstraintSpec : ElementSetSpecs
6696                      | GeneralConstraint'''
6697    t[0] = t[1]
6698
6699# 46 Element set specification ------------------------------------------------
6700
6701# 46.1
6702def p_ElementSetSpecs_1 (t):
6703    'ElementSetSpecs : RootElementSetSpec'
6704    t[0] = t[1]
6705
6706def p_ElementSetSpecs_2 (t):
6707    'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS'
6708    t[0] = t[1]
6709    t[0].ext = True
6710
6711def p_ElementSetSpecs_3 (t):
6712    'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS COMMA AdditionalElementSetSpec'
6713    t[0] = t[1]
6714    t[0].ext = True
6715
6716def p_RootElementSetSpec (t):
6717    'RootElementSetSpec : ElementSetSpec'
6718    t[0] = t[1]
6719
6720def p_AdditionalElementSetSpec (t):
6721    'AdditionalElementSetSpec : ElementSetSpec'
6722    t[0] = t[1]
6723
6724def p_ElementSetSpec (t):
6725    'ElementSetSpec : Unions'
6726    t[0] = t[1]
6727
6728def p_Unions_1 (t):
6729    'Unions : Intersections'
6730    t[0] = t[1]
6731
6732def p_Unions_2 (t):
6733    'Unions : UElems UnionMark Intersections'
6734    t[0] = Constraint(type = 'Union', subtype = [t[1], t[3]])
6735
6736def p_UElems (t):
6737    'UElems : Unions'
6738    t[0] = t[1]
6739
6740def p_Intersections_1 (t):
6741    'Intersections : IntersectionElements'
6742    t[0] = t[1]
6743
6744def p_Intersections_2 (t):
6745    'Intersections : IElems IntersectionMark IntersectionElements'
6746    t[0] = Constraint(type = 'Intersection', subtype = [t[1], t[3]])
6747
6748def p_IElems (t):
6749    'IElems : Intersections'
6750    t[0] = t[1]
6751
6752def p_IntersectionElements (t):
6753    'IntersectionElements : Elements'
6754    t[0] = t[1]
6755
6756def p_UnionMark (t):
6757    '''UnionMark : BAR
6758                 | UNION'''
6759
6760def p_IntersectionMark (t):
6761    '''IntersectionMark : CIRCUMFLEX
6762                        | INTERSECTION'''
6763
6764# 46.5
6765def p_Elements_1 (t):
6766    'Elements : SubtypeElements'
6767    t[0] = t[1]
6768
6769def p_Elements_2 (t):
6770    'Elements : LPAREN ElementSetSpec RPAREN'
6771    t[0] = t[2]
6772
6773# 47 Subtype elements ---------------------------------------------------------
6774
6775# 47.1 General
6776def p_SubtypeElements (t):
6777    '''SubtypeElements : SingleValue
6778                       | ContainedSubtype
6779                       | ValueRange
6780                       | PermittedAlphabet
6781                       | SizeConstraint
6782                       | TypeConstraint
6783                       | InnerTypeConstraints
6784                       | PatternConstraint'''
6785    t[0] = t[1]
6786
6787# 47.2 Single value
6788# 47.2.1
6789def p_SingleValue (t):
6790    'SingleValue : Value'
6791    t[0] = Constraint(type = 'SingleValue', subtype = t[1])
6792
6793# 47.3 Contained subtype
6794# 47.3.1
6795def p_ContainedSubtype (t):
6796    'ContainedSubtype : Includes Type'
6797    t[0] = Constraint(type = 'ContainedSubtype', subtype = t[2])
6798
6799def p_Includes (t):
6800    '''Includes : INCLUDES
6801                | '''
6802
6803# 47.4 Value range
6804# 47.4.1
6805def p_ValueRange (t):
6806    'ValueRange : LowerEndpoint RANGE UpperEndpoint'
6807    t[0] = Constraint(type = 'ValueRange', subtype = [t[1], t[3]])
6808
6809# 47.4.3
6810def p_LowerEndpoint_1 (t):
6811    'LowerEndpoint : LowerEndValue'
6812    t[0] = t[1]
6813
6814def p_LowerEndpoint_2 (t):
6815    'LowerEndpoint : LowerEndValue LT'
6816    t[0] = t[1] # but not inclusive range
6817
6818def p_UpperEndpoint_1 (t):
6819    'UpperEndpoint : UpperEndValue'
6820    t[0] = t[1]
6821
6822def p_UpperEndpoint_2 (t):
6823    'UpperEndpoint : LT UpperEndValue'
6824    t[0] = t[1] # but not inclusive range
6825
6826# 47.4.4
6827def p_LowerEndValue (t):
6828    '''LowerEndValue : Value
6829                     | MIN'''
6830    t[0] = t[1] # XXX
6831
6832def p_UpperEndValue (t):
6833    '''UpperEndValue : Value
6834                      | MAX'''
6835    t[0] = t[1]
6836
6837# 47.5 Size constraint
6838# 47.5.1
6839def p_SizeConstraint (t):
6840    'SizeConstraint : SIZE Constraint'
6841    t[0] = Constraint (type = 'Size', subtype = t[2])
6842
6843# 47.6 Type constraint
6844# 47.6.1
6845def p_TypeConstraint (t):
6846    'TypeConstraint : Type'
6847    t[0] = Constraint (type = 'Type', subtype = t[1])
6848
6849# 47.7 Permitted alphabet
6850# 47.7.1
6851def p_PermittedAlphabet (t):
6852    'PermittedAlphabet : FROM Constraint'
6853    t[0] = Constraint (type = 'From', subtype = t[2])
6854
6855# 47.8 Inner subtyping
6856# 47.8.1
6857def p_InnerTypeConstraints (t):
6858    '''InnerTypeConstraints : WITH COMPONENT SingleTypeConstraint
6859                            | WITH COMPONENTS MultipleTypeConstraints'''
6860    pass # ignore PER invisible constraint
6861
6862# 47.8.3
6863def p_SingleTypeConstraint (t):
6864    'SingleTypeConstraint : Constraint'
6865    t[0] = t[1]
6866
6867# 47.8.4
6868def p_MultipleTypeConstraints (t):
6869    '''MultipleTypeConstraints : FullSpecification
6870                               | PartialSpecification'''
6871    t[0] = t[1]
6872
6873def p_FullSpecification (t):
6874    'FullSpecification : LBRACE TypeConstraints RBRACE'
6875    t[0] = t[2]
6876
6877def p_PartialSpecification (t):
6878    'PartialSpecification : LBRACE ELLIPSIS COMMA TypeConstraints RBRACE'
6879    t[0] = t[4]
6880
6881def p_TypeConstraints_1 (t):
6882    'TypeConstraints : named_constraint'
6883    t [0] = [t[1]]
6884
6885def p_TypeConstraints_2 (t):
6886    'TypeConstraints : TypeConstraints COMMA named_constraint'
6887    t[0] = t[1] + [t[3]]
6888
6889def p_named_constraint_1 (t):
6890    'named_constraint : identifier constraint'
6891    return Node ('named_constraint', ident = t[1], constr = t[2])
6892
6893def p_named_constraint_2 (t):
6894    'named_constraint : constraint'
6895    return Node ('named_constraint', constr = t[1])
6896
6897def p_constraint (t):
6898    'constraint : value_constraint presence_constraint'
6899    t[0] = Node ('constraint', value = t[1], presence = t[2])
6900
6901def p_value_constraint_1 (t):
6902    'value_constraint : Constraint'
6903    t[0] = t[1]
6904
6905def p_value_constraint_2 (t):
6906    'value_constraint : '
6907    pass
6908
6909def p_presence_constraint_1 (t):
6910    '''presence_constraint : PRESENT
6911                 | ABSENT
6912                 | OPTIONAL'''
6913    t[0] = t[1]
6914
6915def p_presence_constraint_2 (t):
6916    '''presence_constraint : '''
6917    pass
6918
6919# 47.9 Pattern constraint
6920# 47.9.1
6921def p_PatternConstraint (t):
6922    'PatternConstraint : PATTERN Value'
6923    t[0] = Constraint (type = 'Pattern', subtype = t[2])
6924
6925# 49 The exception identifier
6926
6927# 49.4
6928def p_ExceptionSpec_1 (t):
6929    'ExceptionSpec : EXCLAMATION ExceptionIdentification'
6930    pass
6931
6932def p_ExceptionSpec_2 (t):
6933    'ExceptionSpec : '
6934    pass
6935
6936def p_ExceptionIdentification (t):
6937    '''ExceptionIdentification : SignedNumber
6938                               | DefinedValue
6939                               | Type COLON Value '''
6940    pass
6941
6942#  /*-----------------------------------------------------------------------*/
6943#  /* Value Notation Productions */
6944#  /*-----------------------------------------------------------------------*/
6945
6946
6947
6948def p_binary_string (t):
6949    'binary_string : BSTRING'
6950    t[0] = BStringValue(val = t[1])
6951
6952def p_hex_string (t):
6953    'hex_string : HSTRING'
6954    t[0] = HStringValue(val = t[1])
6955
6956def p_char_string (t):
6957    'char_string : QSTRING'
6958    t[0] = t[1]
6959
6960def p_number (t):
6961    'number : NUMBER'
6962    t[0] = t[1]
6963
6964
6965#--- ITU-T Recommendation X.208 -----------------------------------------------
6966
6967# 27 Notation for the any type ------------------------------------------------
6968
6969# 27.1
6970def p_AnyType (t):
6971    '''AnyType : ANY
6972               | ANY DEFINED BY identifier'''
6973    t[0] = AnyType()
6974
6975#--- ITU-T Recommendation X.681 -----------------------------------------------
6976
6977# 7 ASN.1 lexical items -------------------------------------------------------
6978
6979# 7.1 Information object class references
6980
6981def p_objectclassreference (t):
6982    'objectclassreference : CLASS_IDENT'
6983    t[0] = Class_Ref(val=t[1])
6984
6985# 7.2 Information object references
6986
6987def p_objectreference (t):
6988    'objectreference : LCASE_IDENT'
6989    t[0] = t[1]
6990
6991# 7.3 Information object set references
6992
6993#def p_objectsetreference (t):
6994#  'objectsetreference : UCASE_IDENT'
6995#  t[0] = t[1]
6996
6997# 7.4 Type field references
6998# ucasefieldreference
6999# 7.5 Value field references
7000# lcasefieldreference
7001# 7.6 Value set field references
7002# ucasefieldreference
7003# 7.7 Object field references
7004# lcasefieldreference
7005# 7.8 Object set field references
7006# ucasefieldreference
7007
7008def p_ucasefieldreference (t):
7009    'ucasefieldreference : AMPERSAND UCASE_IDENT'
7010    t[0] = '&' + t[2]
7011
7012def p_lcasefieldreference (t):
7013    'lcasefieldreference : AMPERSAND LCASE_IDENT'
7014    t[0] = '&' + t[2]
7015
7016# 8 Referencing definitions
7017
7018# 8.1
7019def p_DefinedObjectClass (t):
7020    '''DefinedObjectClass : objectclassreference
7021                          | UsefulObjectClassReference'''
7022    t[0] = t[1]
7023    global obj_class
7024    obj_class = t[0].val
7025
7026def p_DefinedObject (t):
7027    '''DefinedObject : objectreference'''
7028    t[0] = t[1]
7029
7030# 8.4
7031def p_UsefulObjectClassReference (t):
7032    '''UsefulObjectClassReference : TYPE_IDENTIFIER
7033                                  | ABSTRACT_SYNTAX'''
7034    t[0] = Class_Ref(val=t[1])
7035
7036# 9 Information object class definition and assignment
7037
7038# 9.1
7039def p_ObjectClassAssignment (t):
7040    '''ObjectClassAssignment : CLASS_IDENT ASSIGNMENT ObjectClass
7041                             | UCASE_IDENT ASSIGNMENT ObjectClass'''
7042    t[0] = t[3]
7043    t[0].SetName(t[1])
7044    if isinstance(t[0], ObjectClassDefn):
7045        t[0].reg_types()
7046
7047# 9.2
7048def p_ObjectClass (t):
7049    '''ObjectClass : DefinedObjectClass
7050                   | ObjectClassDefn
7051                   | ParameterizedObjectClass '''
7052    t[0] = t[1]
7053
7054# 9.3
7055def p_ObjectClassDefn (t):
7056    '''ObjectClassDefn : CLASS LBRACE FieldSpecs RBRACE
7057                       | CLASS LBRACE FieldSpecs RBRACE WithSyntaxSpec'''
7058    t[0] = ObjectClassDefn(fields = t[3])
7059
7060def p_FieldSpecs_1 (t):
7061    'FieldSpecs : FieldSpec'
7062    t[0] = [t[1]]
7063
7064def p_FieldSpecs_2 (t):
7065    'FieldSpecs : FieldSpecs COMMA FieldSpec'
7066    t[0] = t[1] + [t[3]]
7067
7068def p_WithSyntaxSpec (t):
7069    'WithSyntaxSpec : WITH SYNTAX lbraceignore rbraceignore'
7070    t[0] = None
7071
7072# 9.4
7073def p_FieldSpec (t):
7074    '''FieldSpec : TypeFieldSpec
7075                 | FixedTypeValueFieldSpec
7076                 | VariableTypeValueFieldSpec
7077                 | FixedTypeValueSetFieldSpec
7078                 | ObjectFieldSpec
7079                 | ObjectSetFieldSpec '''
7080    t[0] = t[1]
7081
7082# 9.5
7083def p_TypeFieldSpec (t):
7084    '''TypeFieldSpec : ucasefieldreference
7085                     | ucasefieldreference TypeOptionalitySpec '''
7086    t[0] = TypeFieldSpec()
7087    t[0].SetName(t[1])
7088
7089def p_TypeOptionalitySpec_1 (t):
7090    'TypeOptionalitySpec ::= OPTIONAL'
7091    pass
7092
7093def p_TypeOptionalitySpec_2 (t):
7094    'TypeOptionalitySpec ::= DEFAULT Type'
7095    pass
7096
7097# 9.6
7098def p_FixedTypeValueFieldSpec (t):
7099    '''FixedTypeValueFieldSpec : lcasefieldreference Type
7100                               | lcasefieldreference Type UNIQUE
7101                               | lcasefieldreference Type ValueOptionalitySpec
7102                               | lcasefieldreference Type UNIQUE ValueOptionalitySpec '''
7103    t[0] = FixedTypeValueFieldSpec(typ = t[2])
7104    t[0].SetName(t[1])
7105
7106def p_ValueOptionalitySpec_1 (t):
7107    'ValueOptionalitySpec ::= OPTIONAL'
7108    pass
7109
7110def p_ValueOptionalitySpec_2 (t):
7111    'ValueOptionalitySpec ::= DEFAULT Value'
7112    pass
7113
7114# 9.8
7115
7116def p_VariableTypeValueFieldSpec (t):
7117    '''VariableTypeValueFieldSpec : lcasefieldreference FieldName
7118                                  | lcasefieldreference FieldName ValueOptionalitySpec '''
7119    t[0] = VariableTypeValueFieldSpec()
7120    t[0].SetName(t[1])
7121
7122# 9.9
7123def p_FixedTypeValueSetFieldSpec (t):
7124    '''FixedTypeValueSetFieldSpec : ucasefieldreference Type
7125                                  | ucasefieldreference Type ValueSetOptionalitySpec '''
7126    t[0] = FixedTypeValueSetFieldSpec()
7127    t[0].SetName(t[1])
7128
7129def p_ValueSetOptionalitySpec_1 (t):
7130    'ValueSetOptionalitySpec ::= OPTIONAL'
7131    pass
7132
7133def p_ValueSetOptionalitySpec_2 (t):
7134    'ValueSetOptionalitySpec ::= DEFAULT ValueSet'
7135    pass
7136
7137# 9.11
7138def p_ObjectFieldSpec (t):
7139    '''ObjectFieldSpec : lcasefieldreference DefinedObjectClass
7140                       | lcasefieldreference DefinedObjectClass ObjectOptionalitySpec '''
7141    t[0] = ObjectFieldSpec(cls=t[2])
7142    t[0].SetName(t[1])
7143    global obj_class
7144    obj_class = None
7145
7146def p_ObjectOptionalitySpec_1 (t):
7147    'ObjectOptionalitySpec ::= OPTIONAL'
7148    pass
7149
7150def p_ObjectOptionalitySpec_2 (t):
7151    'ObjectOptionalitySpec ::= DEFAULT Object'
7152    pass
7153
7154# 9.12
7155def p_ObjectSetFieldSpec (t):
7156    '''ObjectSetFieldSpec : ucasefieldreference DefinedObjectClass
7157                          | ucasefieldreference DefinedObjectClass ObjectSetOptionalitySpec '''
7158    t[0] = ObjectSetFieldSpec(cls=t[2])
7159    t[0].SetName(t[1])
7160
7161def p_ObjectSetOptionalitySpec_1 (t):
7162    'ObjectSetOptionalitySpec ::= OPTIONAL'
7163    pass
7164
7165def p_ObjectSetOptionalitySpec_2 (t):
7166    'ObjectSetOptionalitySpec ::= DEFAULT ObjectSet'
7167    pass
7168
7169# 9.13
7170def p_PrimitiveFieldName (t):
7171    '''PrimitiveFieldName : ucasefieldreference
7172                          | lcasefieldreference '''
7173    t[0] = t[1]
7174
7175# 9.13
7176def p_FieldName_1 (t):
7177    'FieldName : PrimitiveFieldName'
7178    t[0] = t[1]
7179
7180def p_FieldName_2 (t):
7181    'FieldName : FieldName DOT PrimitiveFieldName'
7182    t[0] = t[1] + '.' + t[3]
7183
7184# 11 Information object definition and assignment
7185
7186# 11.1
7187def p_ObjectAssignment (t):
7188    'ObjectAssignment : objectreference DefinedObjectClass ASSIGNMENT Object'
7189    t[0] = ObjectAssignment (ident = t[1], cls=t[2].val, val=t[4])
7190    global obj_class
7191    obj_class = None
7192
7193# 11.3
7194def p_Object (t):
7195    '''Object : DefinedObject
7196              | ObjectDefn
7197              | ParameterizedObject'''
7198    t[0] = t[1]
7199
7200# 11.4
7201def p_ObjectDefn (t):
7202    'ObjectDefn : lbraceobject bodyobject rbraceobject'
7203    t[0] = t[2]
7204
7205#  {...} block of object definition
7206def p_lbraceobject(t):
7207    'lbraceobject : braceobjectbegin LBRACE'
7208    t[0] = t[1]
7209
7210def p_braceobjectbegin(t):
7211    'braceobjectbegin : '
7212    global lexer
7213    global obj_class
7214    if set_class_syntax(obj_class):
7215        state = 'INITIAL'
7216    else:
7217        lexer.level = 1
7218        state = 'braceignore'
7219    lexer.push_state(state)
7220
7221def p_rbraceobject(t):
7222    'rbraceobject : braceobjectend RBRACE'
7223    t[0] = t[2]
7224
7225def p_braceobjectend(t):
7226    'braceobjectend : '
7227    global lexer
7228    lexer.pop_state()
7229    set_class_syntax(None)
7230
7231def p_bodyobject_1 (t):
7232    'bodyobject : '
7233    t[0] = { }
7234
7235def p_bodyobject_2 (t):
7236    'bodyobject : cls_syntax_list'
7237    t[0] = t[1]
7238
7239def p_cls_syntax_list_1 (t):
7240    'cls_syntax_list : cls_syntax_list cls_syntax'
7241    t[0] = t[1]
7242    t[0].update(t[2])
7243
7244def p_cls_syntax_list_2 (t):
7245    'cls_syntax_list : cls_syntax'
7246    t[0] = t[1]
7247
7248# X.681
7249def p_cls_syntax_1 (t):
7250    'cls_syntax : Type IDENTIFIED BY Value'
7251    t[0] = { get_class_fieled(' ') : t[1], get_class_fieled(' '.join((t[2], t[3]))) : t[4] }
7252
7253def p_cls_syntax_2 (t):
7254    'cls_syntax : HAS PROPERTY Value'
7255    t[0] = { get_class_fieled(' '.join(t[1:-1])) : t[-1:][0] }
7256
7257# X.880
7258def p_cls_syntax_3 (t):
7259    '''cls_syntax : ERRORS ObjectSet
7260                   | LINKED ObjectSet
7261                   | RETURN RESULT BooleanValue
7262                   | SYNCHRONOUS BooleanValue
7263                   | INVOKE PRIORITY Value
7264                   | RESULT_PRIORITY Value
7265                   | PRIORITY Value
7266                   | ALWAYS RESPONDS BooleanValue
7267                   | IDEMPOTENT BooleanValue '''
7268    t[0] = { get_class_fieled(' '.join(t[1:-1])) : t[-1:][0] }
7269
7270def p_cls_syntax_4 (t):
7271    '''cls_syntax : ARGUMENT Type
7272                   | RESULT Type
7273                   | PARAMETER Type '''
7274    t[0] = { get_class_fieled(t[1]) : t[2] }
7275
7276def p_cls_syntax_5 (t):
7277    'cls_syntax : CODE Value'
7278    fld = get_class_fieled(t[1]);
7279    t[0] = { fld : t[2] }
7280    if isinstance(t[2], ChoiceValue):
7281        fldt = fld + '.' + t[2].choice
7282        t[0][fldt] = t[2]
7283
7284def p_cls_syntax_6 (t):
7285    '''cls_syntax : ARGUMENT Type OPTIONAL BooleanValue
7286                   | RESULT Type OPTIONAL BooleanValue
7287                   | PARAMETER Type OPTIONAL BooleanValue '''
7288    t[0] = { get_class_fieled(t[1]) : t[2], get_class_fieled(' '.join((t[1], t[3]))) : t[4] }
7289
7290# 12 Information object set definition and assignment
7291
7292# 12.1
7293def p_ObjectSetAssignment (t):
7294    'ObjectSetAssignment : UCASE_IDENT CLASS_IDENT ASSIGNMENT ObjectSet'
7295    t[0] = Node('ObjectSetAssignment', name=t[1], cls=t[2], val=t[4])
7296
7297# 12.3
7298def p_ObjectSet (t):
7299    'ObjectSet : lbraceignore rbraceignore'
7300    t[0] = None
7301
7302# 14 Notation for the object class field type ---------------------------------
7303
7304# 14.1
7305def p_ObjectClassFieldType (t):
7306    'ObjectClassFieldType : DefinedObjectClass DOT FieldName'
7307    t[0] = get_type_from_class(t[1], t[3])
7308
7309# 14.6
7310def p_ObjectClassFieldValue (t):
7311    '''ObjectClassFieldValue : OpenTypeFieldVal'''
7312    t[0] = t[1]
7313
7314def p_OpenTypeFieldVal (t):
7315    '''OpenTypeFieldVal : Type COLON Value
7316                        | NullType COLON NullValue'''
7317    t[0] = t[3]
7318
7319
7320# 15 Information from objects -------------------------------------------------
7321
7322# 15.1
7323
7324def p_ValueFromObject (t):
7325    'ValueFromObject : LCASE_IDENT DOT FieldName'
7326    t[0] = t[1] + '.' + t[3]
7327
7328
7329# Annex C - The instance-of type ----------------------------------------------
7330
7331# C.2
7332def p_InstanceOfType (t):
7333    'InstanceOfType : INSTANCE OF DefinedObjectClass'
7334    t[0] = InstanceOfType()
7335
7336
7337# ---  tables ---
7338
7339useful_object_class_types = {
7340  # Annex A
7341  'TYPE-IDENTIFIER.&id'   : lambda : ObjectIdentifierType(),
7342  'TYPE-IDENTIFIER.&Type' : lambda : OpenType(),
7343  # Annex B
7344  'ABSTRACT-SYNTAX.&id'       : lambda : ObjectIdentifierType(),
7345  'ABSTRACT-SYNTAX.&Type'     : lambda : OpenType(),
7346  'ABSTRACT-SYNTAX.&property' : lambda : BitStringType(),
7347}
7348
7349object_class_types = { }
7350
7351object_class_typerefs = { }
7352
7353object_class_classrefs = { }
7354
7355# dummy types
7356class _VariableTypeValueFieldSpec (AnyType):
7357    pass
7358
7359class _FixedTypeValueSetFieldSpec (AnyType):
7360    pass
7361
7362class_types_creator = {
7363  'BooleanType'          : lambda : BooleanType(),
7364  'IntegerType'          : lambda : IntegerType(),
7365  'ObjectIdentifierType' : lambda : ObjectIdentifierType(),
7366  'OpenType'             : lambda : OpenType(),
7367  # dummy types
7368  '_VariableTypeValueFieldSpec' : lambda : _VariableTypeValueFieldSpec(),
7369  '_FixedTypeValueSetFieldSpec' : lambda : _FixedTypeValueSetFieldSpec(),
7370}
7371
7372class_names = { }
7373
7374x681_syntaxes = {
7375  'TYPE-IDENTIFIER' : {
7376    ' '             : '&Type',
7377    'IDENTIFIED'    : 'IDENTIFIED',
7378    #'BY'            : 'BY',
7379    'IDENTIFIED BY' : '&id',
7380  },
7381  'ABSTRACT-SYNTAX' : {
7382    ' '             : '&Type',
7383    'IDENTIFIED'    : 'IDENTIFIED',
7384    #'BY'            : 'BY',
7385    'IDENTIFIED BY' : '&id',
7386    'HAS'           : 'HAS',
7387    'PROPERTY'      : 'PROPERTY',
7388    'HAS PROPERTY'  : '&property',
7389  },
7390}
7391
7392class_syntaxes_enabled = {
7393  'TYPE-IDENTIFIER' : True,
7394  'ABSTRACT-SYNTAX' : True,
7395}
7396
7397class_syntaxes = {
7398  'TYPE-IDENTIFIER' : x681_syntaxes['TYPE-IDENTIFIER'],
7399  'ABSTRACT-SYNTAX' : x681_syntaxes['ABSTRACT-SYNTAX'],
7400}
7401
7402class_current_syntax = None
7403
7404def get_syntax_tokens(syntaxes):
7405    tokens = { }
7406    for s in (syntaxes):
7407        for k in (list(syntaxes[s].keys())):
7408            if k.find(' ') < 0:
7409                tokens[k] = k
7410                tokens[k] = tokens[k].replace('-', '_')
7411    return list(tokens.values())
7412
7413tokens = tokens + get_syntax_tokens(x681_syntaxes)
7414
7415def set_class_syntax(syntax):
7416    global class_syntaxes_enabled
7417    global class_current_syntax
7418    #print "set_class_syntax", syntax, class_current_syntax
7419    if class_syntaxes_enabled.get(syntax, False):
7420        class_current_syntax = syntax
7421        return True
7422    else:
7423        class_current_syntax = None
7424        return False
7425
7426def is_class_syntax(name):
7427    global class_syntaxes
7428    global class_current_syntax
7429    #print "is_class_syntax", name, class_current_syntax
7430    if not class_current_syntax:
7431        return False
7432    return name in class_syntaxes[class_current_syntax]
7433
7434def get_class_fieled(name):
7435    if not class_current_syntax:
7436        return None
7437    return class_syntaxes[class_current_syntax][name]
7438
7439def is_class_ident(name):
7440    return name in class_names
7441
7442def add_class_ident(name):
7443    #print "add_class_ident", name
7444    class_names[name] = name
7445
7446def get_type_from_class(cls, fld):
7447    flds = fld.split('.')
7448    if (isinstance(cls, Class_Ref)):
7449        key = cls.val + '.' + flds[0]
7450    else:
7451        key = cls + '.' + flds[0]
7452
7453    if key in object_class_classrefs:
7454        return get_type_from_class(object_class_classrefs[key], '.'.join(flds[1:]))
7455
7456    if key in object_class_typerefs:
7457        return Type_Ref(val=object_class_typerefs[key])
7458
7459    creator = lambda : AnyType()
7460    creator = useful_object_class_types.get(key, creator)
7461    creator = object_class_types.get(key, creator)
7462    return creator()
7463
7464def set_type_to_class(cls, fld, pars):
7465    #print "set_type_to_class", cls, fld, pars
7466    key = cls + '.' + fld
7467    typename = 'OpenType'
7468    if (len(pars) > 0):
7469        typename = pars[0]
7470    else:
7471        pars.append(typename)
7472    typeref = None
7473    if (len(pars) > 1):
7474        if (isinstance(pars[1], Class_Ref)):
7475            pars[1] = pars[1].val
7476        typeref = pars[1]
7477
7478    msg = None
7479    if key in object_class_types:
7480        msg = object_class_types[key]().type
7481    if key in object_class_typerefs:
7482        msg = "TypeReference " + object_class_typerefs[key]
7483    if key in object_class_classrefs:
7484        msg = "ClassReference " + object_class_classrefs[key]
7485
7486    if msg == ' '.join(pars):
7487        msg = None
7488
7489    if msg:
7490        msg0 = "Can not define CLASS field %s as '%s'\n" % (key, ' '.join(pars))
7491        msg1 = "Already defined as '%s'" % (msg)
7492        raise CompError(msg0 + msg1)
7493
7494    if (typename == 'ClassReference'):
7495        if not typeref: return False
7496        object_class_classrefs[key] = typeref
7497        return True
7498
7499    if (typename == 'TypeReference'):
7500        if not typeref: return False
7501        object_class_typerefs[key] = typeref
7502        return True
7503
7504    creator = class_types_creator.get(typename)
7505    if creator:
7506        object_class_types[key] = creator
7507        return True
7508    else:
7509        return False
7510
7511def import_class_from_module(mod, cls):
7512    add_class_ident(cls)
7513    mcls = "$%s$%s" % (mod, cls)
7514    for k in list(object_class_classrefs.keys()):
7515        kk = k.split('.', 1)
7516        if kk[0] == mcls:
7517            object_class_classrefs[cls + '.' + kk[0]] = object_class_classrefs[k]
7518    for k in list(object_class_typerefs.keys()):
7519        kk = k.split('.', 1)
7520        if kk[0] == mcls:
7521            object_class_typerefs[cls + '.' + kk[0]] = object_class_typerefs[k]
7522    for k in list(object_class_types.keys()):
7523        kk = k.split('.', 1)
7524        if kk[0] == mcls:
7525            object_class_types[cls + '.' + kk[0]] = object_class_types[k]
7526
7527#--- ITU-T Recommendation X.682 -----------------------------------------------
7528
7529# 8 General constraint specification ------------------------------------------
7530
7531# 8.1
7532def p_GeneralConstraint (t):
7533    '''GeneralConstraint : UserDefinedConstraint
7534                         | TableConstraint
7535                         | ContentsConstraint'''
7536    t[0] = t[1]
7537
7538# 9 User-defined constraints --------------------------------------------------
7539
7540# 9.1
7541def p_UserDefinedConstraint (t):
7542    'UserDefinedConstraint : CONSTRAINED BY LBRACE UserDefinedConstraintParameterList RBRACE'
7543    t[0] = Constraint(type = 'UserDefined', subtype = t[4])
7544
7545def p_UserDefinedConstraintParameterList_1 (t):
7546    'UserDefinedConstraintParameterList : '
7547    t[0] = []
7548
7549def p_UserDefinedConstraintParameterList_2 (t):
7550    'UserDefinedConstraintParameterList : UserDefinedConstraintParameter'
7551    t[0] = [t[1]]
7552
7553def p_UserDefinedConstraintParameterList_3 (t):
7554    'UserDefinedConstraintParameterList : UserDefinedConstraintParameterList COMMA UserDefinedConstraintParameter'
7555    t[0] = t[1] + [t[3]]
7556
7557# 9.3
7558def p_UserDefinedConstraintParameter (t):
7559    'UserDefinedConstraintParameter : Type'
7560    t[0] = t[1]
7561
7562# 10 Table constraints, including component relation constraints --------------
7563
7564# 10.3
7565def p_TableConstraint (t):
7566    '''TableConstraint : SimpleTableConstraint
7567                       | ComponentRelationConstraint'''
7568    t[0] = Constraint(type = 'Table', subtype = t[1])
7569
7570def p_SimpleTableConstraint (t):
7571    'SimpleTableConstraint : LBRACE UCASE_IDENT RBRACE'
7572    t[0] = t[2]
7573
7574# 10.7
7575def p_ComponentRelationConstraint (t):
7576    'ComponentRelationConstraint : LBRACE UCASE_IDENT RBRACE LBRACE AtNotations RBRACE'
7577    t[0] = t[2] + str(t[5])
7578
7579def p_AtNotations_1 (t):
7580    'AtNotations : AtNotation'
7581    t[0] = [t[1]]
7582
7583def p_AtNotations_2 (t):
7584    'AtNotations : AtNotations COMMA  AtNotation'
7585    t[0] = t[1] + [t[3]]
7586
7587def p_AtNotation_1 (t):
7588    'AtNotation : AT ComponentIdList'
7589    t[0] = '@' + t[2]
7590
7591def p_AtNotation_2 (t):
7592    'AtNotation : AT DOT Level ComponentIdList'
7593    t[0] = '@.' + t[3] + t[4]
7594
7595def p_Level_1 (t):
7596    'Level : DOT Level'
7597    t[0] = '.' + t[2]
7598
7599def p_Level_2 (t):
7600    'Level : '
7601    t[0] = ''
7602
7603def p_ComponentIdList_1 (t):
7604    'ComponentIdList : LCASE_IDENT'
7605    t[0] = t[1]
7606
7607def p_ComponentIdList_2 (t):
7608    'ComponentIdList : ComponentIdList DOT LCASE_IDENT'
7609    t[0] = t[1] + '.' + t[3]
7610
7611# 11 Contents constraints -----------------------------------------------------
7612
7613# 11.1
7614def p_ContentsConstraint (t):
7615    'ContentsConstraint : CONTAINING type_ref'
7616    t[0] = Constraint(type = 'Contents', subtype = t[2])
7617
7618
7619#--- ITU-T Recommendation X.683 -----------------------------------------------
7620
7621# 8 Parameterized assignments -------------------------------------------------
7622
7623# 8.1
7624def p_ParameterizedAssignment (t):
7625    '''ParameterizedAssignment : ParameterizedTypeAssignment
7626                               | ParameterizedObjectClassAssignment
7627                               | ParameterizedObjectAssignment
7628                               | ParameterizedObjectSetAssignment'''
7629    t[0] = t[1]
7630
7631# 8.2
7632def p_ParameterizedTypeAssignment (t):
7633    'ParameterizedTypeAssignment : UCASE_IDENT ParameterList ASSIGNMENT Type'
7634    t[0] = t[4]
7635    t[0].SetName(t[1])  # t[0].SetName(t[1] + 'xxx')
7636
7637def p_ParameterizedObjectClassAssignment (t):
7638    '''ParameterizedObjectClassAssignment : CLASS_IDENT ParameterList ASSIGNMENT ObjectClass
7639                                          | UCASE_IDENT ParameterList ASSIGNMENT ObjectClass'''
7640    t[0] = t[4]
7641    t[0].SetName(t[1])
7642    if isinstance(t[0], ObjectClassDefn):
7643        t[0].reg_types()
7644
7645def p_ParameterizedObjectAssignment (t):
7646    'ParameterizedObjectAssignment : objectreference ParameterList DefinedObjectClass ASSIGNMENT Object'
7647    t[0] = ObjectAssignment (ident = t[1], cls=t[3].val, val=t[5])
7648    global obj_class
7649    obj_class = None
7650
7651def p_ParameterizedObjectSetAssignment (t):
7652    'ParameterizedObjectSetAssignment : UCASE_IDENT ParameterList DefinedObjectClass ASSIGNMENT ObjectSet'
7653    t[0] = Node('ObjectSetAssignment', name=t[1], cls=t[3].val, val=t[5])
7654
7655# 8.3
7656def p_ParameterList (t):
7657    'ParameterList : lbraceignore rbraceignore'
7658
7659#def p_ParameterList (t):
7660#  'ParameterList : LBRACE Parameters RBRACE'
7661#  t[0] = t[2]
7662
7663#def p_Parameters_1 (t):
7664#  'Parameters : Parameter'
7665#  t[0] = [t[1]]
7666
7667#def p_Parameters_2 (t):
7668#  'Parameters : Parameters COMMA Parameter'
7669#  t[0] = t[1] + [t[3]]
7670
7671#def p_Parameter_1 (t):
7672#  'Parameter : Type COLON Reference'
7673#  t[0] = [t[1], t[3]]
7674
7675#def p_Parameter_2 (t):
7676#  'Parameter : Reference'
7677#  t[0] = t[1]
7678
7679
7680# 9 Referencing parameterized definitions -------------------------------------
7681
7682# 9.1
7683def p_ParameterizedReference (t):
7684    'ParameterizedReference : Reference LBRACE RBRACE'
7685    t[0] = t[1]
7686    #t[0].val += 'xxx'
7687
7688# 9.2
7689def p_ParameterizedType (t):
7690    'ParameterizedType : type_ref ActualParameterList'
7691    t[0] = t[1]
7692    #t[0].val += 'xxx'
7693
7694
7695def p_ParameterizedObjectClass (t):
7696    'ParameterizedObjectClass : DefinedObjectClass ActualParameterList'
7697    t[0] = t[1]
7698    #t[0].val += 'xxx'
7699
7700def p_ParameterizedObject (t):
7701    'ParameterizedObject : DefinedObject ActualParameterList'
7702    t[0] = t[1]
7703    #t[0].val += 'xxx'
7704
7705# 9.5
7706def p_ActualParameterList (t):
7707    'ActualParameterList : lbraceignore rbraceignore'
7708
7709#def p_ActualParameterList (t):
7710#  'ActualParameterList : LBRACE ActualParameters RBRACE'
7711#  t[0] = t[2]
7712
7713#def p_ActualParameters_1 (t):
7714#  'ActualParameters : ActualParameter'
7715#  t[0] = [t[1]]
7716
7717#def p_ActualParameters_2 (t):
7718#  'ActualParameters : ActualParameters COMMA ActualParameter'
7719#  t[0] = t[1] + [t[3]]
7720
7721#def p_ActualParameter (t):
7722#  '''ActualParameter : Type
7723#                     | Value'''
7724#  t[0] = t[1]
7725
7726
7727#--- ITU-T Recommendation X.880 -----------------------------------------------
7728
7729x880_classes = {
7730  'OPERATION' : {
7731    '&ArgumentType'         : [],
7732    '&argumentTypeOptional' : [ 'BooleanType' ],
7733    '&returnResult'         : [ 'BooleanType' ],
7734    '&ResultType'           : [],
7735    '&resultTypeOptional'   : [ 'BooleanType' ],
7736    '&Errors'               : [ 'ClassReference', 'ERROR' ],
7737    '&Linked'               : [ 'ClassReference', 'OPERATION' ],
7738    '&synchronous'          : [ 'BooleanType' ],
7739    '&idempotent'           : [ 'BooleanType' ],
7740    '&alwaysReturns'        : [ 'BooleanType' ],
7741    '&InvokePriority'       : [ '_FixedTypeValueSetFieldSpec' ],
7742    '&ResultPriority'       : [ '_FixedTypeValueSetFieldSpec' ],
7743    '&operationCode'        : [ 'TypeReference', 'Code' ],
7744  },
7745  'ERROR' : {
7746    '&ParameterType'         : [],
7747    '&parameterTypeOptional' : [ 'BooleanType' ],
7748    '&ErrorPriority'         : [ '_FixedTypeValueSetFieldSpec' ],
7749    '&errorCode'             : [ 'TypeReference', 'Code' ],
7750  },
7751  'OPERATION-PACKAGE' : {
7752    '&Both'     : [ 'ClassReference', 'OPERATION' ],
7753    '&Consumer' : [ 'ClassReference', 'OPERATION' ],
7754    '&Supplier' : [ 'ClassReference', 'OPERATION' ],
7755    '&id'       : [ 'ObjectIdentifierType' ],
7756  },
7757  'CONNECTION-PACKAGE' : {
7758    '&bind'               : [ 'ClassReference', 'OPERATION' ],
7759    '&unbind'             : [ 'ClassReference', 'OPERATION' ],
7760    '&responderCanUnbind' : [ 'BooleanType' ],
7761    '&unbindCanFail'      : [ 'BooleanType' ],
7762    '&id'                 : [ 'ObjectIdentifierType' ],
7763  },
7764  'CONTRACT' : {
7765    '&connection'          : [ 'ClassReference', 'CONNECTION-PACKAGE' ],
7766    '&OperationsOf'        : [ 'ClassReference', 'OPERATION-PACKAGE' ],
7767    '&InitiatorConsumerOf' : [ 'ClassReference', 'OPERATION-PACKAGE' ],
7768    '&InitiatorSupplierOf' : [ 'ClassReference', 'OPERATION-PACKAGE' ],
7769    '&id'                  : [ 'ObjectIdentifierType' ],
7770  },
7771  'ROS-OBJECT-CLASS' : {
7772    '&Is'                   : [ 'ClassReference', 'ROS-OBJECT-CLASS' ],
7773    '&Initiates'            : [ 'ClassReference', 'CONTRACT' ],
7774    '&Responds'             : [ 'ClassReference', 'CONTRACT' ],
7775    '&InitiatesAndResponds' : [ 'ClassReference', 'CONTRACT' ],
7776    '&id'                   : [ 'ObjectIdentifierType' ],
7777  },
7778}
7779
7780x880_syntaxes = {
7781  'OPERATION' : {
7782    'ARGUMENT'       : '&ArgumentType',
7783    'ARGUMENT OPTIONAL' : '&argumentTypeOptional',
7784    'RESULT'         : '&ResultType',
7785    'RESULT OPTIONAL' : '&resultTypeOptional',
7786    'RETURN'         : 'RETURN',
7787    'RETURN RESULT'  : '&returnResult',
7788    'ERRORS'         : '&Errors',
7789    'LINKED'         : '&Linked',
7790    'SYNCHRONOUS'    : '&synchronous',
7791    'IDEMPOTENT'     : '&idempotent',
7792    'ALWAYS'         : 'ALWAYS',
7793    'RESPONDS'       : 'RESPONDS',
7794    'ALWAYS RESPONDS' : '&alwaysReturns',
7795    'INVOKE'         : 'INVOKE',
7796    'PRIORITY'       : 'PRIORITY',
7797    'INVOKE PRIORITY' : '&InvokePriority',
7798    'RESULT-PRIORITY': '&ResultPriority',
7799    'CODE'           : '&operationCode',
7800  },
7801  'ERROR' : {
7802    'PARAMETER'      : '&ParameterType',
7803    'PARAMETER OPTIONAL' : '&parameterTypeOptional',
7804    'PRIORITY'       : '&ErrorPriority',
7805    'CODE'           : '&errorCode',
7806  },
7807#  'OPERATION-PACKAGE' : {
7808#  },
7809#  'CONNECTION-PACKAGE' : {
7810#  },
7811#  'CONTRACT' : {
7812#  },
7813#  'ROS-OBJECT-CLASS' : {
7814#  },
7815}
7816
7817def x880_module_begin():
7818    #print "x880_module_begin()"
7819    for name in list(x880_classes.keys()):
7820        add_class_ident(name)
7821
7822def x880_import(name):
7823    if name in x880_syntaxes:
7824        class_syntaxes_enabled[name] = True
7825        class_syntaxes[name] = x880_syntaxes[name]
7826    if name in x880_classes:
7827        add_class_ident(name)
7828        for f in (list(x880_classes[name].keys())):
7829            set_type_to_class(name, f, x880_classes[name][f])
7830
7831tokens = tokens + get_syntax_tokens(x880_syntaxes)
7832
7833#  {...} OID value
7834#def p_lbrace_oid(t):
7835#  'lbrace_oid : brace_oid_begin LBRACE'
7836#  t[0] = t[1]
7837
7838#def p_brace_oid_begin(t):
7839#  'brace_oid_begin : '
7840#  global in_oid
7841#  in_oid = True
7842
7843#def p_rbrace_oid(t):
7844#  'rbrace_oid : brace_oid_end RBRACE'
7845#  t[0] = t[2]
7846
7847#def p_brace_oid_end(t):
7848#  'brace_oid_end : '
7849#  global in_oid
7850#  in_oid = False
7851
7852#  {...} block to be ignored
7853def p_lbraceignore(t):
7854    'lbraceignore : braceignorebegin LBRACE'
7855    t[0] = t[1]
7856
7857def p_braceignorebegin(t):
7858    'braceignorebegin : '
7859    global lexer
7860    lexer.level = 1
7861    lexer.push_state('braceignore')
7862
7863def p_rbraceignore(t):
7864    'rbraceignore : braceignoreend RBRACE'
7865    t[0] = t[2]
7866
7867def p_braceignoreend(t):
7868    'braceignoreend : '
7869    global lexer
7870    lexer.pop_state()
7871
7872def p_error(t):
7873    global input_file
7874    raise ParseError(t, input_file)
7875
7876def p_pyquote (t):
7877    '''pyquote : PYQUOTE'''
7878    t[0] = PyQuote (val = t[1])
7879
7880
7881def testlex (s):
7882    lexer.input (s)
7883    while True:
7884        token = lexer.token ()
7885        if not token:
7886            break
7887        print(token)
7888
7889
7890def do_module (ast, defined_dict):
7891    assert (ast.type == 'Module')
7892    ctx = Ctx (defined_dict)
7893    print(ast.to_python (ctx))
7894    print(ctx.output_assignments ())
7895    print(ctx.output_pyquotes ())
7896
7897def eth_do_module (ast, ectx):
7898    assert (ast.type == 'Module')
7899    if ectx.dbg('s'): print(ast.str_depth(0))
7900    ast.to_eth(ectx)
7901
7902def testyacc(s, fn, defined_dict):
7903    ast = yacc.parse(s, debug=0)
7904    time_str = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
7905    print("""#!/usr/bin/env python
7906# Auto-generated from %s at %s
7907from PyZ3950 import asn1""" % (fn, time_str))
7908    for module in ast:
7909        eth_do_module (module, defined_dict)
7910
7911
7912# Wireshark compiler
7913def eth_usage():
7914    print("""
7915  asn2wrs [-h|?] [-d dbg] [-b] [-p proto] [-c cnf_file] [-e] input_file(s) ...
7916    -h|?          : Usage
7917    -b            : BER (default is PER)
7918    -u            : Unaligned (default is aligned)
7919    -p proto      : Protocol name (implies -S). Default is module-name
7920                    from input_file (renamed by #.MODULE if present)
7921    -o name       : Output files name core (default is <proto>)
7922    -O dir        : Output directory for dissector
7923    -c cnf_file   : Conformance file
7924    -I path       : Path for conformance file includes
7925    -e            : Create conformance file for exported types
7926    -E            : Just create conformance file for exported types
7927    -S            : Single output for multiple modules
7928    -s template   : Single file output (template is input file
7929                    without .c/.h extension)
7930    -k            : Keep intermediate files though single file output is used
7931    -L            : Suppress #line directive from .cnf file
7932    -D dir        : Directory for input_file(s) (default: '.')
7933    -C            : Add check for SIZE constraints
7934    -r prefix     : Remove the prefix from type names
7935
7936    input_file(s) : Input ASN.1 file(s)
7937
7938    -d dbg        : Debug output, dbg = [l][y][p][s][a][t][c][m][o]
7939                    l - lex
7940                    y - yacc
7941                    p - parsing
7942                    s - internal ASN.1 structure
7943                    a - list of assignments
7944                    t - tables
7945                    c - conformance values
7946                    m - list of compiled modules with dependency
7947                    o - list of output files
7948  """)
7949
7950def eth_main():
7951    global input_file
7952    global g_conform
7953    global lexer
7954    print("ASN.1 to Wireshark dissector compiler");
7955    try:
7956        opts, args = getopt.getopt(sys.argv[1:], "h?d:D:buXp:FTo:O:c:I:eESs:kLCr:");
7957    except getopt.GetoptError:
7958        eth_usage(); sys.exit(2)
7959    if len(args) < 1:
7960        eth_usage(); sys.exit(2)
7961
7962    conform = EthCnf()
7963    conf_to_read = None
7964    output = EthOut()
7965    ectx = EthCtx(conform, output)
7966    ectx.encoding = 'per'
7967    ectx.proto_opt = None
7968    ectx.fld_opt = {}
7969    ectx.tag_opt = False
7970    ectx.outnm_opt = None
7971    ectx.aligned = True
7972    ectx.dbgopt = ''
7973    ectx.new = True
7974    ectx.expcnf = False
7975    ectx.justexpcnf = False
7976    ectx.merge_modules = False
7977    ectx.group_by_prot = False
7978    ectx.conform.last_group = 0
7979    ectx.conform.suppress_line = False;
7980    ectx.output.outnm = None
7981    ectx.output.single_file = None
7982    ectx.constraints_check = False;
7983    for o, a in opts:
7984        if o in ("-h", "-?"):
7985            eth_usage(); sys.exit(2)
7986        if o in ("-c",):
7987            conf_to_read = relpath(a)
7988        if o in ("-I",):
7989            ectx.conform.include_path.append(relpath(a))
7990        if o in ("-E",):
7991            ectx.expcnf = True
7992            ectx.justexpcnf = True
7993        if o in ("-D",):
7994            ectx.srcdir = relpath(a)
7995        if o in ("-C",):
7996            ectx.constraints_check = True
7997        if o in ("-X",):
7998            warnings.warn("Command line option -X is obsolete and can be removed")
7999        if o in ("-T",):
8000            warnings.warn("Command line option -T is obsolete and can be removed")
8001
8002    if conf_to_read:
8003        ectx.conform.read(conf_to_read)
8004
8005    for o, a in opts:
8006        if o in ("-h", "-?", "-c", "-I", "-E", "-D", "-C", "-X", "-T"):
8007            pass  # already processed
8008        else:
8009            par = []
8010            if a: par.append(a)
8011            ectx.conform.set_opt(o, par, "commandline", 0)
8012
8013    (ld, yd, pd) = (0, 0, 0);
8014    if ectx.dbg('l'): ld = 1
8015    if ectx.dbg('y'): yd = 1
8016    if ectx.dbg('p'): pd = 2
8017    lexer = lex.lex(debug=ld)
8018    parser = yacc.yacc(method='LALR', debug=yd, outputdir='.')
8019    parser.defaulted_states = {}
8020    g_conform = ectx.conform
8021    ast = []
8022    for fn in args:
8023        input_file = fn
8024        lexer.lineno = 1
8025        if (ectx.srcdir): fn = ectx.srcdir + '/' + fn
8026        # Read ASN.1 definition, trying one of the common encodings.
8027        data = open(fn, "rb").read()
8028        for encoding in ('utf-8', 'windows-1252'):
8029            try:
8030                data = data.decode(encoding)
8031                break
8032            except Exception:
8033                warnings.warn_explicit("Decoding %s as %s failed, trying next." % (fn, encoding), UserWarning, '', 0)
8034        # Py2 compat, name.translate in eth_output_hf_arr fails with unicode
8035        if not isinstance(data, str):
8036            data = data.encode('utf-8')
8037        ast.extend(yacc.parse(data, lexer=lexer, debug=pd))
8038    ectx.eth_clean()
8039    if (ectx.merge_modules):  # common output for all module
8040        ectx.eth_clean()
8041        for module in ast:
8042            eth_do_module(module, ectx)
8043        ectx.eth_prepare()
8044        ectx.eth_do_output()
8045    elif (ectx.groups()):  # group by protocols/group
8046        groups = []
8047        pr2gr = {}
8048        if (ectx.group_by_prot):  # group by protocols
8049            for module in ast:
8050                prot = module.get_proto(ectx)
8051                if prot not in pr2gr:
8052                    pr2gr[prot] = len(groups)
8053                    groups.append([])
8054                groups[pr2gr[prot]].append(module)
8055        else:  # group by groups
8056            pass
8057        for gm in (groups):
8058            ectx.eth_clean()
8059            for module in gm:
8060                eth_do_module(module, ectx)
8061            ectx.eth_prepare()
8062            ectx.eth_do_output()
8063    else:   # output for each module
8064        for module in ast:
8065            ectx.eth_clean()
8066            eth_do_module(module, ectx)
8067            ectx.eth_prepare()
8068            ectx.eth_do_output()
8069
8070    if ectx.dbg('m'):
8071        ectx.dbg_modules()
8072
8073    if ectx.dbg('c'):
8074        ectx.conform.dbg_print()
8075    if not ectx.justexpcnf:
8076        ectx.conform.unused_report()
8077
8078    if ectx.dbg('o'):
8079        ectx.output.dbg_print()
8080    ectx.output.make_single_file()
8081
8082
8083# Python compiler
8084def main():
8085    if sys.version_info[0] < 3:
8086        print("This requires Python 3")
8087        sys.exit(2)
8088
8089    testfn = testyacc
8090    if len (sys.argv) == 1:
8091        while True:
8092            s = eval(input ('Query: '))
8093            if len (s) == 0:
8094                break
8095            testfn (s, 'console', {})
8096    else:
8097        defined_dict = {}
8098        for fn in sys.argv [1:]:
8099            f = open (fn, "r")
8100            testfn (f.read (), fn, defined_dict)
8101            f.close ()
8102            lexer.lineno = 1
8103
8104
8105#--- BODY ---------------------------------------------------------------------
8106
8107if __name__ == '__main__':
8108    if (os.path.splitext(os.path.basename(sys.argv[0]))[0].lower() in ('asn2wrs', 'asn2eth')):
8109        eth_main()
8110    else:
8111        main()
8112
8113#------------------------------------------------------------------------------
8114#
8115# Editor modelines  -  https://www.wireshark.org/tools/modelines.html
8116#
8117# c-basic-offset: 4; tab-width: 8; indent-tabs-mode: nil
8118# vi: set shiftwidth=4 tabstop=8 expandtab:
8119# :indentSize=4:tabSize=8:noTabs=true:
8120