protected virtual TypeConstructor FindTypeConstructor(DerAsnIdentifier identifier)
        {
            if (_registeredClassSpecificTypes.TryGetValue(identifier, out var classSpecificTypeConstructor))
            {
                return(classSpecificTypeConstructor);
            }

            var typeKey = new TypeKey {
                EncodingType = identifier.EncodingType, Tag = identifier.Tag
            };

            if (_registeredTypes.TryGetValue(typeKey, out classSpecificTypeConstructor))
            {
                return(classSpecificTypeConstructor);
            }

            return(null);
        }
        /// <summary>
        /// Decode a single ASN.1 type encoded in the given byte queue.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns>The decoded ASN.1 type (primitive or constructed set/sequence).</returns>
        public DerAsnType Decode(Queue <byte> data)
        {
            var identifier = DerAsnIdentifier.Decode(data);

            var typeConstructor = FindTypeConstructor(identifier)
                                  ?? throw new InvalidOperationException($"No type registered for identifier {identifier}");

            var length = DerAsnLength.Decode(data);

            if (data.Count < length)
            {
                throw new InvalidOperationException($"Expected {length} bytes to decode type with identifier {identifier} but got {data.Count} bytes");
            }

            var dataForType = new Queue <byte>(data.Dequeue(length.Length));

            return(typeConstructor(this, identifier, dataForType));
        }
        /// <summary>
        /// Registers a class dependent type.
        /// </summary>
        /// <param name="identifier">The exact tag identifier of the type.</param>
        /// <param name="typeConstructor">The type constructor.</param>
        /// <param name="replace">True to allow replacing an existing registration, otherwise false</param>
        /// <returns>The <see cref="DefaultDerAsnDecoder"/> instance.</returns>
        public DefaultDerAsnDecoder RegisterType(DerAsnIdentifier identifier, TypeConstructor typeConstructor, bool replace = false)
        {
            if (identifier == null)
            {
                throw new ArgumentNullException(nameof(identifier));
            }
            if (typeConstructor == null)
            {
                throw new ArgumentNullException(nameof(typeConstructor));
            }

            if (!replace && _registeredClassSpecificTypes.ContainsKey(identifier))
            {
                throw new InvalidOperationException($"Type with class {identifier.TagClass}, encoding type {identifier.EncodingType} and tag number {identifier.Tag} already registered");
            }

            _registeredClassSpecificTypes[identifier] = typeConstructor;

            return(this);
        }
 protected DerAsnType(DerAsnIdentifier identifier)
 {
     Identifier = identifier;
 }