diff options
Diffstat (limited to 'crypto/src/asn1/ConstructedBitStream.cs')
-rw-r--r-- | crypto/src/asn1/ConstructedBitStream.cs | 134 |
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)); + } + } +} |