001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004import java.util.Enumeration;
005
006/**
007 * BER TaggedObject - in ASN.1 notation this is any object preceded by
008 * a [n] where n is some number - these are assumed to follow the construction
009 * rules (as with sequences).
010 */
011public class BERTaggedObject
012    extends ASN1TaggedObject
013{
014    /**
015     * @param tagNo the tag number for this object.
016     * @param obj the tagged object.
017     */
018    public BERTaggedObject(
019        int             tagNo,
020        ASN1Encodable    obj)
021    {
022        super(true, tagNo, obj);
023    }
024
025    /**
026     * @param explicit true if an explicitly tagged object.
027     * @param tagNo the tag number for this object.
028     * @param obj the tagged object.
029     */
030    public BERTaggedObject(
031        boolean         explicit,
032        int             tagNo,
033        ASN1Encodable    obj)
034    {
035        super(explicit, tagNo, obj);
036    }
037
038    /**
039     * create an implicitly tagged object that contains a zero
040     * length sequence.
041     */
042    public BERTaggedObject(
043        int             tagNo)
044    {
045        super(false, tagNo, new BERSequence());
046    }
047
048    boolean isConstructed()
049    {
050        if (!empty)
051        {
052            if (explicit)
053            {
054                return true;
055            }
056            else
057            {
058                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
059
060                return primitive.isConstructed();
061            }
062        }
063        else
064        {
065            return true;
066        }
067    }
068
069    int encodedLength()
070        throws IOException
071    {
072        if (!empty)
073        {
074            ASN1Primitive primitive = obj.toASN1Primitive();
075            int length = primitive.encodedLength();
076
077            if (explicit)
078            {
079                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
080            }
081            else
082            {
083                // header length already in calculation
084                length = length - 1;
085
086                return StreamUtil.calculateTagLength(tagNo) + length;
087            }
088        }
089        else
090        {
091            return StreamUtil.calculateTagLength(tagNo) + 1;
092        }
093    }
094
095    void encode(
096        ASN1OutputStream out)
097        throws IOException
098    {
099        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}