1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4import java.io.OutputStream;
5
6/**
7 * Stream that produces output based on the default encoding for the passed in objects.
8 */
9public class ASN1OutputStream
10{
11    private OutputStream os;
12
13    public ASN1OutputStream(
14        OutputStream    os)
15    {
16        this.os = os;
17    }
18
19    void writeLength(
20        int length)
21        throws IOException
22    {
23        if (length > 127)
24        {
25            int size = 1;
26            int val = length;
27
28            while ((val >>>= 8) != 0)
29            {
30                size++;
31            }
32
33            write((byte)(size | 0x80));
34
35            for (int i = (size - 1) * 8; i >= 0; i -= 8)
36            {
37                write((byte)(length >> i));
38            }
39        }
40        else
41        {
42            write((byte)length);
43        }
44    }
45
46    void write(int b)
47        throws IOException
48    {
49        os.write(b);
50    }
51
52    void write(byte[] bytes)
53        throws IOException
54    {
55        os.write(bytes);
56    }
57
58    void write(byte[] bytes, int off, int len)
59        throws IOException
60    {
61        os.write(bytes, off, len);
62    }
63
64    void writeEncoded(
65        int     tag,
66        byte[]  bytes)
67        throws IOException
68    {
69        write(tag);
70        writeLength(bytes.length);
71        write(bytes);
72    }
73
74    void writeTag(int flags, int tagNo)
75        throws IOException
76    {
77        if (tagNo < 31)
78        {
79            write(flags | tagNo);
80        }
81        else
82        {
83            write(flags | 0x1f);
84            if (tagNo < 128)
85            {
86                write(tagNo);
87            }
88            else
89            {
90                byte[] stack = new byte[5];
91                int pos = stack.length;
92
93                stack[--pos] = (byte)(tagNo & 0x7F);
94
95                do
96                {
97                    tagNo >>= 7;
98                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
99                }
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}
195