001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.util.asn1;
019
020 import java.io.ByteArrayOutputStream;
021 import java.io.IOException;
022 import java.util.Enumeration;
023 import java.util.Vector;
024
025 abstract public class ASN1Set
026 extends DERObject
027 {
028 protected Vector set = new Vector();
029
030 /**
031 * return an ASN1Set from the given object.
032 *
033 * @param obj the object we want converted.
034 * @exception IllegalArgumentException if the object cannot be converted.
035 */
036 public static ASN1Set getInstance(
037 Object obj)
038 {
039 if (obj == null || obj instanceof ASN1Set)
040 {
041 return (ASN1Set)obj;
042 }
043
044 throw new IllegalArgumentException("unknown object in getInstance");
045 }
046
047 /**
048 * Return an ASN1 set from a tagged object. There is a special
049 * case here, if an object appears to have been explicitly tagged on
050 * reading but we were expecting it to be implictly tagged in the
051 * normal course of events it indicates that we lost the surrounding
052 * set - so we need to add it back (this will happen if the tagged
053 * object is a sequence that contains other sequences). If you are
054 * dealing with implicitly tagged sets you really <b>should</b>
055 * be using this method.
056 *
057 * @param obj the tagged object.
058 * @param explicit true if the object is meant to be explicitly tagged
059 * false otherwise.
060 * @exception IllegalArgumentException if the tagged object cannot
061 * be converted.
062 */
063 public static ASN1Set getInstance(
064 ASN1TaggedObject obj,
065 boolean explicit)
066 {
067 if (explicit)
068 {
069 if (!obj.isExplicit())
070 {
071 throw new IllegalArgumentException("object implicit - explicit expected.");
072 }
073
074 return (ASN1Set)obj.getObject();
075 }
076 else
077 {
078 //
079 // constructed object which appears to be explicitly tagged
080 // and it's really implicit means we have to add the
081 // surrounding sequence.
082 //
083 if (obj.isExplicit())
084 {
085 ASN1Set set = new DERSet(obj.getObject());
086
087 return set;
088 }
089 else
090 {
091 if (obj.getObject() instanceof ASN1Set)
092 {
093 return (ASN1Set)obj.getObject();
094 }
095
096 //
097 // in this case the parser returns a sequence, convert it
098 // into a set.
099 //
100 ASN1EncodableVector v = new ASN1EncodableVector();
101
102 if (obj.getObject() instanceof ASN1Sequence)
103 {
104 ASN1Sequence s = (ASN1Sequence)obj.getObject();
105 Enumeration e = s.getObjects();
106
107 while (e.hasMoreElements())
108 {
109 v.add((DEREncodable)e.nextElement());
110 }
111
112 return new DERSet(v, false);
113 }
114 }
115 }
116
117 throw new IllegalArgumentException(
118 "unknown object in getInstanceFromTagged");
119 }
120
121 public ASN1Set()
122 {
123 }
124
125 public Enumeration getObjects()
126 {
127 return set.elements();
128 }
129
130 /**
131 * return the object at the set postion indicated by index.
132 *
133 * @param index the set number (starting at zero) of the object
134 * @return the object at the set postion indicated by index.
135 */
136 public DEREncodable getObjectAt(
137 int index)
138 {
139 return (DEREncodable)set.elementAt(index);
140 }
141
142 /**
143 * return the number of objects in this set.
144 *
145 * @return the number of objects in this set.
146 */
147 public int size()
148 {
149 return set.size();
150 }
151
152 public int hashCode()
153 {
154 Enumeration e = this.getObjects();
155 int hashCode = 0;
156
157 while (e.hasMoreElements())
158 {
159 hashCode ^= e.nextElement().hashCode();
160 }
161
162 return hashCode;
163 }
164
165 public boolean equals(
166 Object o)
167 {
168 if (o == null || !(o instanceof ASN1Set))
169 {
170 return false;
171 }
172
173 ASN1Set other = (ASN1Set)o;
174
175 if (this.size() != other.size())
176 {
177 return false;
178 }
179
180 Enumeration s1 = this.getObjects();
181 Enumeration s2 = other.getObjects();
182
183 while (s1.hasMoreElements())
184 {
185 if (!s1.nextElement().equals(s2.nextElement()))
186 {
187 return false;
188 }
189 }
190
191 return true;
192 }
193
194 /**
195 * return true if a <= b (arrays are assumed padded with zeros).
196 */
197 private boolean lessThanOrEqual(
198 byte[] a,
199 byte[] b)
200 {
201 if (a.length <= b.length)
202 {
203 for (int i = 0; i != a.length; i++)
204 {
205 int l = a[i] & 0xff;
206 int r = b[i] & 0xff;
207
208 if (r > l)
209 {
210 return true;
211 }
212 else if (l > r)
213 {
214 return false;
215 }
216 }
217
218 return true;
219 }
220 else
221 {
222 for (int i = 0; i != b.length; i++)
223 {
224 int l = a[i] & 0xff;
225 int r = b[i] & 0xff;
226
227 if (r > l)
228 {
229 return true;
230 }
231 else if (l > r)
232 {
233 return false;
234 }
235 }
236
237 return false;
238 }
239 }
240
241 private byte[] getEncoded(
242 DEREncodable obj)
243 {
244 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
245 ASN1OutputStream aOut = new ASN1OutputStream(bOut);
246
247 try
248 {
249 aOut.writeObject(obj);
250 }
251 catch (IOException e)
252 {
253 throw new IllegalArgumentException("cannot encode object added to SET", e);
254 }
255
256 return bOut.toByteArray();
257 }
258
259 protected void sort()
260 {
261 if (set.size() > 1)
262 {
263 boolean swapped = true;
264
265 while (swapped)
266 {
267 int index = 0;
268 byte[] a = getEncoded((DEREncodable)set.elementAt(0));
269
270 swapped = false;
271
272 while (index != set.size() - 1)
273 {
274 byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
275
276 if (lessThanOrEqual(a, b))
277 {
278 a = b;
279 }
280 else
281 {
282 Object o = set.elementAt(index);
283
284 set.setElementAt(set.elementAt(index + 1), index);
285 set.setElementAt(o, index + 1);
286
287 swapped = true;
288 }
289
290 index++;
291 }
292 }
293 }
294 }
295
296 protected void addObject(
297 DEREncodable obj)
298 {
299 set.addElement(obj);
300 }
301
302 abstract void encode(DEROutputStream out)
303 throws IOException;
304 }