001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004import java.util.Enumeration;
005
006/**
007 * The DLSet encodes ASN.1 SET value without element ordering,
008 * and always using definite length form.
009 * <hr>
010 * <h2>X.690</h2>
011 * <h3>8: Basic encoding rules</h3>
012 * <h4>8.11 Encoding of a set value </h4>
013 * <b>8.11.1</b> The encoding of a set value shall be constructed
014 * <p>
015 * <b>8.11.2</b> The contents octets shall consist of the complete
016 * encoding of a data value from each of the types listed in the
017 * ASN.1 definition of the set type, in an order chosen by the sender,
018 * unless the type was referenced with the keyword
019 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
020 * <p>
021 * <b>8.11.3</b> The encoding of a data value may, but need not,
022 * be present for a type which was referenced with the keyword
023 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
024 * <blockquote>
025 * NOTE &mdash; The order of data values in a set value is not significant,
026 * and places no constraints on the order during transfer
027 * </blockquote>
028 * <h3>9: Canonical encoding rules</h3>
029 * <h4>9.3 Set components</h4>
030 * The encodings of the component values of a set value shall
031 * appear in an order determined by their tags as specified
032 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
033 * Additionally, for the purposes of determining the order in which
034 * components are encoded when one or more component is an untagged
035 * choice type, each untagged choice type is ordered as though it
036 * has a tag equal to that of the smallest tag in that choice type
037 * or any untagged choice types nested within.
038 * <h3>10: Distinguished encoding rules</h3>
039 * <h4>10.3 Set components</h4>
040 * The encodings of the component values of a set value shall appear
041 * in an order determined by their tags as specified
042 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
043 * <blockquote>
044 * NOTE &mdash; Where a component of the set is an untagged choice type,
045 * the location of that component in the ordering will depend on
046 * the tag of the choice component being encoded.
047 * </blockquote>
048 * <h3>11: Restrictions on BER employed by both CER and DER</h3>
049 * <h4>11.5 Set and sequence components with default value </h4>
050 * The encoding of a set value or sequence value shall not include
051 * an encoding for any component value which is equal to
052 * its default value.
053 */
054public class DLSet
055    extends ASN1Set
056{
057    private int bodyLength = -1;
058
059    /**
060     * create an empty set
061     */
062    public DLSet()
063    {
064    }
065
066    /**
067     * @param obj - a single object that makes up the set.
068     */
069    public DLSet(
070        ASN1Encodable obj)
071    {
072        super(obj);
073    }
074
075    /**
076     * @param v - a vector of objects making up the set.
077     */
078    public DLSet(
079        ASN1EncodableVector v)
080    {
081        super(v, false);
082    }
083
084    /**
085     * create a set from an array of objects.
086     */
087    public DLSet(
088        ASN1Encodable[] a)
089    {
090        super(a, false);
091    }
092
093    private int getBodyLength()
094        throws IOException
095    {
096        if (bodyLength < 0)
097        {
098            int length = 0;
099
100            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
101            {
102                Object obj = e.nextElement();
103
104                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
105            }
106
107            bodyLength = length;
108        }
109
110        return bodyLength;
111    }
112
113    int encodedLength()
114        throws IOException
115    {
116        int length = getBodyLength();
117
118        return 1 + StreamUtil.calculateBodyLength(length) + length;
119    }
120
121    /**
122     * A note on the implementation:
123     * <p>
124     * As DL requires the constructed, definite-length model to
125     * be used for structured types, this varies slightly from the
126     * ASN.1 descriptions given. Rather than just outputting SET,
127     * we also have to specify CONSTRUCTED, and the objects length.
128     */
129    void encode(
130        ASN1OutputStream out)
131        throws IOException
132    {
133        ASN1OutputStream dOut = out.getDLSubStream();
134        int length = getBodyLength();
135
136        out.write(BERTags.SET | BERTags.CONSTRUCTED);
137        out.writeLength(length);
138
139        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
140        {
141            Object obj = e.nextElement();
142
143            dOut.writeObject((ASN1Encodable)obj);
144        }
145    }
146}