summary refs log tree commit diff
path: root/crypto/src/asn1/ConstructedBitStream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/ConstructedBitStream.cs')
-rw-r--r--crypto/src/asn1/ConstructedBitStream.cs134
1 files changed, 134 insertions, 0 deletions
diff --git a/crypto/src/asn1/ConstructedBitStream.cs b/crypto/src/asn1/ConstructedBitStream.cs
new file mode 100644
index 000000000..7c9e7c9e4
--- /dev/null
+++ b/crypto/src/asn1/ConstructedBitStream.cs
@@ -0,0 +1,134 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class ConstructedBitStream
+        : BaseInputStream
+    {
+        private readonly Asn1StreamParser m_parser;
+        private readonly bool m_octetAligned;
+
+        private bool m_first = true;
+        private int m_padBits = 0;
+
+        private Asn1BitStringParser m_currentParser;
+        private Stream m_currentStream;
+
+        internal ConstructedBitStream(Asn1StreamParser parser, bool octetAligned)
+        {
+            m_parser = parser;
+            m_octetAligned = octetAligned;
+        }
+
+        internal int PadBits
+        {
+            get { return m_padBits; }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (len < 1)
+                return 0;
+
+            if (m_currentStream == null)
+            {
+                if (!m_first)
+                    return 0;
+
+                m_currentParser = GetNextParser();
+                if (m_currentParser == null)
+                    return 0;
+
+                m_first = false;
+                m_currentStream = m_currentParser.GetBitStream();
+            }
+
+            int totalRead = 0;
+
+            for (;;)
+            {
+                int numRead = m_currentStream.Read(buf, off + totalRead, len - totalRead);
+
+                if (numRead > 0)
+                {
+                    totalRead += numRead;
+
+                    if (totalRead == len)
+                        return totalRead;
+                }
+                else
+                {
+                    m_padBits = m_currentParser.PadBits;
+                    m_currentParser = GetNextParser();
+                    if (m_currentParser == null)
+                    {
+                        m_currentStream = null;
+                        return totalRead;
+                    }
+
+                    m_currentStream = m_currentParser.GetBitStream();
+                }
+            }
+        }
+
+        public override int ReadByte()
+        {
+            if (m_currentStream == null)
+            {
+                if (!m_first)
+                    return -1;
+
+                m_currentParser = GetNextParser();
+                if (m_currentParser == null)
+                    return -1;
+
+                m_first = false;
+                m_currentStream = m_currentParser.GetBitStream();
+            }
+
+            for (;;)
+            {
+                int b = m_currentStream.ReadByte();
+
+                if (b >= 0)
+                    return b;
+
+                m_padBits = m_currentParser.PadBits;
+                m_currentParser = GetNextParser();
+                if (m_currentParser == null)
+                {
+                    m_currentStream = null;
+                    return -1;
+                }
+
+                m_currentStream = m_currentParser.GetBitStream();
+            }
+        }
+
+        private Asn1BitStringParser GetNextParser()
+        {
+            IAsn1Convertible asn1Obj = m_parser.ReadObject();
+            if (asn1Obj == null)
+            {
+                if (m_octetAligned && m_padBits != 0)
+                    throw new IOException("expected octet-aligned bitstring, but found padBits: " + m_padBits);
+
+                return null;
+            }
+
+            if (asn1Obj is Asn1BitStringParser)
+            {
+                if (m_padBits != 0)
+                    throw new IOException("only the last nested bitstring can have padding");
+
+                return (Asn1BitStringParser)asn1Obj;
+            }
+
+            throw new IOException("unknown object encountered: " + Platform.GetTypeName(asn1Obj));
+        }
+    }
+}