ASN1Set.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.asn1; 2 3import java.io.ByteArrayOutputStream; 4import java.io.IOException; 5import java.util.Enumeration; 6import java.util.Vector; 7 8abstract public class ASN1Set 9 extends ASN1Primitive 10{ 11 private Vector set = new Vector(); 12 private boolean isSorted = false; 13 14 /** 15 * return an ASN1Set from the given object. 16 * 17 * @param obj the object we want converted. 18 * @exception IllegalArgumentException if the object cannot be converted. 19 */ 20 public static ASN1Set getInstance( 21 Object obj) 22 { 23 if (obj == null || obj instanceof ASN1Set) 24 { 25 return (ASN1Set)obj; 26 } 27 else if (obj instanceof ASN1SetParser) 28 { 29 return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive()); 30 } 31 else if (obj instanceof byte[]) 32 { 33 try 34 { 35 return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); 36 } 37 catch (IOException e) 38 { 39 throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage()); 40 } 41 } 42 else if (obj instanceof ASN1Encodable) 43 { 44 ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); 45 46 if (primitive instanceof ASN1Set) 47 { 48 return (ASN1Set)primitive; 49 } 50 } 51 52 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 53 } 54 55 /** 56 * Return an ASN1 set from a tagged object. There is a special 57 * case here, if an object appears to have been explicitly tagged on 58 * reading but we were expecting it to be implicitly tagged in the 59 * normal course of events it indicates that we lost the surrounding 60 * set - so we need to add it back (this will happen if the tagged 61 * object is a sequence that contains other sequences). If you are 62 * dealing with implicitly tagged sets you really <b>should</b> 63 * be using this method. 64 * 65 * @param obj the tagged object. 66 * @param explicit true if the object is meant to be explicitly tagged 67 * false otherwise. 68 * @exception IllegalArgumentException if the tagged object cannot 69 * be converted. 70 */ 71 public static ASN1Set getInstance( 72 ASN1TaggedObject obj, 73 boolean explicit) 74 { 75 if (explicit) 76 { 77 if (!obj.isExplicit()) 78 { 79 throw new IllegalArgumentException("object implicit - explicit expected."); 80 } 81 82 return (ASN1Set)obj.getObject(); 83 } 84 else 85 { 86 // 87 // constructed object which appears to be explicitly tagged 88 // and it's really implicit means we have to add the 89 // surrounding set. 90 // 91 if (obj.isExplicit()) 92 { 93 if (obj instanceof BERTaggedObject) 94 { 95 return new BERSet(obj.getObject()); 96 } 97 else 98 { 99 return new DLSet(obj.getObject()); 100 } 101 } 102 else 103 { 104 if (obj.getObject() instanceof ASN1Set) 105 { 106 return (ASN1Set)obj.getObject(); 107 } 108 109 // 110 // in this case the parser returns a sequence, convert it 111 // into a set. 112 // 113 114 115 ASN1EncodableVector v = new ASN1EncodableVector(); 116 117 if (obj.getObject() instanceof ASN1Sequence) 118 { 119 ASN1Sequence s = (ASN1Sequence)obj.getObject(); 120 121 if (obj instanceof BERTaggedObject) 122 { 123 return new BERSet(s.toArray()); 124 } 125 else 126 { 127 return new DLSet(s.toArray()); 128 } 129 } 130 } 131 } 132 133 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 134 } 135 136 protected ASN1Set() 137 { 138 } 139 140 /** 141 * create a sequence containing one object 142 */ 143 protected ASN1Set( 144 ASN1Encodable obj) 145 { 146 set.addElement(obj); 147 } 148 149 /** 150 * create a sequence containing a vector of objects. 151 */ 152 protected ASN1Set( 153 ASN1EncodableVector v, 154 boolean doSort) 155 { 156 for (int i = 0; i != v.size(); i++) 157 { 158 set.addElement(v.get(i)); 159 } 160 161 if (doSort) 162 { 163 this.sort(); 164 } 165 } 166 167 /** 168 * create a sequence containing a vector of objects. 169 */ 170 protected ASN1Set( 171 ASN1Encodable[] array, 172 boolean doSort) 173 { 174 for (int i = 0; i != array.length; i++) 175 { 176 set.addElement(array[i]); 177 } 178 179 if (doSort) 180 { 181 this.sort(); 182 } 183 } 184 185 public Enumeration getObjects() 186 { 187 return set.elements(); 188 } 189 190 /** 191 * return the object at the set position indicated by index. 192 * 193 * @param index the set number (starting at zero) of the object 194 * @return the object at the set position indicated by index. 195 */ 196 public ASN1Encodable getObjectAt( 197 int index) 198 { 199 return (ASN1Encodable)set.elementAt(index); 200 } 201 202 /** 203 * return the number of objects in this set. 204 * 205 * @return the number of objects in this set. 206 */ 207 public int size() 208 { 209 return set.size(); 210 } 211 212 public ASN1Encodable[] toArray() 213 { 214 ASN1Encodable[] values = new ASN1Encodable[this.size()]; 215 216 for (int i = 0; i != this.size(); i++) 217 { 218 values[i] = this.getObjectAt(i); 219 } 220 221 return values; 222 } 223 224 public ASN1SetParser parser() 225 { 226 final ASN1Set outer = this; 227 228 return new ASN1SetParser() 229 { 230 private final int max = size(); 231 232 private int index; 233 234 public ASN1Encodable readObject() throws IOException 235 { 236 if (index == max) 237 { 238 return null; 239 } 240 241 ASN1Encodable obj = getObjectAt(index++); 242 if (obj instanceof ASN1Sequence) 243 { 244 return ((ASN1Sequence)obj).parser(); 245 } 246 if (obj instanceof ASN1Set) 247 { 248 return ((ASN1Set)obj).parser(); 249 } 250 251 return obj; 252 } 253 254 public ASN1Primitive getLoadedObject() 255 { 256 return outer; 257 } 258 259 public ASN1Primitive toASN1Primitive() 260 { 261 return outer; 262 } 263 }; 264 } 265 266 public int hashCode() 267 { 268 Enumeration e = this.getObjects(); 269 int hashCode = size(); 270 271 while (e.hasMoreElements()) 272 { 273 Object o = getNext(e); 274 hashCode *= 17; 275 276 hashCode ^= o.hashCode(); 277 } 278 279 return hashCode; 280 } 281 282 ASN1Primitive toDERObject() 283 { 284 if (isSorted) 285 { 286 ASN1Set derSet = new DERSet(); 287 288 derSet.set = this.set; 289 290 return derSet; 291 } 292 else 293 { 294 Vector v = new Vector(); 295 296 for (int i = 0; i != set.size(); i++) 297 { 298 v.addElement(set.elementAt(i)); 299 } 300 301 ASN1Set derSet = new DERSet(); 302 303 derSet.set = v; 304 305 derSet.sort(); 306 307 return derSet; 308 } 309 } 310 311 ASN1Primitive toDLObject() 312 { 313 ASN1Set derSet = new DLSet(); 314 315 derSet.set = this.set; 316 317 return derSet; 318 } 319 320 boolean asn1Equals( 321 ASN1Primitive o) 322 { 323 if (!(o instanceof ASN1Set)) 324 { 325 return false; 326 } 327 328 ASN1Set other = (ASN1Set)o; 329 330 if (this.size() != other.size()) 331 { 332 return false; 333 } 334 335 Enumeration s1 = this.getObjects(); 336 Enumeration s2 = other.getObjects(); 337 338 while (s1.hasMoreElements()) 339 { 340 ASN1Encodable obj1 = getNext(s1); 341 ASN1Encodable obj2 = getNext(s2); 342 343 ASN1Primitive o1 = obj1.toASN1Primitive(); 344 ASN1Primitive o2 = obj2.toASN1Primitive(); 345 346 if (o1 == o2 || o1.equals(o2)) 347 { 348 continue; 349 } 350 351 return false; 352 } 353 354 return true; 355 } 356 357 private ASN1Encodable getNext(Enumeration e) 358 { 359 ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); 360 361 // unfortunately null was allowed as a substitute for DER null 362 if (encObj == null) 363 { 364 return DERNull.INSTANCE; 365 } 366 367 return encObj; 368 } 369 370 /** 371 * return true if a <= b (arrays are assumed padded with zeros). 372 */ 373 private boolean lessThanOrEqual( 374 byte[] a, 375 byte[] b) 376 { 377 int len = Math.min(a.length, b.length); 378 for (int i = 0; i != len; ++i) 379 { 380 if (a[i] != b[i]) 381 { 382 return (a[i] & 0xff) < (b[i] & 0xff); 383 } 384 } 385 return len == a.length; 386 } 387 388 private byte[] getEncoded( 389 ASN1Encodable obj) 390 { 391 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 392 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 393 394 try 395 { 396 aOut.writeObject(obj); 397 } 398 catch (IOException e) 399 { 400 throw new IllegalArgumentException("cannot encode object added to SET"); 401 } 402 403 return bOut.toByteArray(); 404 } 405 406 protected void sort() 407 { 408 if (!isSorted) 409 { 410 isSorted = true; 411 if (set.size() > 1) 412 { 413 boolean swapped = true; 414 int lastSwap = set.size() - 1; 415 416 while (swapped) 417 { 418 int index = 0; 419 int swapIndex = 0; 420 byte[] a = getEncoded((ASN1Encodable)set.elementAt(0)); 421 422 swapped = false; 423 424 while (index != lastSwap) 425 { 426 byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1)); 427 428 if (lessThanOrEqual(a, b)) 429 { 430 a = b; 431 } 432 else 433 { 434 Object o = set.elementAt(index); 435 436 set.setElementAt(set.elementAt(index + 1), index); 437 set.setElementAt(o, index + 1); 438 439 swapped = true; 440 swapIndex = index; 441 } 442 443 index++; 444 } 445 446 lastSwap = swapIndex; 447 } 448 } 449 } 450 } 451 452 boolean isConstructed() 453 { 454 return true; 455 } 456 457 abstract void encode(ASN1OutputStream out) 458 throws IOException; 459 460 public String toString() 461 { 462 return set.toString(); 463 } 464} 465