~brian-thomason/+junk/bouncycastle

« back to all changes in this revision

Viewing changes to src/org/bouncycastle/asn1/ASN1Set.java

  • Committer: Brian Thomason
  • Date: 2011-12-20 17:20:32 UTC
  • Revision ID: brian.thomason@canonical.com-20111220172032-rdtm13jgdxtksacr
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.bouncycastle.asn1;
 
2
 
 
3
import java.io.ByteArrayOutputStream;
 
4
import java.io.IOException;
 
5
import java.util.Enumeration;
 
6
import java.util.Vector;
 
7
 
 
8
abstract public class ASN1Set
 
9
    extends ASN1Object
 
10
{
 
11
    protected Vector set = new Vector();
 
12
 
 
13
    /**
 
14
     * return an ASN1Set from the given object.
 
15
     *
 
16
     * @param obj the object we want converted.
 
17
     * @exception IllegalArgumentException if the object cannot be converted.
 
18
     */
 
19
    public static ASN1Set getInstance(
 
20
        Object  obj)
 
21
    {
 
22
        if (obj == null || obj instanceof ASN1Set)
 
23
        {
 
24
            return (ASN1Set)obj;
 
25
        }
 
26
 
 
27
        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
 
28
    }
 
29
 
 
30
    /**
 
31
     * Return an ASN1 set from a tagged object. There is a special
 
32
     * case here, if an object appears to have been explicitly tagged on 
 
33
     * reading but we were expecting it to be implicitly tagged in the 
 
34
     * normal course of events it indicates that we lost the surrounding
 
35
     * set - so we need to add it back (this will happen if the tagged
 
36
     * object is a sequence that contains other sequences). If you are
 
37
     * dealing with implicitly tagged sets you really <b>should</b>
 
38
     * be using this method.
 
39
     *
 
40
     * @param obj the tagged object.
 
41
     * @param explicit true if the object is meant to be explicitly tagged
 
42
     *          false otherwise.
 
43
     * @exception IllegalArgumentException if the tagged object cannot
 
44
     *          be converted.
 
45
     */
 
46
    public static ASN1Set getInstance(
 
47
        ASN1TaggedObject    obj,
 
48
        boolean             explicit)
 
49
    {
 
50
        if (explicit)
 
51
        {
 
52
            if (!obj.isExplicit())
 
53
            {
 
54
                throw new IllegalArgumentException("object implicit - explicit expected.");
 
55
            }
 
56
 
 
57
            return (ASN1Set)obj.getObject();
 
58
        }
 
59
        else
 
60
        {
 
61
            //
 
62
            // constructed object which appears to be explicitly tagged
 
63
            // and it's really implicit means we have to add the
 
64
            // surrounding sequence.
 
65
            //
 
66
            if (obj.isExplicit())
 
67
            {
 
68
                ASN1Set    set = new DERSet(obj.getObject());
 
69
 
 
70
                return set;
 
71
            }
 
72
            else
 
73
            {
 
74
                if (obj.getObject() instanceof ASN1Set)
 
75
                {
 
76
                    return (ASN1Set)obj.getObject();
 
77
                }
 
78
 
 
79
                //
 
80
                // in this case the parser returns a sequence, convert it
 
81
                // into a set.
 
82
                //
 
83
                ASN1EncodableVector  v = new ASN1EncodableVector();
 
84
 
 
85
                if (obj.getObject() instanceof ASN1Sequence)
 
86
                {
 
87
                    ASN1Sequence s = (ASN1Sequence)obj.getObject();
 
88
                    Enumeration e = s.getObjects();
 
89
 
 
90
                    while (e.hasMoreElements())
 
91
                    {
 
92
                        v.add((DEREncodable)e.nextElement());
 
93
                    }
 
94
 
 
95
                    return new DERSet(v, false);
 
96
                }
 
97
            }
 
98
        }
 
99
 
 
100
        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
 
101
    }
 
102
 
 
103
    public ASN1Set()
 
104
    {
 
105
    }
 
106
 
 
107
    public Enumeration getObjects()
 
108
    {
 
109
        return set.elements();
 
110
    }
 
111
 
 
112
    /**
 
113
     * return the object at the set position indicated by index.
 
114
     *
 
115
     * @param index the set number (starting at zero) of the object
 
116
     * @return the object at the set position indicated by index.
 
117
     */
 
118
    public DEREncodable getObjectAt(
 
119
        int index)
 
120
    {
 
121
        return (DEREncodable)set.elementAt(index);
 
122
    }
 
123
 
 
124
    /**
 
125
     * return the number of objects in this set.
 
126
     *
 
127
     * @return the number of objects in this set.
 
128
     */
 
129
    public int size()
 
130
    {
 
131
        return set.size();
 
132
    }
 
133
 
 
134
    public ASN1Encodable[] toArray()
 
135
    {
 
136
        ASN1Encodable[] values = new ASN1Encodable[this.size()];
 
137
 
 
138
        for (int i = 0; i != this.size(); i++)
 
139
        {
 
140
            values[i] = (ASN1Encodable)this.getObjectAt(i);
 
141
        }
 
142
 
 
143
        return values;
 
144
    }
 
145
 
 
146
    public ASN1SetParser parser()
 
147
    {
 
148
        final ASN1Set outer = this;
 
149
 
 
150
        return new ASN1SetParser()
 
151
        {
 
152
            private final int max = size();
 
153
 
 
154
            private int index;
 
155
 
 
156
            public DEREncodable readObject() throws IOException
 
157
            {
 
158
                if (index == max)
 
159
                {
 
160
                    return null;
 
161
                }
 
162
 
 
163
                DEREncodable obj = getObjectAt(index++);
 
164
                if (obj instanceof ASN1Sequence)
 
165
                {
 
166
                    return ((ASN1Sequence)obj).parser();
 
167
                }
 
168
                if (obj instanceof ASN1Set)
 
169
                {
 
170
                    return ((ASN1Set)obj).parser();
 
171
                }
 
172
 
 
173
                return obj;
 
174
            }
 
175
 
 
176
            public DERObject getLoadedObject()
 
177
            {
 
178
                return outer;
 
179
            }
 
180
 
 
181
            public DERObject getDERObject()
 
182
            {
 
183
                return outer;
 
184
            }
 
185
        };
 
186
    }
 
187
 
 
188
    public int hashCode()
 
189
    {
 
190
        Enumeration             e = this.getObjects();
 
191
        int                     hashCode = size();
 
192
 
 
193
        while (e.hasMoreElements())
 
194
        {
 
195
            Object o = getNext(e);
 
196
            hashCode *= 17;
 
197
 
 
198
            hashCode ^= o.hashCode();
 
199
        }
 
200
 
 
201
        return hashCode;
 
202
    }
 
203
 
 
204
    boolean asn1Equals(
 
205
        DERObject  o)
 
206
    {
 
207
        if (!(o instanceof ASN1Set))
 
208
        {
 
209
            return false;
 
210
        }
 
211
 
 
212
        ASN1Set   other = (ASN1Set)o;
 
213
 
 
214
        if (this.size() != other.size())
 
215
        {
 
216
            return false;
 
217
        }
 
218
 
 
219
        Enumeration s1 = this.getObjects();
 
220
        Enumeration s2 = other.getObjects();
 
221
 
 
222
        while (s1.hasMoreElements())
 
223
        {
 
224
            DEREncodable  obj1 = getNext(s1);
 
225
            DEREncodable  obj2 = getNext(s2);
 
226
 
 
227
            DERObject  o1 = obj1.getDERObject();
 
228
            DERObject  o2 = obj2.getDERObject();
 
229
 
 
230
            if (o1 == o2 || o1.equals(o2))
 
231
            {
 
232
                continue;
 
233
            }
 
234
 
 
235
            return false;
 
236
        }
 
237
 
 
238
        return true;
 
239
    }
 
240
 
 
241
    private DEREncodable getNext(Enumeration e)
 
242
    {
 
243
        DEREncodable encObj = (DEREncodable)e.nextElement();
 
244
 
 
245
        // unfortunately null was allowed as a substitute for DER null
 
246
        if (encObj == null)
 
247
        {
 
248
            return DERNull.INSTANCE;
 
249
        }
 
250
 
 
251
        return encObj;
 
252
    }
 
253
 
 
254
    /**
 
255
     * return true if a <= b (arrays are assumed padded with zeros).
 
256
     */
 
257
    private boolean lessThanOrEqual(
 
258
         byte[] a,
 
259
         byte[] b)
 
260
    {
 
261
        int len = Math.min(a.length, b.length);
 
262
        for (int i = 0; i != len; ++i)
 
263
        {
 
264
            if (a[i] != b[i])
 
265
            {
 
266
                return (a[i] & 0xff) < (b[i] & 0xff);
 
267
            }
 
268
        }
 
269
        return len == a.length;
 
270
    }
 
271
 
 
272
    private byte[] getEncoded(
 
273
        DEREncodable obj)
 
274
    {
 
275
        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
 
276
        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
 
277
 
 
278
        try
 
279
        {
 
280
            aOut.writeObject(obj);
 
281
        }
 
282
        catch (IOException e)
 
283
        {
 
284
            throw new IllegalArgumentException("cannot encode object added to SET");
 
285
        }
 
286
 
 
287
        return bOut.toByteArray();
 
288
    }
 
289
 
 
290
    protected void sort()
 
291
    {
 
292
        if (set.size() > 1)
 
293
        {
 
294
            boolean    swapped = true;
 
295
            int        lastSwap = set.size() - 1;
 
296
 
 
297
            while (swapped)
 
298
            {
 
299
                int    index = 0;
 
300
                int    swapIndex = 0;
 
301
                byte[] a = getEncoded((DEREncodable)set.elementAt(0));
 
302
                
 
303
                swapped = false;
 
304
 
 
305
                while (index != lastSwap)
 
306
                {
 
307
                    byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
 
308
 
 
309
                    if (lessThanOrEqual(a, b))
 
310
                    {
 
311
                        a = b;
 
312
                    }
 
313
                    else
 
314
                    {
 
315
                        Object  o = set.elementAt(index);
 
316
 
 
317
                        set.setElementAt(set.elementAt(index + 1), index);
 
318
                        set.setElementAt(o, index + 1);
 
319
 
 
320
                        swapped = true;
 
321
                        swapIndex = index;
 
322
                    }
 
323
 
 
324
                    index++;
 
325
                }
 
326
 
 
327
                lastSwap = swapIndex;
 
328
            }
 
329
        }
 
330
    }
 
331
 
 
332
    protected void addObject(
 
333
        DEREncodable obj)
 
334
    {
 
335
        set.addElement(obj);
 
336
    }
 
337
 
 
338
    abstract void encode(DEROutputStream out)
 
339
            throws IOException;
 
340
 
 
341
    public String toString() 
 
342
    {
 
343
      return set.toString();
 
344
    }
 
345
}