using System; using System.IO; using System.Text; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Date; namespace Org.BouncyCastle.Bcpg.OpenPgp { /// Class for producing literal data packets. public class PgpLiteralDataGenerator : IStreamGenerator { public const char Binary = PgpLiteralData.Binary; public const char Text = PgpLiteralData.Text; public const char Utf8 = PgpLiteralData.Utf8; /// The special name indicating a "for your eyes only" packet. public const string Console = PgpLiteralData.Console; private BcpgOutputStream pkOut; private bool oldFormat; public PgpLiteralDataGenerator() { } /// /// Generates literal data objects in the old format. /// This is important if you need compatibility with PGP 2.6.x. /// /// If true, uses old format. public PgpLiteralDataGenerator( bool oldFormat) { this.oldFormat = oldFormat; } private void WriteHeader( BcpgOutputStream outStr, char format, byte[] encName, long modificationTime) { outStr.Write( (byte) format, (byte) encName.Length); outStr.Write(encName); long modDate = modificationTime / 1000L; outStr.Write( (byte)(modDate >> 24), (byte)(modDate >> 16), (byte)(modDate >> 8), (byte)modDate); } /// ///

/// Open a literal data packet, returning a stream to store the data inside the packet. ///

///

/// 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 Stream parameter outStr. ///

///
/// The stream we want the packet in. /// The format we are using. /// The name of the 'file'. /// The length of the data we will write. /// The time of last modification we want stored. public Stream Open( Stream outStr, char format, string name, long length, DateTime modificationTime) { if (pkOut != null) throw new InvalidOperationException("generator already in open state"); if (outStr == null) throw new ArgumentNullException("outStr"); // Do this first, since it might throw an exception long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime); byte[] encName = Strings.ToUtf8ByteArray(name); pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, length + 2 + encName.Length + 4, oldFormat); WriteHeader(pkOut, format, encName, unixMs); return new WrappedGeneratorStream(this, pkOut); } /// ///

/// 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. ///

///

/// 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 Stream parameter outStr. ///

///

/// Note: 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.

///
/// The stream we want the packet in. /// The format we are using. /// The name of the 'file'. /// The time of last modification we want stored. /// The buffer to use for collecting data to put into chunks. public Stream Open( Stream outStr, char format, string name, DateTime modificationTime, byte[] buffer) { if (pkOut != null) throw new InvalidOperationException("generator already in open state"); if (outStr == null) throw new ArgumentNullException("outStr"); // Do this first, since it might throw an exception long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime); byte[] encName = Strings.ToUtf8ByteArray(name); pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer); WriteHeader(pkOut, format, encName, unixMs); return new WrappedGeneratorStream(this, pkOut); } /// ///

/// Open a literal data packet for the passed in FileInfo object, returning /// an output stream for saving the file contents. ///

///

/// 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 Stream parameter outStr. ///

///
/// The stream we want the packet in. /// The format we are using. /// The FileInfo object containg the packet details. public Stream Open( Stream outStr, char format, FileInfo file) { return Open(outStr, format, file.Name, file.Length, file.LastWriteTime); } /// /// Close the literal data packet - this is equivalent to calling Close() /// on the stream returned by the Open() method. /// public void Close() { if (pkOut != null) { pkOut.Finish(); pkOut.Flush(); pkOut = null; } } } }