def _build()

in stk-sample/lambda/stk-player-events-loader-pg/package/asn1crypto/core.py [0:0]


def _build(class_, method, tag, header, contents, trailer, spec=None, spec_params=None, nested_spec=None):
    """
    Builds an Asn1Value object generically, or using a spec with optional params

    :param class_:
        An integer representing the ASN.1 class

    :param method:
        An integer representing the ASN.1 method

    :param tag:
        An integer representing the ASN.1 tag

    :param header:
        A byte string of the ASN.1 header (class, method, tag, length)

    :param contents:
        A byte string of the ASN.1 value

    :param trailer:
        A byte string of any ASN.1 trailer (only used by indefinite length encodings)

    :param spec:
        A class derived from Asn1Value that defines what class_ and tag the
        value should have, and the semantics of the encoded value. The
        return value will be of this type. If omitted, the encoded value
        will be decoded using the standard universal tag based on the
        encoded tag number.

    :param spec_params:
        A dict of params to pass to the spec object

    :param nested_spec:
        For certain Asn1Value classes (such as OctetString and BitString), the
        contents can be further parsed and interpreted as another Asn1Value.
        This parameter controls the spec for that sub-parsing.

    :return:
        An object of the type spec, or if not specified, a child of Asn1Value
    """

    if spec_params is not None:
        _tag_type_to_explicit_implicit(spec_params)

    if header is None:
        return VOID

    header_set = False

    # If an explicit specification was passed in, make sure it matches
    if spec is not None:
        # If there is explicit tagging and contents, we have to split
        # the header and trailer off before we do the parsing
        no_explicit = spec_params and 'no_explicit' in spec_params
        if not no_explicit and (spec.explicit or (spec_params and 'explicit' in spec_params)):
            if spec_params:
                value = spec(**spec_params)
            else:
                value = spec()
            original_explicit = value.explicit
            explicit_info = reversed(original_explicit)
            parsed_class = class_
            parsed_method = method
            parsed_tag = tag
            to_parse = contents
            explicit_header = header
            explicit_trailer = trailer or b''
            for expected_class, expected_tag in explicit_info:
                if parsed_class != expected_class:
                    raise ValueError(unwrap(
                        '''
                        Error parsing %s - explicitly-tagged class should have been
                        %s, but %s was found
                        ''',
                        type_name(value),
                        CLASS_NUM_TO_NAME_MAP.get(expected_class),
                        CLASS_NUM_TO_NAME_MAP.get(parsed_class, parsed_class)
                    ))
                if parsed_method != 1:
                    raise ValueError(unwrap(
                        '''
                        Error parsing %s - explicitly-tagged method should have
                        been %s, but %s was found
                        ''',
                        type_name(value),
                        METHOD_NUM_TO_NAME_MAP.get(1),
                        METHOD_NUM_TO_NAME_MAP.get(parsed_method, parsed_method)
                    ))
                if parsed_tag != expected_tag:
                    raise ValueError(unwrap(
                        '''
                        Error parsing %s - explicitly-tagged tag should have been
                        %s, but %s was found
                        ''',
                        type_name(value),
                        expected_tag,
                        parsed_tag
                    ))
                info, _ = _parse(to_parse, len(to_parse))
                parsed_class, parsed_method, parsed_tag, parsed_header, to_parse, parsed_trailer = info

                if not isinstance(value, Choice):
                    explicit_header += parsed_header
                    explicit_trailer = parsed_trailer + explicit_trailer

            value = _build(*info, spec=spec, spec_params={'no_explicit': True})
            value._header = explicit_header
            value._trailer = explicit_trailer
            value.explicit = original_explicit
            header_set = True
        else:
            if spec_params:
                value = spec(contents=contents, **spec_params)
            else:
                value = spec(contents=contents)

            if spec is Any:
                pass

            elif isinstance(value, Choice):
                value.validate(class_, tag, contents)
                try:
                    # Force parsing the Choice now
                    value.contents = header + value.contents
                    header = b''
                    value.parse()
                except (ValueError, TypeError) as e:
                    args = e.args[1:]
                    e.args = (e.args[0] + '\n    while parsing %s' % type_name(value),) + args
                    raise e

            else:
                if class_ != value.class_:
                    raise ValueError(unwrap(
                        '''
                        Error parsing %s - class should have been %s, but %s was
                        found
                        ''',
                        type_name(value),
                        CLASS_NUM_TO_NAME_MAP.get(value.class_),
                        CLASS_NUM_TO_NAME_MAP.get(class_, class_)
                    ))
                if method != value.method:
                    # Allow parsing a primitive method as constructed if the value
                    # is indefinite length. This is to allow parsing BER.
                    ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00'
                    if not ber_indef or not isinstance(value, Constructable):
                        raise ValueError(unwrap(
                            '''
                            Error parsing %s - method should have been %s, but %s was found
                            ''',
                            type_name(value),
                            METHOD_NUM_TO_NAME_MAP.get(value.method),
                            METHOD_NUM_TO_NAME_MAP.get(method, method)
                        ))
                    else:
                        value.method = method
                        value._indefinite = True
                if tag != value.tag:
                    if isinstance(value._bad_tag, tuple):
                        is_bad_tag = tag in value._bad_tag
                    else:
                        is_bad_tag = tag == value._bad_tag
                    if not is_bad_tag:
                        raise ValueError(unwrap(
                            '''
                            Error parsing %s - tag should have been %s, but %s was found
                            ''',
                            type_name(value),
                            value.tag,
                            tag
                        ))

    # For explicitly tagged, un-speced parsings, we use a generic container
    # since we will be parsing the contents and discarding the outer object
    # anyway a little further on
    elif spec_params and 'explicit' in spec_params:
        original_value = Asn1Value(contents=contents, **spec_params)
        original_explicit = original_value.explicit

        to_parse = contents
        explicit_header = header
        explicit_trailer = trailer or b''
        for expected_class, expected_tag in reversed(original_explicit):
            info, _ = _parse(to_parse, len(to_parse))
            _, _, _, parsed_header, to_parse, parsed_trailer = info
            explicit_header += parsed_header
            explicit_trailer = parsed_trailer + explicit_trailer
        value = _build(*info, spec=spec, spec_params={'no_explicit': True})
        value._header = header + value._header
        value._trailer += trailer or b''
        value.explicit = original_explicit
        header_set = True

    # If no spec was specified, allow anything and just process what
    # is in the input data
    else:
        if tag not in _UNIVERSAL_SPECS:
            raise ValueError(unwrap(
                '''
                Unknown element - %s class, %s method, tag %s
                ''',
                CLASS_NUM_TO_NAME_MAP.get(class_),
                METHOD_NUM_TO_NAME_MAP.get(method),
                tag
            ))

        spec = _UNIVERSAL_SPECS[tag]

        value = spec(contents=contents, class_=class_)
        ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00'
        if ber_indef and isinstance(value, Constructable):
            value._indefinite = True
        value.method = method

    if not header_set:
        value._header = header
        value._trailer = trailer or b''

    # Destroy any default value that our contents have overwritten
    value._native = None

    if nested_spec:
        try:
            value.parse(nested_spec)
        except (ValueError, TypeError) as e:
            args = e.args[1:]
            e.args = (e.args[0] + '\n    while parsing %s' % type_name(value),) + args
            raise e

    return value