1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4import java.util.Enumeration;
5
6/**
7 * The DLSet encodes ASN.1 SET value without element ordering,
8 * and always using definite length form.
9 * <hr>
10 * <h2>X.690</h2>
11 * <h3>8: Basic encoding rules</h3>
12 * <h4>8.11 Encoding of a set value </h4>
13 * <b>8.11.1</b> The encoding of a set value shall be constructed
14 * <p>
15 * <b>8.11.2</b> The contents octets shall consist of the complete
16 * encoding of a data value from each of the types listed in the
17 * ASN.1 definition of the set type, in an order chosen by the sender,
18 * unless the type was referenced with the keyword
19 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
20 * <p>
21 * <b>8.11.3</b> The encoding of a data value may, but need not,
22 * be present for a type which was referenced with the keyword
23 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
24 * <blockquote>
25 * NOTE &mdash; The order of data values in a set value is not significant,
26 * and places no constraints on the order during transfer
27 * </blockquote>
28 * <h3>9: Canonical encoding rules</h3>
29 * <h4>9.3 Set components</h4>
30 * The encodings of the component values of a set value shall
31 * appear in an order determined by their tags as specified
32 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
33 * Additionally, for the purposes of determining the order in which
34 * components are encoded when one or more component is an untagged
35 * choice type, each untagged choice type is ordered as though it
36 * has a tag equal to that of the smallest tag in that choice type
37 * or any untagged choice types nested within.
38 * <h3>10: Distinguished encoding rules</h3>
39 * <h4>10.3 Set components</h4>
40 * The encodings of the component values of a set value shall appear
41 * in an order determined by their tags as specified
42 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
43 * <blockquote>
44 * NOTE &mdash; Where a component of the set is an untagged choice type,
45 * the location of that component in the ordering will depend on
46 * the tag of the choice component being encoded.
47 * </blockquote>
48 * <h3>11: Restrictions on BER employed by both CER and DER</h3>
49 * <h4>11.5 Set and sequence components with default value </h4>
50 * The encoding of a set value or sequence value shall not include
51 * an encoding for any component value which is equal to
52 * its default value.
53 */
54public class DLSet
55    extends ASN1Set
56{
57    private int bodyLength = -1;
58
59    /**
60     * create an empty set
61     */
62    public DLSet()
63    {
64    }
65
66    /**
67     * @param obj - a single object that makes up the set.
68     */
69    public DLSet(
70        ASN1Encodable obj)
71    {
72        super(obj);
73    }
74
75    /**
76     * @param v - a vector of objects making up the set.
77     */
78    public DLSet(
79        ASN1EncodableVector v)
80    {
81        super(v, false);
82    }
83
84    /**
85     * create a set from an array of objects.
86     */
87    public DLSet(
88        ASN1Encodable[] a)
89    {
90        super(a, false);
91    }
92
93    private int getBodyLength()
94        throws IOException
95    {
96        if (bodyLength < 0)
97        {
98            int length = 0;
99
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}