001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004import java.util.Enumeration;
005
006/**
007 * A DER encoded set object
008 */
009public class DERSet
010    extends ASN1Set
011{
012    private int bodyLength = -1;
013
014    /**
015     * create an empty set
016     */
017    public DERSet()
018    {
019    }
020
021    /**
022     * @param obj - a single object that makes up the set.
023     */
024    public DERSet(
025        ASN1Encodable obj)
026    {
027        super(obj);
028    }
029
030    /**
031     * @param v - a vector of objects making up the set.
032     */
033    public DERSet(
034        ASN1EncodableVector v)
035    {
036        super(v, true);
037    }
038    
039    /**
040     * create a set from an array of objects.
041     */
042    public DERSet(
043        ASN1Encodable[]   a)
044    {
045        super(a, true);
046    }
047
048    DERSet(
049        ASN1EncodableVector v,
050        boolean                  doSort)
051    {
052        super(v, doSort);
053    }
054
055    private int getBodyLength()
056        throws IOException
057    {
058        if (bodyLength < 0)
059        {
060            int length = 0;
061
062            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
063            {
064                Object    obj = e.nextElement();
065
066                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
067            }
068
069            bodyLength = length;
070        }
071
072        return bodyLength;
073    }
074
075    int encodedLength()
076        throws IOException
077    {
078        int length = getBodyLength();
079
080        return 1 + StreamUtil.calculateBodyLength(length) + length;
081    }
082
083    /*
084     * A note on the implementation:
085     * <p>
086     * As DER requires the constructed, definite-length model to
087     * be used for structured types, this varies slightly from the
088     * ASN.1 descriptions given. Rather than just outputting SET,
089     * we also have to specify CONSTRUCTED, and the objects length.
090     */
091    void encode(
092        ASN1OutputStream out)
093        throws IOException
094    {
095        ASN1OutputStream        dOut = out.getDERSubStream();
096        int                     length = getBodyLength();
097
098        out.write(BERTags.SET | BERTags.CONSTRUCTED);
099        out.writeLength(length);
100
101        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
102        {
103            Object    obj = e.nextElement();
104
105            dOut.writeObject((ASN1Encodable)obj);
106        }
107    }
108}