package org.bouncycastle.asn1;

import java.io.IOException;
import java.io.InputStream;

class ConstructedOctetStream
    extends InputStream
{
    private final ASN1StreamParser _parser;

    private boolean                _first = true;
    private InputStream            _currentStream;

    ConstructedOctetStream(
        ASN1StreamParser parser)
    {
        _parser = parser;
    }

    public int read(byte[] b, int off, int len) throws IOException
    {
        if (_currentStream == null)
        {
            if (!_first)
            {
                return -1;
            }

            ASN1Encodable asn1Obj = _parser.readObject();
            if (asn1Obj == null)
            {
                return -1;
            }

            if (!(asn1Obj instanceof ASN1OctetStringParser))
            {
                throw new IOException("unknown object encountered: " + asn1Obj.getClass());
            }

            ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj;

            _first = false;
            _currentStream = s.getOctetStream();
        }

        int totalRead = 0;

        for (;;)
        {
            int numRead = _currentStream.read(b, off + totalRead, len - totalRead);

            if (numRead >= 0)
            {
                totalRead += numRead;

                if (totalRead == len)
                {
                    return totalRead;
                }
            }
            else
            {
                ASN1Encodable asn1Obj = _parser.readObject();

                if (asn1Obj == null)
                {
                    _currentStream = null;
                    return totalRead < 1 ? -1 : totalRead;
                }

                if (!(asn1Obj instanceof ASN1OctetStringParser))
                {
                    throw new IOException("unknown object encountered: " + asn1Obj.getClass());
                }

                ASN1OctetStringParser aos = (ASN1OctetStringParser)asn1Obj;

                _currentStream = aos.getOctetStream();
            }
        }
    }

    public int read()
        throws IOException
    {
        if (_currentStream == null)
        {
            if (!_first)
            {
                return -1;
            }

            ASN1Encodable asn1Obj = _parser.readObject();
    
            if (asn1Obj == null)
            {
                return -1;
            }

            if (!(asn1Obj instanceof ASN1OctetStringParser))
            {
                throw new IOException("unknown object encountered: " + asn1Obj.getClass());
            }

            ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj;

            _first = false;
            _currentStream = s.getOctetStream();
        }

        for (;;)
        {
            int b = _currentStream.read();

            if (b >= 0)
            {
                return b;
            }

            ASN1Encodable asn1Obj = _parser.readObject();

            if (asn1Obj == null)
            {
                _currentStream = null;
                return -1;
            }

            if (!(asn1Obj instanceof ASN1OctetStringParser))
            {
                throw new IOException("unknown object encountered: " + asn1Obj.getClass());
            }

            ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj;

            _currentStream = s.getOctetStream();
        }
    }
}

@@ -604,46 +604,46 @@
 ASN1
-Encodable asn1Obj = _parser.readObject
+OctetStringParser next = getNextParser
 ();%0A
@@ -650,39 +650,36 @@
             if (
-asn1Obj
+next
  == null)%0A      
@@ -732,261 +732,8 @@
  %7D%0A%0A
-            if (!(asn1Obj instanceof ASN1OctetStringParser))%0A            %7B%0A                throw new IOException(%22unknown object encountered: %22 + asn1Obj.getClass());%0A            %7D%0A%0A            ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj;%0A%0A
     
@@ -777,33 +777,36 @@
 currentStream = 
-s
+next
 .getOctetStream(
@@ -1223,51 +1223,50 @@
 ASN1
-Encodable asn1Obj = _parser.readObject
+OctetStringParser next = getNextParser
 ();%0A
-%0A
     
@@ -1273,39 +1273,36 @@
             if (
-asn1Obj
+next
  == null)%0A      
@@ -1438,283 +1438,8 @@
  %7D%0A%0A
-                if (!(asn1Obj instanceof ASN1OctetStringParser))%0A                %7B%0A                    throw new IOException(%22unknown object encountered: %22 + asn1Obj.getClass());%0A                %7D%0A%0A                ASN1OctetStringParser aos = (ASN1OctetStringParser)asn1Obj;%0A%0A
     
@@ -1471,11 +1471,12 @@
 m = 
-aos
+next
 .get
@@ -1723,54 +1723,49 @@
 ASN1
-Encodable asn1Obj = _parser.readObject();%0A    
+OctetStringParser next = getNextParser();
 %0A   
@@ -1769,39 +1769,36 @@
             if (
-asn1Obj
+next
  == null)%0A      
@@ -1851,261 +1851,8 @@
  %7D%0A%0A
-            if (!(asn1Obj instanceof ASN1OctetStringParser))%0A            %7B%0A                throw new IOException(%22unknown object encountered: %22 + asn1Obj.getClass());%0A            %7D%0A%0A            ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj;%0A%0A
     
@@ -1896,33 +1896,36 @@
 currentStream = 
-s
+next
 .getOctetStream(
@@ -2108,51 +2108,50 @@
 ASN1
-Encodable asn1Obj = _parser.readObject
+OctetStringParser next = getNextParser
 ();%0A
-%0A
     
@@ -2162,23 +2162,20 @@
     if (
-asn1Obj
+next
  == null
@@ -2287,56 +2287,47 @@
     
-if (!(asn1Obj instanceof ASN1OctetStringParser))
+_currentStream = next.getOctetStream();
 %0A   
@@ -2335,39 +2335,73 @@
     
+%7D%0A
     
-%7B
+%7D%0A
 %0A    
-           
+private ASN1OctetStringParser getNextParser()
  throw
- new
+s
  IOE
@@ -2412,115 +2412,226 @@
 tion
-(%22unknown object encountered: %22 + asn1Obj.getClass());%0A            %7D%0A%0A            ASN1OctetStringParser s =
+%0A    %7B%0A        ASN1Encodable asn1Obj = _parser.readObject();%0A        if (asn1Obj == null)%0A        %7B%0A            return null;%0A        %7D%0A%0A        if (asn1Obj instanceof ASN1OctetStringParser)%0A        %7B%0A            return
  (AS
@@ -2659,29 +2659,35 @@
 sn1Obj;%0A
-%0A
+   
     
+ %7D%0A%0A
         
 _current
@@ -2682,54 +2682,83 @@
     
-_currentStream = s.getOctetStream();%0A        %7D
+throw new IOException(%22unknown object encountered: %22 + asn1Obj.getClass());
 %0A   

Factor out method