1package org.bouncycastle.asn1; 2 3import java.io.IOException; 4import java.util.Enumeration; 5import java.util.Vector; 6 7public abstract class ASN1Sequence 8 extends ASN1Primitive 9{ 10 protected Vector seq = new Vector(); 11 12 /** 13 * return an ASN1Sequence from the given object. 14 * 15 * @param obj the object we want converted. 16 * @exception IllegalArgumentException if the object cannot be converted. 17 */ 18 public static ASN1Sequence getInstance( 19 Object obj) 20 { 21 if (obj == null || obj instanceof ASN1Sequence) 22 { 23 return (ASN1Sequence)obj; 24 } 25 else if (obj instanceof ASN1SequenceParser) 26 { 27 return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive()); 28 } 29 else if (obj instanceof byte[]) 30 { 31 try 32 { 33 return ASN1Sequence.getInstance(fromByteArray((byte[])obj)); 34 } 35 catch (IOException e) 36 { 37 throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); 38 } 39 } 40 else if (obj instanceof ASN1Encodable) 41 { 42 ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); 43 44 if (primitive instanceof ASN1Sequence) 45 { 46 return (ASN1Sequence)primitive; 47 } 48 } 49 50 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 51 } 52 53 /** 54 * Return an ASN1 sequence from a tagged object. There is a special 55 * case here, if an object appears to have been explicitly tagged on 56 * reading but we were expecting it to be implicitly tagged in the 57 * normal course of events it indicates that we lost the surrounding 58 * sequence - so we need to add it back (this will happen if the tagged 59 * object is a sequence that contains other sequences). If you are 60 * dealing with implicitly tagged sequences you really <b>should</b> 61 * be using this method. 62 * 63 * @param obj the tagged object. 64 * @param explicit true if the object is meant to be explicitly tagged, 65 * false otherwise. 66 * @exception IllegalArgumentException if the tagged object cannot 67 * be converted. 68 */ 69 public static ASN1Sequence getInstance( 70 ASN1TaggedObject obj, 71 boolean explicit) 72 { 73 if (explicit) 74 { 75 if (!obj.isExplicit()) 76 { 77 throw new IllegalArgumentException("object implicit - explicit expected."); 78 } 79 80 return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive()); 81 } 82 else 83 { 84 // 85 // constructed object which appears to be explicitly tagged 86 // when it should be implicit means we have to add the 87 // surrounding sequence. 88 // 89 if (obj.isExplicit()) 90 { 91 if (obj instanceof BERTaggedObject) 92 { 93 return new BERSequence(obj.getObject()); 94 } 95 else 96 { 97 return new DLSequence(obj.getObject()); 98 } 99 } 100 else 101 { 102 if (obj.getObject() instanceof ASN1Sequence) 103 { 104 return (ASN1Sequence)obj.getObject(); 105 } 106 } 107 } 108 109 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 110 } 111 112 /** 113 * create an empty sequence 114 */ 115 protected ASN1Sequence() 116 { 117 } 118 119 /** 120 * create a sequence containing one object 121 */ 122 protected ASN1Sequence( 123 ASN1Encodable obj) 124 { 125 seq.addElement(obj); 126 } 127 128 /** 129 * create a sequence containing a vector of objects. 130 */ 131 protected ASN1Sequence( 132 ASN1EncodableVector v) 133 { 134 for (int i = 0; i != v.size(); i++) 135 { 136 seq.addElement(v.get(i)); 137 } 138 } 139 140 /** 141 * create a sequence containing a vector of objects. 142 */ 143 protected ASN1Sequence( 144 ASN1Encodable[] array) 145 { 146 for (int i = 0; i != array.length; i++) 147 { 148 seq.addElement(array[i]); 149 } 150 } 151 152 public ASN1Encodable[] toArray() 153 { 154 ASN1Encodable[] values = new ASN1Encodable[this.size()]; 155 156 for (int i = 0; i != this.size(); i++) 157 { 158 values[i] = this.getObjectAt(i); 159 } 160 161 return values; 162 } 163 164 public Enumeration getObjects() 165 { 166 return seq.elements(); 167 } 168 169 public ASN1SequenceParser parser() 170 { 171 final ASN1Sequence outer = this; 172 173 return new ASN1SequenceParser() 174 { 175 private final int max = size(); 176 177 private int index; 178 179 public ASN1Encodable readObject() throws IOException 180 { 181 if (index == max) 182 { 183 return null; 184 } 185 186 ASN1Encodable obj = getObjectAt(index++); 187 if (obj instanceof ASN1Sequence) 188 { 189 return ((ASN1Sequence)obj).parser(); 190 } 191 if (obj instanceof ASN1Set) 192 { 193 return ((ASN1Set)obj).parser(); 194 } 195 196 return obj; 197 } 198 199 public ASN1Primitive getLoadedObject() 200 { 201 return outer; 202 } 203 204 public ASN1Primitive toASN1Primitive() 205 { 206 return outer; 207 } 208 }; 209 } 210 211 /** 212 * return the object at the sequence position indicated by index. 213 * 214 * @param index the sequence number (starting at zero) of the object 215 * @return the object at the sequence position indicated by index. 216 */ 217 public ASN1Encodable getObjectAt( 218 int index) 219 { 220 return (ASN1Encodable)seq.elementAt(index); 221 } 222 223 /** 224 * return the number of objects in this sequence. 225 * 226 * @return the number of objects in this sequence. 227 */ 228 public int size() 229 { 230 return seq.size(); 231 } 232 233 public int hashCode() 234 { 235 Enumeration e = this.getObjects(); 236 int hashCode = size(); 237 238 while (e.hasMoreElements()) 239 { 240 Object o = getNext(e); 241 hashCode *= 17; 242 243 hashCode ^= o.hashCode(); 244 } 245 246 return hashCode; 247 } 248 249 boolean asn1Equals( 250 ASN1Primitive o) 251 { 252 if (!(o instanceof ASN1Sequence)) 253 { 254 return false; 255 } 256 257 ASN1Sequence other = (ASN1Sequence)o; 258 259 if (this.size() != other.size()) 260 { 261 return false; 262 } 263 264 Enumeration s1 = this.getObjects(); 265 Enumeration s2 = other.getObjects(); 266 267 while (s1.hasMoreElements()) 268 { 269 ASN1Encodable obj1 = getNext(s1); 270 ASN1Encodable obj2 = getNext(s2); 271 272 ASN1Primitive o1 = obj1.toASN1Primitive(); 273 ASN1Primitive o2 = obj2.toASN1Primitive(); 274 275 if (o1 == o2 || o1.equals(o2)) 276 { 277 continue; 278 } 279 280 return false; 281 } 282 283 return true; 284 } 285 286 private ASN1Encodable getNext(Enumeration e) 287 { 288 ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); 289 290 return encObj; 291 } 292 293 ASN1Primitive toDERObject() 294 { 295 ASN1Sequence derSeq = new DERSequence(); 296 297 derSeq.seq = this.seq; 298 299 return derSeq; 300 } 301 302 ASN1Primitive toDLObject() 303 { 304 ASN1Sequence dlSeq = new DLSequence(); 305 306 dlSeq.seq = this.seq; 307 308 return dlSeq; 309 } 310 311 boolean isConstructed() 312 { 313 return true; 314 } 315 316 abstract void encode(ASN1OutputStream out) 317 throws IOException; 318 319 public String toString() 320 { 321 return seq.toString(); 322 } 323} 324