    001package org.apache.commons.ssl.asn1;
    002
    003import java.io.IOException;
    004import java.util.Enumeration;
    005import java.util.Vector;
    006
    007public 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}