aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.Compression/OffsetStream.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.Compression/OffsetStream.cs206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.Compression/OffsetStream.cs b/src/dtf/WixToolset.Dtf.Compression/OffsetStream.cs
new file mode 100644
index 00000000..65562524
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.Compression/OffsetStream.cs
@@ -0,0 +1,206 @@
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 /// Wraps a source stream and offsets all read/write/seek calls by a given value.
10 /// </summary>
11 /// <remarks>
12 /// This class is used to trick archive an packing or unpacking process
13 /// into reading or writing at an offset into a file, primarily for
14 /// self-extracting packages.
15 /// </remarks>
16 public class OffsetStream : Stream
17 {
18 private Stream source;
19 private long sourceOffset;
20
21 /// <summary>
22 /// Creates a new OffsetStream instance from a source stream
23 /// and using a specified offset.
24 /// </summary>
25 /// <param name="source">Underlying stream for which all calls will be offset.</param>
26 /// <param name="offset">Positive or negative number of bytes to offset.</param>
27 public OffsetStream(Stream source, long offset)
28 {
29 if (source == null)
30 {
31 throw new ArgumentNullException("source");
32 }
33
34 this.source = source;
35 this.sourceOffset = offset;
36
37 this.source.Seek(this.sourceOffset, SeekOrigin.Current);
38 }
39
40 /// <summary>
41 /// Gets the underlying stream that this OffsetStream calls into.
42 /// </summary>
43 public Stream Source
44 {
45 get { return this.source; }
46 }
47
48 /// <summary>
49 /// Gets the number of bytes to offset all calls before
50 /// redirecting to the underlying stream.
51 /// </summary>
52 public long Offset
53 {
54 get { return this.sourceOffset; }
55 }
56
57 /// <summary>
58 /// Gets a value indicating whether the source stream supports reading.
59 /// </summary>
60 /// <value>true if the stream supports reading; otherwise, false.</value>
61 public override bool CanRead
62 {
63 get
64 {
65 return this.source.CanRead;
66 }
67 }
68
69 /// <summary>
70 /// Gets a value indicating whether the source stream supports writing.
71 /// </summary>
72 /// <value>true if the stream supports writing; otherwise, false.</value>
73 public override bool CanWrite
74 {
75 get
76 {
77 return this.source.CanWrite;
78 }
79 }
80
81 /// <summary>
82 /// Gets a value indicating whether the source stream supports seeking.
83 /// </summary>
84 /// <value>true if the stream supports seeking; otherwise, false.</value>
85 public override bool CanSeek
86 {
87 get
88 {
89 return this.source.CanSeek;
90 }
91 }
92
93 /// <summary>
94 /// Gets the effective length of the stream, which is equal to
95 /// the length of the source stream minus the offset.
96 /// </summary>
97 public override long Length
98 {
99 get { return this.source.Length - this.sourceOffset; }
100 }
101
102 /// <summary>
103 /// Gets or sets the effective position of the stream, which
104 /// is equal to the position of the source stream minus the offset.
105 /// </summary>
106 public override long Position
107 {
108 get { return this.source.Position - this.sourceOffset; }
109 set { this.source.Position = value + this.sourceOffset; }
110 }
111
112 /// <summary>
113 /// Reads a sequence of bytes from the source stream and advances
114 /// the position within the stream by the number of bytes read.
115 /// </summary>
116 /// <param name="buffer">An array of bytes. When this method returns, the buffer
117 /// contains the specified byte array with the values between offset and
118 /// (offset + count - 1) replaced by the bytes read from the current source.</param>
119 /// <param name="offset">The zero-based byte offset in buffer at which to begin
120 /// storing the data read from the current stream.</param>
121 /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
122 /// <returns>The total number of bytes read into the buffer. This can be less
123 /// than the number of bytes requested if that many bytes are not currently available,
124 /// or zero (0) if the end of the stream has been reached.</returns>
125 public override int Read(byte[] buffer, int offset, int count)
126 {
127 return this.source.Read(buffer, offset, count);
128 }
129
130 /// <summary>
131 /// Writes a sequence of bytes to the source stream and advances the
132 /// current position within this stream by the number of bytes written.
133 /// </summary>
134 /// <param name="buffer">An array of bytes. This method copies count
135 /// bytes from buffer to the current stream.</param>
136 /// <param name="offset">The zero-based byte offset in buffer at which
137 /// to begin copying bytes to the current stream.</param>
138 /// <param name="count">The number of bytes to be written to the
139 /// current stream.</param>
140 public override void Write(byte[] buffer, int offset, int count)
141 {
142 this.source.Write(buffer, offset, count);
143 }
144
145 /// <summary>
146 /// Reads a byte from the stream and advances the position within the
147 /// source stream by one byte, or returns -1 if at the end of the stream.
148 /// </summary>
149 /// <returns>The unsigned byte cast to an Int32, or -1 if at the
150 /// end of the stream.</returns>
151 public override int ReadByte()
152 {
153 return this.source.ReadByte();
154 }
155
156 /// <summary>
157 /// Writes a byte to the current position in the source stream and
158 /// advances the position within the stream by one byte.
159 /// </summary>
160 /// <param name="value">The byte to write to the stream.</param>
161 public override void WriteByte(byte value)
162 {
163 this.source.WriteByte(value);
164 }
165
166 /// <summary>
167 /// Flushes the source stream.
168 /// </summary>
169 public override void Flush()
170 {
171 this.source.Flush();
172 }
173
174 /// <summary>
175 /// Sets the position within the current stream, which is
176 /// equal to the position within the source stream minus the offset.
177 /// </summary>
178 /// <param name="offset">A byte offset relative to the origin parameter.</param>
179 /// <param name="origin">A value of type SeekOrigin indicating
180 /// the reference point used to obtain the new position.</param>
181 /// <returns>The new position within the current stream.</returns>
182 public override long Seek(long offset, SeekOrigin origin)
183 {
184 return this.source.Seek(offset + (origin == SeekOrigin.Begin ? this.sourceOffset : 0), origin) - this.sourceOffset;
185 }
186
187 /// <summary>
188 /// Sets the effective length of the stream, which is equal to
189 /// the length of the source stream minus the offset.
190 /// </summary>
191 /// <param name="value">The desired length of the
192 /// current stream in bytes.</param>
193 public override void SetLength(long value)
194 {
195 this.source.SetLength(value + this.sourceOffset);
196 }
197
198 /// <summary>
199 /// Closes the underlying stream.
200 /// </summary>
201 public override void Close()
202 {
203 this.source.Close();
204 }
205 }
206}