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