summaryrefslogtreecommitdiff
path: root/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
blob: 55e695c7460893e2e7e3e9bdc4b046371b0321fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package org.bouncycastle.asn1;

import java.io.IOException;
import java.io.OutputStream;

/**
 * A generator for indefinite-length OCTET STRINGs
 */
public class BEROctetStringGenerator
    extends BERGenerator
{
    /**
     * Use the passed in stream as the target for the generator, writing out the header tag
     * for a constructed OCTET STRING.
     *
     * @param out target stream
     * @throws IOException if the target stream cannot be written to.
     */
    public BEROctetStringGenerator(OutputStream out) 
        throws IOException
    {
        super(out);
        
        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
    }

    /**
     * Use the passed in stream as the target for the generator, writing out the header tag
     * for a tagged constructed OCTET STRING (possibly implicit).
     *
     * @param out target stream
     * @param tagNo the tag number to introduce
     * @param isExplicit true if this is an explicitly tagged object, false otherwise.
     * @throws IOException if the target stream cannot be written to.
     */
    public BEROctetStringGenerator(
        OutputStream out,
        int tagNo,
        boolean isExplicit) 
        throws IOException
    {
        super(out, tagNo, isExplicit);
        
        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
    }

    /**
     * Return a stream representing the content target for this OCTET STRING
     *
     * @return an OutputStream which chunks data in blocks of 1000 (CER limit).
     */
    public OutputStream getOctetOutputStream()
    {
        return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
    }

    /**
     * Return a stream representing the content target for this OCTET STRING
     *
     * @param buf the buffer to use for chunking the data.
     * @return an OutputStream which chunks data in blocks of buf length.
     */
    public OutputStream getOctetOutputStream(
        byte[] buf)
    {
        return new BufferedBEROctetStream(buf);
    }
   
    private class BufferedBEROctetStream
        extends OutputStream
    {
        private byte[] _buf;
        private int    _off;
        private DEROutputStream _derOut;

        BufferedBEROctetStream(
            byte[] buf)
        {
            _buf = buf;
            _off = 0;
            _derOut = new DEROutputStream(_out);
        }
        
        public void write(
            int b)
            throws IOException
        {
            _buf[_off++] = (byte)b;

            if (_off == _buf.length)
            {
                DEROctetString.encode(_derOut, _buf);
                _off = 0;
            }
        }

        public void write(byte[] b, int off, int len) throws IOException
        {
            while (len > 0)
            {
                int numToCopy = Math.min(len, _buf.length - _off);
                System.arraycopy(b, off, _buf, _off, numToCopy);

                _off += numToCopy;
                if (_off < _buf.length)
                {
                    break;
                }

                DEROctetString.encode(_derOut, _buf);
                _off = 0;

                off += numToCopy;
                len -= numToCopy;
            }
        }

        public void close() 
            throws IOException
        {
            if (_off != 0)
            {
                byte[] bytes = new byte[_off];
                System.arraycopy(_buf, 0, bytes, 0, _off);
                
                DEROctetString.encode(_derOut, bytes);
            }
            
             writeBEREnd();
        }
    }
}