001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.ByteArrayOutputStream;
004import java.io.IOException;
005import java.io.InputStream;
006import java.io.OutputStream;
007
008import org.bouncycastle.util.io.Streams;
009
010public abstract class DERGenerator
011    extends ASN1Generator
012{       
013    private boolean      _tagged = false;
014    private boolean      _isExplicit;
015    private int          _tagNo;
016    
017    protected DERGenerator(
018        OutputStream out)
019    {
020        super(out);
021    }
022
023    public DERGenerator(
024        OutputStream out,
025        int          tagNo,
026        boolean      isExplicit)
027    { 
028        super(out);
029        
030        _tagged = true;
031        _isExplicit = isExplicit;
032        _tagNo = tagNo;
033    }
034
035    private void writeLength(
036        OutputStream out,
037        int          length)
038        throws IOException
039    {
040        if (length > 127)
041        {
042            int size = 1;
043            int val = length;
044
045            while ((val >>>= 8) != 0)
046            {
047                size++;
048            }
049
050            out.write((byte)(size | 0x80));
051
052            for (int i = (size - 1) * 8; i >= 0; i -= 8)
053            {
054                out.write((byte)(length >> i));
055            }
056        }
057        else
058        {
059            out.write((byte)length);
060        }
061    }
062
063    void writeDEREncoded(
064        OutputStream out,
065        int          tag,
066        byte[]       bytes)
067        throws IOException
068    {
069        out.write(tag);
070        writeLength(out, bytes.length);
071        out.write(bytes);
072    }
073
074    void writeDEREncoded(
075        int       tag,
076        byte[]    bytes)
077        throws IOException
078    {
079        if (_tagged)
080        {
081            int tagNum = _tagNo | BERTags.TAGGED;
082            
083            if (_isExplicit)
084            {
085                int newTag = _tagNo | BERTags.CONSTRUCTED | BERTags.TAGGED;
086
087                ByteArrayOutputStream bOut = new ByteArrayOutputStream();
088                
089                writeDEREncoded(bOut, tag, bytes);
090                
091                writeDEREncoded(_out, newTag, bOut.toByteArray());
092            }
093            else
094            {   
095                if ((tag & BERTags.CONSTRUCTED) != 0)
096                {
097                    writeDEREncoded(_out, tagNum | BERTags.CONSTRUCTED, bytes);
098                }
099                else
100                {
101                    writeDEREncoded(_out, tagNum, bytes);
102                }
103            }
104        }
105        else
106        {
107            writeDEREncoded(_out, tag, bytes);
108        }
109    }
110    
111    void writeDEREncoded(
112        OutputStream out,
113        int          tag,
114        InputStream  in)
115        throws IOException
116    {
117        writeDEREncoded(out, tag, Streams.readAll(in));
118    }
119}