1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5/**
6 * DER 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 DERTaggedObject
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 DERTaggedObject(
21        boolean       explicit,
22        int           tagNo,
23        ASN1Encodable obj)
24    {
25        super(explicit, tagNo, obj);
26    }
27
28    public DERTaggedObject(int tagNo, ASN1Encodable encodable)
29    {
30        super(true, tagNo, encodable);
31    }
32
33    boolean isConstructed()
34    {
35        if (!empty)
36        {
37            if (explicit)
38            {
39                return true;
40            }
41            else
42            {
43                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
44
45                return primitive.isConstructed();
46            }
47        }
48        else
49        {
50            return true;
51        }
52    }
53
54    int encodedLength()
55        throws IOException
56    {
57        if (!empty)
58        {
59            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
60            int length = primitive.encodedLength();
61
62            if (explicit)
63            {
64                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
65            }
66            else
67            {
68                // header length already in calculation
69                length = length - 1;
70
71                return StreamUtil.calculateTagLength(tagNo) + length;
72            }
73        }
74        else
75        {
76            return StreamUtil.calculateTagLength(tagNo) + 1;
77        }
78    }
79
80    void encode(
81        ASN1OutputStream out)
82        throws IOException
83    {
84        if (!empty)
85        {
86            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
87
88            if (explicit)
89            {
90                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
91                out.writeLength(primitive.encodedLength());
92                out.writeObject(primitive);
93            }
94            else
95            {
96                //
97                // need to mark constructed types...
98                //
99                int flags;
100                if (primitive.isConstructed())
101                {
102                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
103                }
104                else
105                {
106                    flags = BERTags.TAGGED;
107                }
108
109                out.writeTag(flags, tagNo);
110                out.writeImplicitObject(primitive);
111            }
112        }
113        else
114        {
115            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
116        }
117    }
118}
119