1 package org.bouncycastle.asn1;
2 
3 import java.io.IOException;
4 
5 /**
6  * The DLSequence encodes a SEQUENCE using definite length form.
7  */
8 public class DLSequence
9     extends ASN1Sequence
10 {
11     private int bodyLength = -1;
12 
13     /**
14      * Create an empty sequence
15      */
DLSequence()16     public DLSequence()
17     {
18     }
19 
20     /**
21      * create a sequence containing one object
22      * @param element the object to go in the sequence.
23      */
DLSequence(ASN1Encodable element)24     public DLSequence(ASN1Encodable element)
25     {
26         super(element);
27     }
28 
29     /**
30      * create a sequence containing a vector of objects.
31      * @param elementVector the vector of objects to make up the sequence.
32      */
DLSequence(ASN1EncodableVector elementVector)33     public DLSequence(ASN1EncodableVector elementVector)
34     {
35         super(elementVector);
36     }
37 
38     /**
39      * create a sequence containing an array of objects.
40      * @param elements the array of objects to make up the sequence.
41      */
DLSequence(ASN1Encodable[] elements)42     public DLSequence(ASN1Encodable[] elements)
43     {
44         super(elements);
45     }
46 
DLSequence(ASN1Encodable[] elements, boolean clone)47     DLSequence(ASN1Encodable[] elements, boolean clone)
48     {
49         super(elements, clone);
50     }
51 
getBodyLength()52     private int getBodyLength() throws IOException
53     {
54         if (bodyLength < 0)
55         {
56             int count = elements.length;
57             int totalLength = 0;
58 
59             for (int i = 0; i < count; ++i)
60             {
61                 ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject();
62                 totalLength += dlObject.encodedLength();
63             }
64 
65             this.bodyLength = totalLength;
66         }
67 
68         return bodyLength;
69     }
70 
encodedLength()71     int encodedLength() throws IOException
72     {
73         int length = getBodyLength();
74 
75         return 1 + StreamUtil.calculateBodyLength(length) + length;
76     }
77 
78     /**
79      * A note on the implementation:
80      * <p>
81      * As DL requires the constructed, definite-length model to
82      * be used for structured types, this varies slightly from the
83      * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
84      * we also have to specify CONSTRUCTED, and the objects length.
85      */
encode(ASN1OutputStream out, boolean withTag)86     void encode(ASN1OutputStream out, boolean withTag) throws IOException
87     {
88         if (withTag)
89         {
90             out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
91         }
92 
93         ASN1OutputStream dlOut = out.getDLSubStream();
94 
95         int count = elements.length;
96         if (bodyLength >= 0 || count > 16)
97         {
98             out.writeLength(getBodyLength());
99 
100             for (int i = 0; i < count; ++i)
101             {
102                 dlOut.writePrimitive(elements[i].toASN1Primitive(), true);
103             }
104         }
105         else
106         {
107             int totalLength = 0;
108 
109             ASN1Primitive[] dlObjects = new ASN1Primitive[count];
110             for (int i = 0; i < count; ++i)
111             {
112                 ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject();
113                 dlObjects[i] = dlObject;
114                 totalLength += dlObject.encodedLength();
115             }
116 
117             this.bodyLength = totalLength;
118             out.writeLength(totalLength);
119 
120             for (int i = 0; i < count; ++i)
121             {
122                 dlOut.writePrimitive(dlObjects[i], true);
123             }
124         }
125     }
126 
toDLObject()127     ASN1Primitive toDLObject()
128     {
129         return this;
130     }
131 }