summary refs log tree commit diff
path: root/crypto/src/openpgp/PgpLiteralDataGenerator.cs
blob: fd59c1ebeb46e999c3719b496a457527e7efa01f (plain) (blame)
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
using System;
using System.IO;

using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Date;

namespace Org.BouncyCastle.Bcpg.OpenPgp
{
	/// <remarks>Class for producing literal data packets.</remarks>
    public class PgpLiteralDataGenerator
		: IStreamGenerator
	{
        public const char Binary = PgpLiteralData.Binary;
        public const char Text = PgpLiteralData.Text;
		public const char Utf8 = PgpLiteralData.Utf8;

		/// <summary>The special name indicating a "for your eyes only" packet.</summary>
        public const string Console = PgpLiteralData.Console;

		private BcpgOutputStream pkOut;
        private bool oldFormat;

		public PgpLiteralDataGenerator()
        {
        }

		/// <summary>
		/// Generates literal data objects in the old format.
		/// This is important if you need compatibility with PGP 2.6.x.
		/// </summary>
		/// <param name="oldFormat">If true, uses old format.</param>
        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);
        }

		/// <summary>
		/// <p>
		/// Open a literal data packet, returning a stream to store the data inside the packet.
		/// </p>
		/// <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 Stream parameter <c>outStr</c>.
		/// </p>
		/// </summary>
		/// <param name="outStr">The stream we want the packet in.</param>
		/// <param name="format">The format we are using.</param>
		/// <param name="name">The name of the 'file'.</param>
		/// <param name="length">The length of the data we will write.</param>
		/// <param name="modificationTime">The time of last modification we want stored.</param>
        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);
        }

        /// <summary>
		/// <p>
		/// 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>
		/// <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 Stream parameter <c>outStr</c>.
		/// </p>
		/// <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.</p>
		/// </summary>
		/// <param name="outStr">The stream we want the packet in.</param>
		/// <param name="format">The format we are using.</param>
		/// <param name="name">The name of the 'file'.</param>
		/// <param name="modificationTime">The time of last modification we want stored.</param>
		/// <param name="buffer">The buffer to use for collecting data to put into chunks.</param>
        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);
		}

        /// <summary>
		/// <p>
		/// Open a literal data packet for the passed in <c>FileInfo</c> object, returning
		/// an output stream for saving the file contents.
		/// </p>
		/// <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 Stream parameter <c>outStr</c>.
		/// </p>
		/// </summary>
		/// <param name="outStr">The stream we want the packet in.</param>
		/// <param name="format">The format we are using.</param>
		/// <param name="file">The <c>FileInfo</c> object containg the packet details.</param>
		public Stream Open(
            Stream		outStr,
            char		format,
            FileInfo	file)
        {
			return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
        }

        #region IDisposable

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (pkOut != null)
                {
                    pkOut.Finish();
                    pkOut.Flush();
                    pkOut = null;
                }
            }
        }

        #endregion
	}
}