001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.geronimo.util.asn1;
020
021 import java.io.ByteArrayOutputStream;
022 import java.io.IOException;
023 import java.util.Enumeration;
024 import java.util.Vector;
025
026 abstract public class ASN1Set
027 extends DERObject
028 {
029 protected Vector set = new Vector();
030
031 /**
032 * return an ASN1Set from the given object.
033 *
034 * @param obj the object we want converted.
035 * @exception IllegalArgumentException if the object cannot be converted.
036 */
037 public static ASN1Set getInstance(
038 Object obj)
039 {
040 if (obj == null || obj instanceof ASN1Set)
041 {
042 return (ASN1Set)obj;
043 }
044
045 throw new IllegalArgumentException("unknown object in getInstance");
046 }
047
048 /**
049 * Return an ASN1 set from a tagged object. There is a special
050 * case here, if an object appears to have been explicitly tagged on
051 * reading but we were expecting it to be implictly tagged in the
052 * normal course of events it indicates that we lost the surrounding
053 * set - so we need to add it back (this will happen if the tagged
054 * object is a sequence that contains other sequences). If you are
055 * dealing with implicitly tagged sets you really <b>should</b>
056 * be using this method.
057 *
058 * @param obj the tagged object.
059 * @param explicit true if the object is meant to be explicitly tagged
060 * false otherwise.
061 * @exception IllegalArgumentException if the tagged object cannot
062 * be converted.
063 */
064 public static ASN1Set getInstance(
065 ASN1TaggedObject obj,
066 boolean explicit)
067 {
068 if (explicit)
069 {
070 if (!obj.isExplicit())
071 {
072 throw new IllegalArgumentException("object implicit - explicit expected.");
073 }
074
075 return (ASN1Set)obj.getObject();
076 }
077 else
078 {
079 //
080 // constructed object which appears to be explicitly tagged
081 // and it's really implicit means we have to add the
082 // surrounding sequence.
083 //
084 if (obj.isExplicit())
085 {
086 ASN1Set set = new DERSet(obj.getObject());
087
088 return set;
089 }
090 else
091 {
092 if (obj.getObject() instanceof ASN1Set)
093 {
094 return (ASN1Set)obj.getObject();
095 }
096
097 //
098 // in this case the parser returns a sequence, convert it
099 // into a set.
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 }