aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs b/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs
new file mode 100644
index 00000000..50e62e73
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs
@@ -0,0 +1,212 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dtf.Compression
4{
5 using System;
6 using System.IO;
7
8 /// <summary>
9 /// Duplicates a source stream by maintaining a separate position.
10 /// </summary>
11 /// <remarks>
12 /// WARNING: duplicate streams are not thread-safe with respect to each other or the original stream.
13 /// If multiple threads use duplicate copies of the same stream, they must synchronize for any operations.
14 /// </remarks>
15 public class DuplicateStream : Stream
16 {
17 private Stream source;
18 private long position;
19
20 /// <summary>
21 /// Creates a new duplicate of a stream.
22 /// </summary>
23 /// <param name="source">source of the duplicate</param>
24 public DuplicateStream(Stream source)
25 {
26 if (source == null)
27 {
28 throw new ArgumentNullException("source");
29 }
30
31 this.source = DuplicateStream.OriginalStream(source);
32 }
33
34 /// <summary>
35 /// Gets the original stream that was used to create the duplicate.
36 /// </summary>
37 public Stream Source
38 {
39 get
40 {
41 return this.source;
42 }
43 }
44
45 /// <summary>
46 /// Gets a value indicating whether the source stream supports reading.
47 /// </summary>
48 /// <value>true if the stream supports reading; otherwise, false.</value>
49 public override bool CanRead
50 {
51 get
52 {
53 return this.source.CanRead;
54 }
55 }
56
57 /// <summary>
58 /// Gets a value indicating whether the source stream supports writing.
59 /// </summary>
60 /// <value>true if the stream supports writing; otherwise, false.</value>
61 public override bool CanWrite
62 {
63 get
64 {
65 return this.source.CanWrite;
66 }
67 }
68
69 /// <summary>
70 /// Gets a value indicating whether the source stream supports seeking.
71 /// </summary>
72 /// <value>true if the stream supports seeking; otherwise, false.</value>
73 public override bool CanSeek
74 {
75 get
76 {
77 return this.source.CanSeek;
78 }
79 }
80
81 /// <summary>
82 /// Gets the length of the source stream.
83 /// </summary>
84 public override long Length
85 {
86 get
87 {
88 return this.source.Length;
89 }
90 }
91
92 /// <summary>
93 /// Gets or sets the position of the current stream,
94 /// ignoring the position of the source stream.
95 /// </summary>
96 public override long Position
97 {
98 get
99 {
100 return this.position;
101 }
102
103 set
104 {
105 this.position = value;
106 }
107 }
108
109 /// <summary>
110 /// Retrieves the original stream from a possible duplicate stream.
111 /// </summary>
112 /// <param name="stream">Possible duplicate stream.</param>
113 /// <returns>If the stream is a DuplicateStream, returns
114 /// the duplicate's source; otherwise returns the same stream.</returns>
115 public static Stream OriginalStream(Stream stream)
116 {
117 DuplicateStream dupStream = stream as DuplicateStream;
118 return dupStream != null ? dupStream.Source : stream;
119 }
120
121 /// <summary>
122 /// Flushes the source stream.
123 /// </summary>
124 public override void Flush()
125 {
126 this.source.Flush();
127 }
128
129 /// <summary>
130 /// Sets the length of the source stream.
131 /// </summary>
132 /// <param name="value">The desired length of the stream in bytes.</param>
133 public override void SetLength(long value)
134 {
135 this.source.SetLength(value);
136 }
137
138 /// <summary>
139 /// Closes the underlying stream, effectively closing ALL duplicates.
140 /// </summary>
141 public override void Close()
142 {
143 this.source.Close();
144 }
145
146 /// <summary>
147 /// Reads from the source stream while maintaining a separate position
148 /// and not impacting the source stream's position.
149 /// </summary>
150 /// <param name="buffer">An array of bytes. When this method returns, the buffer
151 /// contains the specified byte array with the values between offset and
152 /// (offset + count - 1) replaced by the bytes read from the current source.</param>
153 /// <param name="offset">The zero-based byte offset in buffer at which to begin
154 /// storing the data read from the current stream.</param>
155 /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
156 /// <returns>The total number of bytes read into the buffer. This can be less
157 /// than the number of bytes requested if that many bytes are not currently available,
158 /// or zero (0) if the end of the stream has been reached.</returns>
159 public override int Read(byte[] buffer, int offset, int count)
160 {
161 long saveSourcePosition = this.source.Position;
162 this.source.Position = this.position;
163 int read = this.source.Read(buffer, offset, count);
164 this.position = this.source.Position;
165 this.source.Position = saveSourcePosition;
166 return read;
167 }
168
169 /// <summary>
170 /// Writes to the source stream while maintaining a separate position
171 /// and not impacting the source stream's position.
172 /// </summary>
173 /// <param name="buffer">An array of bytes. This method copies count
174 /// bytes from buffer to the current stream.</param>
175 /// <param name="offset">The zero-based byte offset in buffer at which
176 /// to begin copying bytes to the current stream.</param>
177 /// <param name="count">The number of bytes to be written to the
178 /// current stream.</param>
179 public override void Write(byte[] buffer, int offset, int count)
180 {
181 long saveSourcePosition = this.source.Position;
182 this.source.Position = this.position;
183 this.source.Write(buffer, offset, count);
184 this.position = this.source.Position;
185 this.source.Position = saveSourcePosition;
186 }
187
188 /// <summary>
189 /// Changes the position of this stream without impacting the
190 /// source stream's position.
191 /// </summary>
192 /// <param name="offset">A byte offset relative to the origin parameter.</param>
193 /// <param name="origin">A value of type SeekOrigin indicating the reference
194 /// point used to obtain the new position.</param>
195 /// <returns>The new position within the current stream.</returns>
196 public override long Seek(long offset, SeekOrigin origin)
197 {
198 long originPosition = 0;
199 if (origin == SeekOrigin.Current)
200 {
201 originPosition = this.position;
202 }
203 else if (origin == SeekOrigin.End)
204 {
205 originPosition = this.Length;
206 }
207
208 this.position = originPosition + offset;
209 return this.position;
210 }
211 }
212}