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