001: package org.bouncycastle.asn1;
002:
003: import java.io.IOException;
004: import java.util.Enumeration;
005: import java.util.Vector;
006:
007: public abstract class ASN1Sequence extends ASN1Object {
008: private Vector seq = new Vector();
009:
010: /**
011: * return an ASN1Sequence from the given object.
012: *
013: * @param obj the object we want converted.
014: * @exception IllegalArgumentException if the object cannot be converted.
015: */
016: public static ASN1Sequence getInstance(Object obj) {
017: if (obj == null || obj instanceof ASN1Sequence) {
018: return (ASN1Sequence) obj;
019: }
020:
021: throw new IllegalArgumentException(
022: "unknown object in getInstance");
023: }
024:
025: /**
026: * Return an ASN1 sequence from a tagged object. There is a special
027: * case here, if an object appears to have been explicitly tagged on
028: * reading but we were expecting it to be implictly tagged in the
029: * normal course of events it indicates that we lost the surrounding
030: * sequence - so we need to add it back (this will happen if the tagged
031: * object is a sequence that contains other sequences). If you are
032: * dealing with implicitly tagged sequences you really <b>should</b>
033: * be using this method.
034: *
035: * @param obj the tagged object.
036: * @param explicit true if the object is meant to be explicitly tagged,
037: * false otherwise.
038: * @exception IllegalArgumentException if the tagged object cannot
039: * be converted.
040: */
041: public static ASN1Sequence getInstance(ASN1TaggedObject obj,
042: boolean explicit) {
043: if (explicit) {
044: if (!obj.isExplicit()) {
045: throw new IllegalArgumentException(
046: "object implicit - explicit expected.");
047: }
048:
049: return (ASN1Sequence) obj.getObject();
050: } else {
051: //
052: // constructed object which appears to be explicitly tagged
053: // when it should be implicit means we have to add the
054: // surrounding sequence.
055: //
056: if (obj.isExplicit()) {
057: if (obj instanceof BERTaggedObject) {
058: return new BERSequence(obj.getObject());
059: } else {
060: return new DERSequence(obj.getObject());
061: }
062: } else {
063: if (obj.getObject() instanceof ASN1Sequence) {
064: return (ASN1Sequence) obj.getObject();
065: }
066: }
067: }
068:
069: throw new IllegalArgumentException(
070: "unknown object in getInstanceFromTagged");
071: }
072:
073: public Enumeration getObjects() {
074: return seq.elements();
075: }
076:
077: public ASN1SequenceParser parser() {
078: final ASN1Sequence outer = this ;
079:
080: return new ASN1SequenceParser() {
081: private final int max = size();
082:
083: private int index;
084:
085: public DEREncodable readObject() throws IOException {
086: if (index == max) {
087: return null;
088: }
089:
090: DEREncodable obj = getObjectAt(index++);
091: if (obj instanceof ASN1Sequence) {
092: return ((ASN1Sequence) obj).parser();
093: }
094: if (obj instanceof ASN1Set) {
095: return ((ASN1Set) obj).parser();
096: }
097:
098: return obj;
099: }
100:
101: public DERObject getDERObject() {
102: return outer;
103: }
104: };
105: }
106:
107: /**
108: * return the object at the sequence postion indicated by index.
109: *
110: * @param index the sequence number (starting at zero) of the object
111: * @return the object at the sequence postion indicated by index.
112: */
113: public DEREncodable getObjectAt(int index) {
114: return (DEREncodable) seq.elementAt(index);
115: }
116:
117: /**
118: * return the number of objects in this sequence.
119: *
120: * @return the number of objects in this sequence.
121: */
122: public int size() {
123: return seq.size();
124: }
125:
126: public int hashCode() {
127: Enumeration e = this .getObjects();
128: int hashCode = 0;
129:
130: while (e.hasMoreElements()) {
131: Object o = e.nextElement();
132:
133: if (o != null) {
134: hashCode ^= o.hashCode();
135: }
136: }
137:
138: return hashCode;
139: }
140:
141: boolean asn1Equals(DERObject o) {
142: if (!(o instanceof ASN1Sequence)) {
143: return false;
144: }
145:
146: ASN1Sequence other = (ASN1Sequence) o;
147:
148: if (this .size() != other.size()) {
149: return false;
150: }
151:
152: Enumeration s1 = this .getObjects();
153: Enumeration s2 = other.getObjects();
154:
155: while (s1.hasMoreElements()) {
156: DERObject o1 = ((DEREncodable) s1.nextElement())
157: .getDERObject();
158: DERObject o2 = ((DEREncodable) s2.nextElement())
159: .getDERObject();
160:
161: if (o1 == o2 || (o1 != null && o1.equals(o2))) {
162: continue;
163: }
164:
165: return false;
166: }
167:
168: return true;
169: }
170:
171: protected void addObject(DEREncodable obj) {
172: seq.addElement(obj);
173: }
174:
175: abstract void encode(DEROutputStream out) throws IOException;
176:
177: public String toString() {
178: return seq.toString();
179: }
180: }
|