001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004import java.io.OutputStream;
005
006/**
007 * Stream that produces output based on the default encoding for the passed in objects.
008 */
009public class ASN1OutputStream
010{
011    private OutputStream os;
012
013    public ASN1OutputStream(
014        OutputStream    os)
015    {
016        this.os = os;
017    }
018
019    void writeLength(
020        int length)
021        throws IOException
022    {
023        if (length > 127)
024        {
025            int size = 1;
026            int val = length;
027
028            while ((val >>>= 8) != 0)
029            {
030                size++;
031            }
032
033            write((byte)(size | 0x80));
034
035            for (int i = (size - 1) * 8; i >= 0; i -= 8)
036            {
037                write((byte)(length >> i));
038            }
039        }
040        else
041        {
042            write((byte)length);
043        }
044    }
045
046    void write(int b)
047        throws IOException
048    {
049        os.write(b);
050    }
051
052    void write(byte[] bytes)
053        throws IOException
054    {
055        os.write(bytes);
056    }
057
058    void write(byte[] bytes, int off, int len)
059        throws IOException
060    {
061        os.write(bytes, off, len);
062    }
063
064    void writeEncoded(
065        int     tag,
066        byte[]  bytes)
067        throws IOException
068    {
069        write(tag);
070        writeLength(bytes.length);
071        write(bytes);
072    }
073
074    void writeTag(int flags, int tagNo)
075        throws IOException
076    {
077        if (tagNo < 31)
078        {
079            write(flags | tagNo);
080        }
081        else
082        {
083            write(flags | 0x1f);
084            if (tagNo < 128)
085            {
086                write(tagNo);
087            }
088            else
089            {
090                byte[] stack = new byte[5];
091                int pos = stack.length;
092
093                stack[--pos] = (byte)(tagNo & 0x7F);
094
095                do
096                {
097                    tagNo >>= 7;
098                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
099                }
100                while (tagNo > 127);
101
102                write(stack, pos, stack.length - pos);
103            }
104        }
105    }
106
107    void writeEncoded(int flags, int tagNo, byte[] bytes)
108        throws IOException
109    {
110        writeTag(flags, tagNo);
111        writeLength(bytes.length);
112        write(bytes);
113    }
114
115    protected void writeNull()
116        throws IOException
117    {
118        os.write(BERTags.NULL);
119        os.write(0x00);
120    }
121
122    public void writeObject(
123        ASN1Encodable obj)
124        throws IOException
125    {
126        if (obj != null)
127        {
128            obj.toASN1Primitive().encode(this);
129        }
130        else
131        {
132            throw new IOException("null object detected");
133        }
134    }
135
136    void writeImplicitObject(ASN1Primitive obj)
137        throws IOException
138    {
139        if (obj != null)
140        {
141            obj.encode(new ImplicitOutputStream(os));
142        }
143        else
144        {
145            throw new IOException("null object detected");
146        }
147    }
148
149    public void close()
150        throws IOException
151    {
152        os.close();
153    }
154
155    public void flush()
156        throws IOException
157    {
158        os.flush();
159    }
160
161    ASN1OutputStream getDERSubStream()
162    {
163        return new DEROutputStream(os);
164    }
165
166    ASN1OutputStream getDLSubStream()
167    {
168        return new DLOutputStream(os);
169    }
170
171    private class ImplicitOutputStream
172        extends ASN1OutputStream
173    {
174        private boolean first = true;
175
176        public ImplicitOutputStream(OutputStream os)
177        {
178            super(os);
179        }
180
181        public void write(int b)
182            throws IOException
183        {
184            if (first)
185            {
186                first = false;
187            }
188            else
189            {
190                super.write(b);
191            }
192        }
193    }
194}