aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPLiteralDataGenerator.java
blob: 4835be5335d5ff59c9d36205ab5f62223ea517dd (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package org.spongycastle.openpgp;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.util.Strings;

/**
 * Class for producing literal data packets.
 */
public class PGPLiteralDataGenerator implements StreamGenerator
{    
    public static final char    BINARY = PGPLiteralData.BINARY;
    public static final char    TEXT = PGPLiteralData.TEXT;
    public static final char    UTF8 = PGPLiteralData.UTF8;
    
    /**
     * The special name indicating a "for your eyes only" packet.
     */
    public static final String  CONSOLE = PGPLiteralData.CONSOLE;
    
    /**
     * The special time for a modification time of "now" or
     * the present time.
     */
    public static final Date    NOW = PGPLiteralData.NOW;
    
    private BCPGOutputStream    pkOut;
    private boolean             oldFormat = false;
    
    public PGPLiteralDataGenerator()
    {        
    }
    
    /**
     * Generates literal data objects in the old format, this is
     * important if you need compatability with  PGP 2.6.x.
     * 
     * @param oldFormat
     */
    public PGPLiteralDataGenerator(
        boolean    oldFormat)
    {
        this.oldFormat = oldFormat;
    }
    
    private void writeHeader(
        OutputStream    out,
        char            format,
        byte[]          encName,
        long            modificationTime) 
        throws IOException
    {
        out.write(format);

        out.write((byte)encName.length);

        for (int i = 0; i != encName.length; i++)
        {
            out.write(encName[i]);
        }

        long    modDate = modificationTime / 1000;

        out.write((byte)(modDate >> 24));
        out.write((byte)(modDate >> 16));
        out.write((byte)(modDate >> 8));
        out.write((byte)(modDate));
    }
    
    /**
     * Open a literal data packet, returning a stream to store the data inside
     * the packet.
     * <p>
     * The stream created can be closed off by either calling close()
     * on the stream or close() on the generator. Closing the returned
     * stream does not close off the OutputStream parameter out.
     * 
     * @param out the stream we want the packet in
     * @param format the format we are using
     * @param name the name of the "file"
     * @param length the length of the data we will write
     * @param modificationTime the time of last modification we want stored.
     */
    public OutputStream open(
        OutputStream    out,
        char            format,
        String          name,
        long            length,
        Date            modificationTime)
        throws IOException
    {
        if (pkOut != null)
        {
            throw new IllegalStateException("generator already in open state");
        }

        byte[] encName = Strings.toUTF8ByteArray(name);

        pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA, length + 2 + encName.length + 4, oldFormat);
        
        writeHeader(pkOut, format, encName, modificationTime.getTime());

        return new WrappedGeneratorStream(pkOut, this);
    }
    
    /**
     * Open a literal data packet, returning a stream to store the data inside
     * the packet as an indefinite length stream. The stream is written out as a 
     * series of partial packets with a chunk size determined by the size of the
     * passed in buffer.
     * <p>
     * The stream created can be closed off by either calling close()
     * on the stream or close() on the generator. Closing the returned
     * stream does not close off the OutputStream parameter out.
     * <p>
     * <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
     * bytes worth of the buffer will be used.
     * 
     * @param out the stream we want the packet in
     * @param format the format we are using
     * @param name the name of the "file"
     * @param modificationTime the time of last modification we want stored.
     * @param buffer the buffer to use for collecting data to put into chunks.
     */
    public OutputStream open(
        OutputStream    out,
        char            format,
        String          name,
        Date            modificationTime,
        byte[]          buffer)
        throws IOException
    {
        if (pkOut != null)
        {
            throw new IllegalStateException("generator already in open state");
        }

        pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA, buffer);

        byte[] encName = Strings.toUTF8ByteArray(name);

        writeHeader(pkOut, format, encName, modificationTime.getTime());

        return new WrappedGeneratorStream(pkOut, this);
    }
    
    /**
     * Open a literal data packet for the passed in File object, returning
     * an output stream for saving the file contents.
     * <p>
     * The stream created can be closed off by either calling close()
     * on the stream or close() on the generator. Closing the returned
     * stream does not close off the OutputStream parameter out.
     * 
     * @param out
     * @param format
     * @param file
     * @return OutputStream
     * @throws IOException
     */
    public OutputStream open(
        OutputStream    out,
        char            format,
        File            file)
        throws IOException
    {
        if (pkOut != null)
        {
            throw new IllegalStateException("generator already in open state");
        }

        byte[] encName = Strings.toUTF8ByteArray(file.getName());

        pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA, file.length() + 2 + encName.length + 4, oldFormat);
        
        writeHeader(pkOut, format, encName, file.lastModified());

        return new WrappedGeneratorStream(pkOut, this);
    }
    
    /**
     * Close the literal data packet - this is equivalent to calling close on the stream
     * returned by the open() method.
     * 
     * @throws IOException
     */
    public void close()
        throws IOException
    {
        if (pkOut != null)
        {
            pkOut.finish();
            pkOut.flush();
            pkOut = null;
        }
    }
}