BERTaggedObject.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4import java.util.Enumeration;
5
6/**
7 * BER TaggedObject - in ASN.1 notation this is any object preceded by
8 * a [n] where n is some number - these are assumed to follow the construction
9 * rules (as with sequences).
10 */
11public class BERTaggedObject
12    extends ASN1TaggedObject
13{
14    /**
15     * @param tagNo the tag number for this object.
16     * @param obj the tagged object.
17     */
18    public BERTaggedObject(
19        int             tagNo,
20        ASN1Encodable    obj)
21    {
22        super(true, tagNo, obj);
23    }
24
25    /**
26     * @param explicit true if an explicitly tagged object.
27     * @param tagNo the tag number for this object.
28     * @param obj the tagged object.
29     */
30    public BERTaggedObject(
31        boolean         explicit,
32        int             tagNo,
33        ASN1Encodable    obj)
34    {
35        super(explicit, tagNo, obj);
36    }
37
38    /**
39     * create an implicitly tagged object that contains a zero
40     * length sequence.
41     */
42    public BERTaggedObject(
43        int             tagNo)
44    {
45        super(false, tagNo, new BERSequence());
46    }
47
48    boolean isConstructed()
49    {
50        if (!empty)
51        {
52            if (explicit)
53            {
54                return true;
55            }
56            else
57            {
58                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
59
60                return primitive.isConstructed();
61            }
62        }
63        else
64        {
65            return true;
66        }
67    }
68
69    int encodedLength()
70        throws IOException
71    {
72        if (!empty)
73        {
74            ASN1Primitive primitive = obj.toASN1Primitive();
75            int length = primitive.encodedLength();
76
77            if (explicit)
78            {
79                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
80            }
81            else
82            {
83                // header length already in calculation
84                length = length - 1;
85
86                return StreamUtil.calculateTagLength(tagNo) + length;
87            }
88        }
89        else
90        {
91            return StreamUtil.calculateTagLength(tagNo) + 1;
92        }
93    }
94
95    void encode(
96        ASN1OutputStream out)
97        throws IOException
98    {
99        out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
100        out.write(0x80);
101
102        if (!empty)
103        {
104            if (!explicit)
105            {
106                Enumeration e;
107                if (obj instanceof ASN1OctetString)
108                {
109                    if (obj instanceof BEROctetString)
110                    {
111                        e = ((BEROctetString)obj).getObjects();
112                    }
113                    else
114                    {
115                        ASN1OctetString             octs = (ASN1OctetString)obj;
116                        BEROctetString berO = new BEROctetString(octs.getOctets());
117                        e = berO.getObjects();
118                    }
119                }
120                else if (obj instanceof ASN1Sequence)
121                {
122                    e = ((ASN1Sequence)obj).getObjects();
123                }
124                else if (obj instanceof ASN1Set)
125                {
126                    e = ((ASN1Set)obj).getObjects();
127                }
128                else
129                {
130                    throw new RuntimeException("not implemented: " + obj.getClass().getName());
131                }
132
133                while (e.hasMoreElements())
134                {
135                    out.writeObject((ASN1Encodable)e.nextElement());
136                }
137            }
138            else
139            {
140                out.writeObject(obj);
141            }
142        }
143
144        out.write(0x00);
145        out.write(0x00);
146    }
147}
148