internal override DerSet CreateDerSet(
     DefiniteLengthInputStream dIn)
 {
     return new LazyDerSet(dIn.ToArray());
 }
        /**
        * build an object given its tag and the number of bytes to construct it from.
        */
        private Asn1Object BuildObject(
            int	tag,
            int	tagNo,
            int	length)
        {
            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;

            DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length);

            if ((tag & Asn1Tags.Application) != 0)
            {
                return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
            }

            if ((tag & Asn1Tags.Tagged) != 0)
            {
                return new Asn1StreamParser(defIn).ReadTaggedObject(isConstructed, tagNo);
            }

            if (isConstructed)
            {
                // TODO There are other tags that may be constructed (e.g. BitString)
                switch (tagNo)
                {
                    case Asn1Tags.OctetString:
                        //
                        // yes, people actually do this...
                        //
                        return new BerOctetString(BuildDerEncodableVector(defIn));
                    case Asn1Tags.Sequence:
                        return CreateDerSequence(defIn);
                    case Asn1Tags.Set:
                        return CreateDerSet(defIn);
                    case Asn1Tags.External:
                        return new DerExternal(BuildDerEncodableVector(defIn));
                    default:
                        throw new IOException("unknown tag " + tagNo + " encountered");
                }
            }

            return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
        }
        internal static Asn1Object CreatePrimitiveDerObject(
            int                         tagNo,
            DefiniteLengthInputStream   defIn,
            byte[][]                    tmpBuffers)
        {
            switch (tagNo)
            {
                case Asn1Tags.Boolean:
                    return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
                case Asn1Tags.Enumerated:
                    return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
                case Asn1Tags.ObjectIdentifier:
                    return DerObjectIdentifier.FromOctetString(GetBuffer(defIn, tmpBuffers));
            }

            byte[] bytes = defIn.ToArray();

            switch (tagNo)
            {
                case Asn1Tags.BitString:
                    return DerBitString.FromAsn1Octets(bytes);
                case Asn1Tags.BmpString:
                    return new DerBmpString(bytes);
                case Asn1Tags.GeneralizedTime:
                    return new DerGeneralizedTime(bytes);
                case Asn1Tags.GeneralString:
                    return new DerGeneralString(bytes);
                case Asn1Tags.IA5String:
                    return new DerIA5String(bytes);
                case Asn1Tags.Integer:
                    return new DerInteger(bytes);
                case Asn1Tags.Null:
                    return DerNull.Instance;   // actual content is ignored (enforce 0 length?)
                case Asn1Tags.NumericString:
                    return new DerNumericString(bytes);
                case Asn1Tags.OctetString:
                    return new DerOctetString(bytes);
                case Asn1Tags.PrintableString:
                    return new DerPrintableString(bytes);
                case Asn1Tags.T61String:
                    return new DerT61String(bytes);
                case Asn1Tags.UniversalString:
                    return new DerUniversalString(bytes);
                case Asn1Tags.UtcTime:
                    return new DerUtcTime(bytes);
                case Asn1Tags.Utf8String:
                    return new DerUtf8String(bytes);
                case Asn1Tags.VisibleString:
                    return new DerVisibleString(bytes);
                default:
                    throw new IOException("unknown tag " + tagNo + " encountered");
            }
        }
        internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
        {
            int len = defIn.GetRemaining();
            if (len >= tmpBuffers.Length)
            {
                return defIn.ToArray();
            }

            byte[] buf = tmpBuffers[len];
            if (buf == null)
            {
                buf = tmpBuffers[len] = new byte[len];
            }

            defIn.ReadAllIntoByteArray(buf);

            return buf;
        }
        public virtual IAsn1Convertible ReadObject()
        {
            int tag = _in.ReadByte();
            if (tag == -1)
                return null;

            // turn of looking for "00" while we resolve the tag
            Set00Check(false);

            //
            // calculate tag number
            //
            int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);

            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;

            //
            // calculate length
            //
            int length = Asn1InputStream.ReadLength(_in, _limit);

            if (length < 0) // indefinite length method
            {
                if (!isConstructed)
                    throw new IOException("indefinite length primitive encoding encountered");

                IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
                Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit);

                if ((tag & Asn1Tags.Application) != 0)
                {
                    return new BerApplicationSpecificParser(tagNo, sp);
                }

                if ((tag & Asn1Tags.Tagged) != 0)
                {
                    return new BerTaggedObjectParser(true, tagNo, sp);
                }

                return sp.ReadIndef(tagNo);
            }
            else
            {
                DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);

                if ((tag & Asn1Tags.Application) != 0)
                {
                    return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
                }

                if ((tag & Asn1Tags.Tagged) != 0)
                {
                    return new BerTaggedObjectParser(isConstructed, tagNo, new Asn1StreamParser(defIn));
                }

                if (isConstructed)
                {
                    // TODO There are other tags that may be constructed (e.g. BitString)
                    switch (tagNo)
                    {
                        case Asn1Tags.OctetString:
                            //
                            // yes, people actually do this...
                            //
                            return new BerOctetStringParser(new Asn1StreamParser(defIn));
                        case Asn1Tags.Sequence:
                            return new DerSequenceParser(new Asn1StreamParser(defIn));
                        case Asn1Tags.Set:
                            return new DerSetParser(new Asn1StreamParser(defIn));
                        case Asn1Tags.External:
                            return new DerExternalParser(new Asn1StreamParser(defIn));
                        default:
                            throw new IOException("unknown tag " + tagNo + " encountered");
                    }
                }

                // Some primitive encodings can be handled by parsers too...
                switch (tagNo)
                {
                    case Asn1Tags.OctetString:
                        return new DerOctetStringParser(defIn);
                }

                try
                {
                    return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
                }
                catch (ArgumentException e)
                {
                    throw new Asn1Exception("corrupted stream detected", e);
                }
            }
        }