107cc13f2dabf661793da548707cbaf2cb672635
[org.ibex.core.git] / src / org / bouncycastle / asn1 / DERInputStream.java
1 package org.bouncycastle.asn1;
2
3 import java.io.FilterInputStream;
4
5 import java.io.InputStream;
6 import java.io.ByteArrayInputStream;
7 import java.io.IOException;
8 import java.io.EOFException;
9
10
11 public class DERInputStream
12     extends FilterInputStream implements DERTags
13 {
14     public DERInputStream(
15         InputStream is)
16     {
17         super(is);
18     }
19
20     protected int readLength()
21         throws IOException
22     {
23         int length = read();
24         if (length < 0)
25         {
26             throw new IOException("EOF found when length expected");
27         }
28
29         if (length == 0x80)
30         {
31             return -1;      // indefinite-length encoding
32         }
33
34         if (length > 127)
35         {
36             int size = length & 0x7f;
37
38             length = 0;
39             for (int i = 0; i < size; i++)
40             {
41                 int next = read();
42
43                 if (next < 0)
44                 {
45                     throw new IOException("EOF found reading length");
46                 }
47
48                 length = (length << 8) + next;
49             }
50         }
51
52         return length;
53     }
54
55     protected void readFully(
56         byte[]  bytes)
57         throws IOException
58     {
59         int     left = bytes.length;
60
61         if (left == 0)
62         {
63             return;
64         }
65
66         while ((left -= read(bytes, bytes.length - left, left)) != 0)
67         {
68             ;
69         }
70     }
71
72         /**
73          * build an object given its tag and a byte stream to construct it
74          * from.
75          */
76     protected DERObject buildObject(
77                 int         tag,
78                 byte[]  bytes)
79                 throws IOException
80         {
81                 switch (tag)
82         {
83         case NULL:
84             return null;   
85         case SEQUENCE | CONSTRUCTED:
86             ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
87             BERInputStream          dIn = new BERInputStream(bIn);
88             DERConstructedSequence  seq = new DERConstructedSequence();
89
90             try
91             {
92                 for (;;)
93                 {
94                     DERObject   obj = dIn.readObject();
95
96                     seq.addObject(obj);
97                 }
98             }
99             catch (EOFException ex)
100             {
101                 return seq;
102             }
103         case SET | CONSTRUCTED:
104             bIn = new ByteArrayInputStream(bytes);
105             dIn = new BERInputStream(bIn);
106
107             DEREncodableVector    v = new DEREncodableVector();
108
109             try
110             {
111                 for (;;)
112                 {
113                     DERObject   obj = dIn.readObject();
114
115                     v.add(obj);
116                 }
117             }
118             catch (EOFException ex)
119             {
120                 return new DERConstructedSet(v);
121             }
122         case BOOLEAN:
123             return new DERBoolean(bytes);
124         case INTEGER:
125             return new DERInteger(bytes);
126         case ENUMERATED:
127             return new DEREnumerated(bytes);
128         case OBJECT_IDENTIFIER:
129             return new DERObjectIdentifier(bytes);
130         case BIT_STRING:
131             int     padBits = bytes[0];
132             byte[]  data = new byte[bytes.length - 1];
133
134             System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
135
136             return new DERBitString(data, padBits);
137         case UTF8_STRING:
138             return new DERUTF8String(bytes);
139         case PRINTABLE_STRING:
140             return new DERPrintableString(bytes);
141         case IA5_STRING:
142             return new DERIA5String(bytes);
143         case T61_STRING:
144             return new DERT61String(bytes);
145         case VISIBLE_STRING:
146             return new DERVisibleString(bytes);
147         case UNIVERSAL_STRING:
148             return new DERUniversalString(bytes);
149         case BMP_STRING:
150             return new DERBMPString(bytes);
151         case OCTET_STRING:
152             return new DEROctetString(bytes);
153         case UTC_TIME:
154             return new DERUTCTime(bytes);
155         case GENERALIZED_TIME:
156             return new DERGeneralizedTime(bytes);
157         default:
158             //
159             // with tagged object tag number is bottom 5 bits
160             //
161             if ((tag & TAGGED) != 0)  
162             {
163                 if ((tag & 0x1f) == 0x1f)
164                 {
165                     throw new IOException("unsupported high tag encountered");
166                 }
167
168                 if (bytes.length == 0)        // empty tag!
169                 {
170                     return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
171                 }
172
173                 //
174                 // simple type - implicit... return an octet string
175                 //
176                 if ((tag & CONSTRUCTED) == 0)
177                 {
178                     return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
179                 }
180
181                 bIn = new ByteArrayInputStream(bytes);
182                 dIn = new BERInputStream(bIn);
183
184                 DEREncodable dObj = dIn.readObject();
185
186                 //
187                 // explicitly tagged (probably!) - if it isn't we'd have to
188                 // tell from the context
189                 //
190                 if (dIn.available() == 0)
191                 {
192                     return new DERTaggedObject(tag & 0x1f, dObj);
193                 }
194
195                 //
196                 // another implicit object, we'll create a sequence...
197                 //
198                 seq = new DERConstructedSequence();
199
200                 seq.addObject(dObj);
201
202                 try
203                 {
204                     for (;;)
205                     {
206                         dObj = dIn.readObject();
207
208                         seq.addObject(dObj);
209                     }
210                 }
211                 catch (EOFException ex)
212                 {
213                     // ignore --
214                 }
215
216                 return new DERTaggedObject(false, tag & 0x1f, seq);
217             }
218
219             return new DERUnknownTag(tag, bytes);
220         }
221         }
222
223     public DERObject readObject()
224         throws IOException
225     {
226         int tag = read();
227         if (tag == -1)
228         {
229             throw new EOFException();
230         }
231
232         int     length = readLength();
233         byte[]  bytes = new byte[length];
234
235         readFully(bytes);
236
237                 return buildObject(tag, bytes);
238         }
239 }