001: package org.bouncycastle.openpgp;
002:
003: import org.bouncycastle.bcpg.BCPGOutputStream;
004: import org.bouncycastle.bcpg.PacketTags;
005:
006: import java.io.File;
007: import java.io.IOException;
008: import java.io.OutputStream;
009: import java.util.Date;
010:
011: /**
012: * Class for producing literal data packets.
013: */
014: public class PGPLiteralDataGenerator implements StreamGenerator {
015: public static final char BINARY = PGPLiteralData.BINARY;
016: public static final char TEXT = PGPLiteralData.TEXT;
017:
018: /**
019: * The special name indicating a "for your eyes only" packet.
020: */
021: public static final String CONSOLE = PGPLiteralData.CONSOLE;
022:
023: /**
024: * The special time for a modification time of "now" or
025: * the present time.
026: */
027: public static final Date NOW = PGPLiteralData.NOW;
028:
029: private BCPGOutputStream pkOut;
030: private boolean oldFormat = false;
031:
032: public PGPLiteralDataGenerator() {
033: }
034:
035: /**
036: * Generates literal data objects in the old format, this is
037: * important if you need compatability with PGP 2.6.x.
038: *
039: * @param oldFormat
040: */
041: public PGPLiteralDataGenerator(boolean oldFormat) {
042: this .oldFormat = oldFormat;
043: }
044:
045: private void writeHeader(OutputStream out, char format,
046: String name, long modificationTime) throws IOException {
047: out.write(format);
048: out.write((byte) name.length());
049:
050: for (int i = 0; i != name.length(); i++) {
051: out.write(name.charAt(i));
052: }
053:
054: long modDate = modificationTime / 1000;
055:
056: out.write((byte) (modDate >> 24));
057: out.write((byte) (modDate >> 16));
058: out.write((byte) (modDate >> 8));
059: out.write((byte) (modDate));
060: }
061:
062: /**
063: * Open a literal data packet, returning a stream to store the data inside
064: * the packet. The stream can be closed off by either calling close()
065: * on the stream or close() on the generator.
066: *
067: * @param out the stream we want the packet in
068: * @param format the format we are using
069: * @param name the name of the "file"
070: * @param length the length of the data we will write
071: * @param modificationTime the time of last modification we want stored.
072: */
073: public OutputStream open(OutputStream out, char format,
074: String name, long length, Date modificationTime)
075: throws IOException {
076: if (pkOut != null) {
077: throw new IllegalStateException(
078: "generator already in open state");
079: }
080:
081: pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA,
082: length + 2 + name.length() + 4, oldFormat);
083:
084: writeHeader(pkOut, format, name, modificationTime.getTime());
085:
086: return new WrappedGeneratorStream(pkOut, this );
087: }
088:
089: /**
090: * Open a literal data packet, returning a stream to store the data inside
091: * the packet as an indefiinite length stream. The stream is written out as a
092: * series of partial packets with a chunk size determined by the size of the
093: * passed in buffer.The stream can be closed off by either calling close()
094: * on the stream or close() on the generator.
095: * <p>
096: * <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
097: * bytes worth of the buffer will be used.
098: *
099: * @param out the stream we want the packet in
100: * @param format the format we are using
101: * @param name the name of the "file"
102: * @param modificationTime the time of last modification we want stored.
103: * @param buffer the buffer to use for collecting data to put into chunks.
104: */
105: public OutputStream open(OutputStream out, char format,
106: String name, Date modificationTime, byte[] buffer)
107: throws IOException {
108: if (pkOut != null) {
109: throw new IllegalStateException(
110: "generator already in open state");
111: }
112:
113: pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA,
114: buffer);
115:
116: writeHeader(pkOut, format, name, modificationTime.getTime());
117:
118: return new WrappedGeneratorStream(pkOut, this );
119: }
120:
121: /**
122: * Open a literal data packet for the passed in File object, returning
123: * an output stream for saving the file contents. The stream can be closed off by either calling close()
124: * on the stream or close() on the generator.
125: *
126: * @param out
127: * @param format
128: * @param file
129: * @return OutputStream
130: * @throws IOException
131: */
132: public OutputStream open(OutputStream out, char format, File file)
133: throws IOException {
134: if (pkOut != null) {
135: throw new IllegalStateException(
136: "generator already in open state");
137: }
138:
139: pkOut = new BCPGOutputStream(out, PacketTags.LITERAL_DATA, file
140: .length()
141: + 2 + file.getName().length() + 4, oldFormat);
142:
143: writeHeader(pkOut, format, file.getName(), file.lastModified());
144:
145: return new WrappedGeneratorStream(pkOut, this );
146: }
147:
148: /**
149: * Close the literal data packet - this is equivalent to calling close on the stream
150: * returned by the open() method.
151: *
152: * @throws IOException
153: */
154: public void close() throws IOException {
155: if (pkOut != null) {
156: pkOut.finish();
157: pkOut.flush();
158: pkOut = null;
159: }
160: }
161: }
|