Asn1scc.py 3.54 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    Python API for the ASN1Scc compiler

    Copyright (c) 2013 European Space Agency

    Designed and implemented by Maxime Perrotin

    Based on the ASN.1 Space Certified Compiler from Neuropublic

    Contact: maxime.perrotin@esa.int
"""

import subprocess
import tempfile
import uuid
import os
Maxime Perrotin's avatar
Maxime Perrotin committed
20
import distutils.spawn as spawn
Maxime Perrotin's avatar
Maxime Perrotin committed
21
22
23
import sys
import importlib
import logging
24
25
from PySide.QtCore import QProcess

Maxime Perrotin's avatar
Maxime Perrotin committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

LOG = logging.getLogger(__name__)

# global needed to store the imported module and list of modules ever loaded
AST = {}

try:
    from enum import Enum
except ImportError:
    raise ImportError('Enum module not found. use sudo pip install enum34')


__all__ = ['ASN1', 'parse_asn1']
__version__ = '0.1'

Maxime Perrotin's avatar
Maxime Perrotin committed
41

Maxime Perrotin's avatar
Maxime Perrotin committed
42
43
44
45
46
47
48
49
50
51
52
class ASN1(Enum):
    ''' Flags used to control the compiler options '''
    NoParameterizedTypes = 1
    NoInnerTypes = 2
    NoConstraintReference = 3
    UniqueEnumeratedNames = 4
    AstOnly = 5


def parse_asn1(*files, **options):
    ''' Call the ASN.1 parser on a number of files, and return the module
53
54
55
56
        containing the AST
        This function uses QProcess to launch the ASN.1 compiler because
        the subprocess module from Python has issues on the Windows platform
    '''
Maxime Perrotin's avatar
Maxime Perrotin committed
57
58
59
    global AST

    ast_version = options.get('ast_version', ASN1.UniqueEnumeratedNames)
Maxime Perrotin's avatar
Maxime Perrotin committed
60
    flags = options.get('flags', [ASN1.AstOnly])
Maxime Perrotin's avatar
Maxime Perrotin committed
61
62
    assert isinstance(ast_version, ASN1)
    assert isinstance(flags, list)
63
64
65
66
67
68
    if os.name == 'posix' and hasattr(sys, 'frozen'):
        # Frozen Linux binaries are expected to use the frozen ASN.1 compiler
        asn1exe = 'asn1scc'
    else:
        asn1exe = 'asn1.exe'
    path_to_asn1scc = spawn.find_executable(asn1exe)
69
70
71
72
    if not path_to_asn1scc:
        raise TypeError('ASN.1 Compiler not found in path')
    asn1scc_root = os.path.abspath(os.path.dirname(path_to_asn1scc))
    # Create a temporary directory to store dataview.py and import it
Maxime Perrotin's avatar
Maxime Perrotin committed
73
    tempdir = tempfile.mkdtemp()
74
    sys.path.append(tempdir)
75
    if os.name == 'nt':
76
77
        # On windows, remove the drive letter, workaround to ASN1SCC bug
        tempdir = tempdir[2:]
78
        asn1scc_root = asn1scc_root[2:]
Maxime Perrotin's avatar
Maxime Perrotin committed
79
80
81
    filename = str(uuid.uuid4()).replace('-', '_')
    filepath = tempdir + os.sep + filename + '.py'

Maxime Perrotin's avatar
Maxime Perrotin committed
82
    stg = asn1scc_root + os.sep + 'python.stg'
Maxime Perrotin's avatar
Maxime Perrotin committed
83

84
    args = ['-customStgAstVerion', str(ast_version.value),
Maxime Perrotin's avatar
Maxime Perrotin committed
85
            '-customStg', stg + ':' + filepath] + list(*files)
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    asn1scc = QProcess()
    LOG.debug(os.getcwd())
    LOG.debug(path_to_asn1scc + ' ' + ' '.join(args))
    asn1scc.start(path_to_asn1scc, args)
    if not asn1scc.waitForStarted():
        raise TypeError('Could not start ASN.1 Compiler')
    if not asn1scc.waitForFinished():
        raise TypeError('Execution of ASN.1 Compiler timed out')
    exitcode = asn1scc.exitCode()
    result = asn1scc.readAllStandardError()
    if exitcode != 0:
        raise TypeError('ASN.1 Compiler Error (exit code = {}) - {}'
                        .format(exitcode, str(result)))
    else:
Maxime Perrotin's avatar
Maxime Perrotin committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
        if filename in AST.viewkeys():
            # Re-import module if it was already loaded
            ast = AST[filename]
            reload(ast)
        else:
            ast = importlib.import_module(filename)
            AST[filename] = ast
        return ast


if __name__ == '__main__':
    try:
        ast = parse_asn1('dataview-uniq.asn',
                          ast_version=ASN1.NoParameterizedTypes,
                          flags=[ASN1.AstOnly])
        print ast.types.keys()
        sys.exit(0)
    except TypeError as err:
        print(str(err))
        sys.exit(1)