internal static void Decode(AsnReader reader, out Asn1ExtendedResponse decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            Decode(reader, Asn1Tag.Sequence, out decoded);
        }
        internal static void Decode(AsnReader reader, out Asn1ProtocolOp decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new Asn1ProtocolOp();
            Asn1Tag   tag = reader.PeekTag();
            AsnReader collectionReader;

            if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 0)))
            {
                Asn1BindRequest tmpBindRequest;
                Asn1BindRequest.Decode(reader, new Asn1Tag(TagClass.Application, 0), out tmpBindRequest);
                decoded.BindRequest = tmpBindRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 1)))
            {
                Asn1BindResponse tmpBindResponse;
                Asn1BindResponse.Decode(reader, new Asn1Tag(TagClass.Application, 1), out tmpBindResponse);
                decoded.BindResponse = tmpBindResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 2)))
            {
                reader.ReadNull(new Asn1Tag(TagClass.Application, 2));
                decoded.UnbindRequest = true;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 3)))
            {
                Asn1SearchRequest tmpSearchRequest;
                Asn1SearchRequest.Decode(reader, new Asn1Tag(TagClass.Application, 3), out tmpSearchRequest);
                decoded.SearchRequest = tmpSearchRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 4)))
            {
                Asn1SearchResultEntry tmpSearchResEntry;
                Asn1SearchResultEntry.Decode(reader, new Asn1Tag(TagClass.Application, 4), out tmpSearchResEntry);
                decoded.SearchResEntry = tmpSearchResEntry;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 5)))
            {
                Asn1LDAPResult tmpSearchResultDone;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 5), out tmpSearchResultDone);
                decoded.SearchResultDone = tmpSearchResultDone;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 19)))
            {
                // Decode SEQUENCE OF for SearchResultReference
                {
                    collectionReader = reader.ReadSequence(new Asn1Tag(TagClass.Application, 19));
                    var tmpList = new List <ReadOnlyMemory <byte> >();
                    ReadOnlyMemory <byte> tmpItem;

                    while (collectionReader.HasData)
                    {
                        if (collectionReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmp))
                        {
                            tmpItem = tmp;
                        }
                        else
                        {
                            tmpItem = collectionReader.ReadOctetString();
                        }

                        tmpList.Add(tmpItem);
                    }

                    decoded.SearchResultReference = tmpList.ToArray();
                }
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 6)))
            {
                Asn1ModifyRequest tmpModifyRequest;
                Asn1ModifyRequest.Decode(reader, new Asn1Tag(TagClass.Application, 6), out tmpModifyRequest);
                decoded.ModifyRequest = tmpModifyRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 7)))
            {
                Asn1LDAPResult tmpModifyResponse;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 7), out tmpModifyResponse);
                decoded.ModifyResponse = tmpModifyResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 8)))
            {
                Asn1AddRequest tmpAddRequest;
                Asn1AddRequest.Decode(reader, new Asn1Tag(TagClass.Application, 8), out tmpAddRequest);
                decoded.AddRequest = tmpAddRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 9)))
            {
                Asn1LDAPResult tmpAddResponse;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 9), out tmpAddResponse);
                decoded.AddResponse = tmpAddResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 10)))
            {
                if (reader.TryGetPrimitiveOctetStringBytes(new Asn1Tag(TagClass.Application, 10), out ReadOnlyMemory <byte> tmpDelRequest))
                {
                    decoded.DelRequest = tmpDelRequest;
                }
                else
                {
                    decoded.DelRequest = reader.ReadOctetString(new Asn1Tag(TagClass.Application, 10));
                }
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 11)))
            {
                Asn1LDAPResult tmpDelResponse;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 11), out tmpDelResponse);
                decoded.DelResponse = tmpDelResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 12)))
            {
                Asn1ModifyDNRequest tmpModifyDNRequest;
                Asn1ModifyDNRequest.Decode(reader, new Asn1Tag(TagClass.Application, 12), out tmpModifyDNRequest);
                decoded.ModifyDNRequest = tmpModifyDNRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 13)))
            {
                Asn1LDAPResult tmpModifyDNResponse;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 13), out tmpModifyDNResponse);
                decoded.ModifyDNResponse = tmpModifyDNResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 14)))
            {
                Asn1CompareRequest tmpCompareRequest;
                Asn1CompareRequest.Decode(reader, new Asn1Tag(TagClass.Application, 14), out tmpCompareRequest);
                decoded.CompareRequest = tmpCompareRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 15)))
            {
                Asn1LDAPResult tmpCompareResponse;
                Asn1LDAPResult.Decode(reader, new Asn1Tag(TagClass.Application, 15), out tmpCompareResponse);
                decoded.CompareResponse = tmpCompareResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 16)))
            {
                if (reader.TryReadInt32(new Asn1Tag(TagClass.Application, 16), out int tmpAbandonRequest))
                {
                    decoded.AbandonRequest = tmpAbandonRequest;
                }
                else
                {
                    reader.ThrowIfNotEmpty();
                }
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 23)))
            {
                Asn1ExtendedRequest tmpExtendedRequest;
                Asn1ExtendedRequest.Decode(reader, new Asn1Tag(TagClass.Application, 23), out tmpExtendedRequest);
                decoded.ExtendedRequest = tmpExtendedRequest;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 24)))
            {
                Asn1ExtendedResponse tmpExtendedResponse;
                Asn1ExtendedResponse.Decode(reader, new Asn1Tag(TagClass.Application, 24), out tmpExtendedResponse);
                decoded.ExtendedResponse = tmpExtendedResponse;
            }
            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.Application, 25)))
            {
                Asn1IntermediateResponse tmpIntermediateResponse;
                Asn1IntermediateResponse.Decode(reader, new Asn1Tag(TagClass.Application, 25), out tmpIntermediateResponse);
                decoded.IntermediateResponse = tmpIntermediateResponse;
            }
            else
            {
                throw new CryptographicException();
            }
        }
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Asn1ExtendedResponse decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new Asn1ExtendedResponse();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader collectionReader;

            decoded.ResultCode = sequenceReader.GetEnumeratedValue <ResultCode>();

            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmpMatchedDN))
            {
                decoded.MatchedDN = tmpMatchedDN;
            }
            else
            {
                decoded.MatchedDN = sequenceReader.ReadOctetString();
            }


            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmpDiagnosticMessage))
            {
                decoded.DiagnosticMessage = tmpDiagnosticMessage;
            }
            else
            {
                decoded.DiagnosticMessage = sequenceReader.ReadOctetString();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                // Decode SEQUENCE OF for Referral
                {
                    collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
                    var tmpList = new List <ReadOnlyMemory <byte> >();
                    ReadOnlyMemory <byte> tmpItem;

                    while (collectionReader.HasData)
                    {
                        if (collectionReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmp))
                        {
                            tmpItem = tmp;
                        }
                        else
                        {
                            tmpItem = collectionReader.ReadOctetString();
                        }

                        tmpList.Add(tmpItem);
                    }

                    decoded.Referral = tmpList.ToArray();
                }
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 10)))
            {
                if (sequenceReader.TryGetPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 10), out ReadOnlyMemory <byte> tmpName))
                {
                    decoded.Name = tmpName;
                }
                else
                {
                    decoded.Name = sequenceReader.ReadOctetString(new Asn1Tag(TagClass.ContextSpecific, 10));
                }
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 11)))
            {
                if (sequenceReader.TryGetPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 11), out ReadOnlyMemory <byte> tmpValue))
                {
                    decoded.Value = tmpValue;
                }
                else
                {
                    decoded.Value = sequenceReader.ReadOctetString(new Asn1Tag(TagClass.ContextSpecific, 11));
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }