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