1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5/**
6 * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by
7 * a [n] where n is some number - these are assumed to follow the construction
8 * rules (as with sequences).
9 */
10public class DLTaggedObject
11    extends ASN1TaggedObject
12{
13    private static final byte[] ZERO_BYTES = new byte[0];
14
15    /**
16     * @param explicit true if an explicitly tagged object.
17     * @param tagNo the tag number for this object.
18     * @param obj the tagged object.
19     */
20    public DLTaggedObject(
21        boolean explicit,
22        int tagNo,
23        ASN1Encodable obj)
24    {
25        super(explicit, tagNo, obj);
26    }
27
28    boolean isConstructed()
29    {
30        if (!empty)
31        {
32            if (explicit)
33            {
34                return true;
35            }
36            else
37            {
38                ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
39
40                return primitive.isConstructed();
41            }
42        }
43        else
44        {
45            return true;
46        }
47    }
48
49    int encodedLength()
50        throws IOException
51    {
52        if (!empty)
53        {
54            int length = obj.toASN1Primitive().toDLObject().encodedLength();
55
56            if (explicit)
57            {
58                return  StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
59            }
60            else
61            {
62                // header length already in calculation
63                length = length - 1;
64
65                return StreamUtil.calculateTagLength(tagNo) + length;
66            }
67        }
68        else
69        {
70            return StreamUtil.calculateTagLength(tagNo) + 1;
71        }
72    }
73
74    void encode(
75        ASN1OutputStream out)
76        throws IOException
77    {
78        if (!empty)
79        {
80            ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
81
82            if (explicit)
83            {
84                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
85                out.writeLength(primitive.encodedLength());
86                out.writeObject(primitive);
87            }
88            else
89            {
90                //
91                // need to mark constructed types...
92                //
93                int flags;
94                if (primitive.isConstructed())
95                {
96                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
97                }
98                else
99                {
100                    flags = BERTags.TAGGED;
101                }
102
103                out.writeTag(flags, tagNo);
104                out.writeImplicitObject(primitive);
105            }
106        }
107        else
108        {
109            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
110        }
111    }
112}
113