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