3
3
4
4
using System . IO ;
5
5
using System . Net . Http . Headers ;
6
+ using System . Threading ;
7
+ using System . Threading . Tasks ;
6
8
using System . Web . Http ;
7
9
8
10
namespace System . Net . Http . Internal
9
11
{
10
12
/// <summary>
11
- /// Stream which only exposes a read-only only range view of an
13
+ /// Stream which only exposes a read-only only range view of an
12
14
/// inner stream.
13
15
/// </summary>
14
16
internal class ByteRangeStream : DelegatingStream
15
17
{
16
18
// The offset stream position at which the range starts.
17
19
private readonly long _lowerbounds ;
18
20
19
- // The total number of bytes within the range.
21
+ // The total number of bytes within the range.
20
22
private readonly long _totalCount ;
21
23
22
24
// The current number of bytes read into the range
@@ -92,6 +94,23 @@ public override bool CanWrite
92
94
get { return false ; }
93
95
}
94
96
97
+ public override long Position
98
+ {
99
+ get
100
+ {
101
+ return _currentCount ;
102
+ }
103
+ set
104
+ {
105
+ if ( value < 0 )
106
+ {
107
+ throw Error . ArgumentMustBeGreaterThanOrEqualTo ( "value" , value , 0L ) ;
108
+ }
109
+
110
+ _currentCount = value ;
111
+ }
112
+ }
113
+
95
114
public override IAsyncResult BeginRead ( byte [ ] buffer , int offset , int count , AsyncCallback callback , object state )
96
115
{
97
116
return base . BeginRead ( buffer , offset , PrepareStreamForRangeRead ( count ) , callback , state ) ;
@@ -102,16 +121,47 @@ public override int Read(byte[] buffer, int offset, int count)
102
121
return base . Read ( buffer , offset , PrepareStreamForRangeRead ( count ) ) ;
103
122
}
104
123
124
+ public override Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
125
+ {
126
+ return base . ReadAsync ( buffer , offset , PrepareStreamForRangeRead ( count ) , cancellationToken ) ;
127
+ }
128
+
105
129
public override int ReadByte ( )
106
130
{
107
131
int effectiveCount = PrepareStreamForRangeRead ( 1 ) ;
108
132
if ( effectiveCount <= 0 )
109
133
{
110
134
return - 1 ;
111
135
}
136
+
112
137
return base . ReadByte ( ) ;
113
138
}
114
139
140
+ public override long Seek ( long offset , SeekOrigin origin )
141
+ {
142
+ switch ( origin )
143
+ {
144
+ case SeekOrigin . Begin :
145
+ _currentCount = offset ;
146
+ break ;
147
+ case SeekOrigin . Current :
148
+ _currentCount = _currentCount + offset ;
149
+ break ;
150
+ case SeekOrigin . End :
151
+ _currentCount = _totalCount + offset ;
152
+ break ;
153
+ default :
154
+ throw Error . InvalidEnumArgument ( "origin" , ( int ) origin , typeof ( SeekOrigin ) ) ;
155
+ }
156
+
157
+ if ( _currentCount < 0L )
158
+ {
159
+ throw new IOException ( Properties . Resources . ByteRangeStreamInvalidOffset ) ;
160
+ }
161
+
162
+ return _currentCount ;
163
+ }
164
+
115
165
public override void SetLength ( long value )
116
166
{
117
167
throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
@@ -132,33 +182,49 @@ public override void EndWrite(IAsyncResult asyncResult)
132
182
throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
133
183
}
134
184
185
+ public override Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
186
+ {
187
+ throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
188
+ }
189
+
135
190
public override void WriteByte ( byte value )
136
191
{
137
192
throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
138
193
}
139
194
140
195
/// <summary>
141
- /// Gets the
196
+ /// Gets the correct count for the next read operation.
142
197
/// </summary>
143
198
/// <param name="count">The count requested to be read by the caller.</param>
144
199
/// <returns>The remaining bytes to read within the range defined for this stream.</returns>
145
200
private int PrepareStreamForRangeRead ( int count )
146
201
{
147
- long effectiveCount = Math . Min ( count , _totalCount - _currentCount ) ;
148
- if ( effectiveCount > 0 )
202
+ // A negative count causes base.Raad* methods to throw an ArgumentOutOfRangeException.
203
+ if ( count <= 0 )
149
204
{
150
- // Check if we should update the stream position
151
- long position = InnerStream . Position ;
152
- if ( _lowerbounds + _currentCount != position )
153
- {
154
- InnerStream . Position = _lowerbounds + _currentCount ;
155
- }
205
+ return count ;
206
+ }
156
207
157
- // Update current number of bytes read
158
- _currentCount += effectiveCount ;
208
+ // Reading past the end simply does nothing.
209
+ if ( _currentCount >= _totalCount )
210
+ {
211
+ return 0 ;
159
212
}
160
213
161
- // Effective count can never be bigger than int
214
+ long effectiveCount = Math . Min ( count , _totalCount - _currentCount ) ;
215
+
216
+ // Check if we should update the inner stream's position.
217
+ var newPosition = _lowerbounds + _currentCount ;
218
+ var position = InnerStream . Position ;
219
+ if ( newPosition != position )
220
+ {
221
+ InnerStream . Position = newPosition ;
222
+ }
223
+
224
+ // Update current number of bytes read.
225
+ _currentCount += effectiveCount ;
226
+
227
+ // Effective count can never be bigger than int.
162
228
return ( int ) effectiveCount ;
163
229
}
164
230
}
0 commit comments