1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.geronimo.util.asn1;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.util.Enumeration;
24 import java.util.Vector;
25
26 abstract public class ASN1Set
27 extends DERObject
28 {
29 protected Vector set = new Vector();
30
31 /**
32 * return an ASN1Set from the given object.
33 *
34 * @param obj the object we want converted.
35 * @exception IllegalArgumentException if the object cannot be converted.
36 */
37 public static ASN1Set getInstance(
38 Object obj)
39 {
40 if (obj == null || obj instanceof ASN1Set)
41 {
42 return (ASN1Set)obj;
43 }
44
45 throw new IllegalArgumentException("unknown object in getInstance");
46 }
47
48 /**
49 * Return an ASN1 set from a tagged object. There is a special
50 * case here, if an object appears to have been explicitly tagged on
51 * reading but we were expecting it to be implictly tagged in the
52 * normal course of events it indicates that we lost the surrounding
53 * set - so we need to add it back (this will happen if the tagged
54 * object is a sequence that contains other sequences). If you are
55 * dealing with implicitly tagged sets you really <b>should</b>
56 * be using this method.
57 *
58 * @param obj the tagged object.
59 * @param explicit true if the object is meant to be explicitly tagged
60 * false otherwise.
61 * @exception IllegalArgumentException if the tagged object cannot
62 * be converted.
63 */
64 public static ASN1Set getInstance(
65 ASN1TaggedObject obj,
66 boolean explicit)
67 {
68 if (explicit)
69 {
70 if (!obj.isExplicit())
71 {
72 throw new IllegalArgumentException("object implicit - explicit expected.");
73 }
74
75 return (ASN1Set)obj.getObject();
76 }
77 else
78 {
79
80
81
82
83
84 if (obj.isExplicit())
85 {
86 ASN1Set set = new DERSet(obj.getObject());
87
88 return set;
89 }
90 else
91 {
92 if (obj.getObject() instanceof ASN1Set)
93 {
94 return (ASN1Set)obj.getObject();
95 }
96
97
98
99
100
101 ASN1EncodableVector v = new ASN1EncodableVector();
102
103 if (obj.getObject() instanceof ASN1Sequence)
104 {
105 ASN1Sequence s = (ASN1Sequence)obj.getObject();
106 Enumeration e = s.getObjects();
107
108 while (e.hasMoreElements())
109 {
110 v.add((DEREncodable)e.nextElement());
111 }
112
113 return new DERSet(v, false);
114 }
115 }
116 }
117
118 throw new IllegalArgumentException(
119 "unknown object in getInstanceFromTagged");
120 }
121
122 public ASN1Set()
123 {
124 }
125
126 public Enumeration getObjects()
127 {
128 return set.elements();
129 }
130
131 /**
132 * return the object at the set postion indicated by index.
133 *
134 * @param index the set number (starting at zero) of the object
135 * @return the object at the set postion indicated by index.
136 */
137 public DEREncodable getObjectAt(
138 int index)
139 {
140 return (DEREncodable)set.elementAt(index);
141 }
142
143 /**
144 * return the number of objects in this set.
145 *
146 * @return the number of objects in this set.
147 */
148 public int size()
149 {
150 return set.size();
151 }
152
153 public int hashCode()
154 {
155 Enumeration e = this.getObjects();
156 int hashCode = 0;
157
158 while (e.hasMoreElements())
159 {
160 hashCode ^= e.nextElement().hashCode();
161 }
162
163 return hashCode;
164 }
165
166 public boolean equals(
167 Object o)
168 {
169 if (o == null || !(o instanceof ASN1Set))
170 {
171 return false;
172 }
173
174 ASN1Set other = (ASN1Set)o;
175
176 if (this.size() != other.size())
177 {
178 return false;
179 }
180
181 Enumeration s1 = this.getObjects();
182 Enumeration s2 = other.getObjects();
183
184 while (s1.hasMoreElements())
185 {
186 if (!s1.nextElement().equals(s2.nextElement()))
187 {
188 return false;
189 }
190 }
191
192 return true;
193 }
194
195 /**
196 * return true if a <= b (arrays are assumed padded with zeros).
197 */
198 private boolean lessThanOrEqual(
199 byte[] a,
200 byte[] b)
201 {
202 if (a.length <= b.length)
203 {
204 for (int i = 0; i != a.length; i++)
205 {
206 int l = a[i] & 0xff;
207 int r = b[i] & 0xff;
208
209 if (r > l)
210 {
211 return true;
212 }
213 else if (l > r)
214 {
215 return false;
216 }
217 }
218
219 return true;
220 }
221 else
222 {
223 for (int i = 0; i != b.length; i++)
224 {
225 int l = a[i] & 0xff;
226 int r = b[i] & 0xff;
227
228 if (r > l)
229 {
230 return true;
231 }
232 else if (l > r)
233 {
234 return false;
235 }
236 }
237
238 return false;
239 }
240 }
241
242 private byte[] getEncoded(
243 DEREncodable obj)
244 {
245 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
246 ASN1OutputStream aOut = new ASN1OutputStream(bOut);
247
248 try
249 {
250 aOut.writeObject(obj);
251 }
252 catch (IOException e)
253 {
254 throw new IllegalArgumentException("cannot encode object added to SET");
255 }
256
257 return bOut.toByteArray();
258 }
259
260 protected void sort()
261 {
262 if (set.size() > 1)
263 {
264 boolean swapped = true;
265
266 while (swapped)
267 {
268 int index = 0;
269 byte[] a = getEncoded((DEREncodable)set.elementAt(0));
270
271 swapped = false;
272
273 while (index != set.size() - 1)
274 {
275 byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
276
277 if (lessThanOrEqual(a, b))
278 {
279 a = b;
280 }
281 else
282 {
283 Object o = set.elementAt(index);
284
285 set.setElementAt(set.elementAt(index + 1), index);
286 set.setElementAt(o, index + 1);
287
288 swapped = true;
289 }
290
291 index++;
292 }
293 }
294 }
295 }
296
297 protected void addObject(
298 DEREncodable obj)
299 {
300 set.addElement(obj);
301 }
302
303 abstract void encode(DEROutputStream out)
304 throws IOException;
305 }