7
7
using System . Text ;
8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
+ using System . Buffers ;
10
11
11
12
namespace System . Net
12
13
{
@@ -20,7 +21,7 @@ internal sealed class Base64Stream : DelegatedStream, IEncodableStream
20
21
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255
F438
span>, 62 , 255 , 255 , 255 , 63 , // 2
21
22
52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 255 , 255 , 255 , 255 , 255 , 255 , // 3
22
23
255 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , // 4
23
- 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 255 , 255 , 255 , 255 , 255 , // 5
24
+ 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 255 , 255 , 255 , 255 , 255 , // 5
24
25
255 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , // 6
25
26
41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , 255 , 255 , 255 , 255 , 255 , // 7
26
27
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , // 8
@@ -52,6 +53,9 @@ internal Base64Stream(Base64WriteStateInfo writeStateInfo) : base(new MemoryStre
52
53
_encoder = new Base64Encoder ( _writeState , writeStateInfo . MaxLineLength ) ;
53
54
}
54
55
56
+ public override bool CanRead => BaseStream . CanRead ;
57
+ public override bool CanWrite => BaseStream . CanWrite ;
58
+
55
59
private ReadStateInfo ReadState => _readState ??= new ReadStateInfo ( ) ;
56
60
57
61
internal WriteStateInfoBase WriteState
@@ -63,12 +67,6 @@ internal WriteStateInfoBase WriteState
63
67
}
64
68
}
65
69
66
- public override IAsyncResult BeginRead ( byte [ ] buffer , int offset , int count , AsyncCallback ? callback , object ? state ) =>
67
- TaskToAsyncResult . Begin ( ReadAsync ( buffer , offset , count , CancellationToken . None ) , callback , state ) ;
68
-
69
- public override IAsyncResult BeginWrite ( byte [ ] buffer , int offset , int count , AsyncCallback ? callback , object ? state ) =>
70
- TaskToAsyncResult . Begin ( WriteAsync ( buffer , offset , count , CancellationToken . None ) , callback , state ) ;
71
-
72
70
public override void Close ( )
73
71
{
74
72
if ( _writeState != null && WriteState . Length > 0 )
@@ -80,14 +78,14 @@ public override void Close()
80
78
base . Close ( ) ;
81
79
}
82
80
83
- public unsafe int DecodeBytes ( byte [ ] buffer , int offset , int count )
81
+ public unsafe int DecodeBytes ( Span < byte > buffer )
84
82
{
85
83
fixed ( byte * pBuffer = buffer )
86
84
{
87
- byte * start = pBuffer + offset ;
85
+ byte * start = pBuffer ;
88
86
byte * source = start ;
89
87
byte * dest = start ;
90
- byte * end = start + count ;
88
+ byte * end = start + buffer . Length ;
91
89
92
90
while ( source < end )
93
91
{
@@ -133,24 +131,18 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count)
133
131
}
134
132
}
135
133
136
- public int EncodeBytes ( byte [ ] buffer , int offset , int count ) =>
137
- EncodeBytes ( buffer , offset , count , true , true ) ;
134
+ public int EncodeBytes ( ReadOnlySpan < byte > buffer ) =>
135
+ _encoder . EncodeBytes ( buffer , true , true ) ;
138
136
139
- internal int EncodeBytes ( byte [ ] buffer , int offset , int count , bool dontDeferFinalBytes , bool shouldAppendSpaceToCRLF )
137
+ internal int EncodeBytes ( ReadOnlySpan < byte > buffer , bool dontDeferFinalBytes , bool shouldAppendSpaceToCRLF )
140
138
{
141
- return _encoder . EncodeBytes ( buffer , offset , count , dontDeferFinalBytes , shouldAppendSpaceToCRLF ) ;
139
+ return _encoder . EncodeBytes ( buffer , dontDeferFinalBytes , shouldAppendSpaceToCRLF ) ;
142
140
}
143
141
144
142
public int EncodeString ( string value , Encoding encoding ) => _encoder . EncodeString ( value , encoding ) ;
145
143
146
144
public string GetEncodedString ( ) => _encoder . GetEncodedString ( ) ;
147
145
148
- public override int EndRead ( IAsyncResult asyncResult ) =>
149
- TaskToAsyncResult . End < int > ( asyncResult ) ;
150
-
151
- public override void EndWrite ( IAsyncResult asyncResult ) =>
152
- TaskToAsyncResult . End ( asyncResult ) ;
153
-
154
146
public override void Flush ( )
155
147
{
156
148
if ( _writeState != null && WriteState . Length > 0 )
@@ -163,90 +155,78 @@ public override void Flush()
<
F42D
/div>
163
155
164
156
public override async Task FlushAsync ( CancellationToken cancellationToken )
165
157
{
166
- if ( _writeState != null && WriteState . Length > 0 )
167
- {
168
- await base . WriteAsync ( WriteState . Buffer . AsMemory ( 0 , WriteState . Length ) , cancellationToken ) . ConfigureAwait ( false ) ;
169
- WriteState . Reset ( ) ;
170
- }
171
-
158
+ await FlushInternalAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
172
159
await base . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
173
160
}
174
161
175
162
private void FlushInternal ( )
176
163
{
177
- base . Write ( WriteState . Buffer , 0 , WriteState . Length ) ;
164
+ BaseStream . Write ( WriteState . Buffer . AsSpan ( 0 , WriteState . Length ) ) ;
178
165
WriteState . Reset ( ) ;
179
166
}
180
167
181
- public override int Read ( byte [ ] buffer , int offset , int count )
168
+ private async ValueTask FlushInternalAsync ( CancellationToken cancellationToken )
182
169
{
183
- ValidateBufferArguments ( buffer , offset , count ) ;
170
+ await BaseStream . WriteAsync ( WriteState . Buffer . AsMemory ( 0 , WriteState . Length ) , cancellationToken ) . ConfigureAwait ( false ) ;
171
+ WriteState . Reset ( ) ;
172
+ }
184
173
174
+ protected override int ReadInternal ( Span < byte > buffer )
175
+ {
185
176
while ( true )
186
177
{
187
178
// read data from the underlying stream
188
- int read = base . Read ( buffer , offset , count ) ;
179
+ int read = BaseStream . Read ( buffer ) ;
189
180
190
181
// if the underlying stream returns 0 then there
191
- // is no more data - ust return 0.
182
+ // is no more data - just return 0.
192
183
if ( read == 0 )
193
184
{
194
185
return 0 ;
195
186
}
196
187
197
- // while decoding, we may end up not having
198
- // any bytes to return pending additional data
199
- // from the underlying stream.
200
- read = DecodeBytes ( buffer , offset , read ) ;
188
+ // Decode the read bytes and update the input buffer with decoded bytes
189
+ read = DecodeBytes ( buffer . Slice ( 0 , read ) ) ;
201
190
if ( read > 0 )
202
191
{
203
192
return read ;
204
193
}
205
194
}
206
195
}
207
- public override Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
208
- {
209
- ValidateBufferArguments ( buffer , offset , count ) ;
210
- return ReadAsyncCore ( buffer , offset , count , cancellationToken ) ;
211
196
212
- async Task < int > ReadAsyncCore ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
197
+ protected override async ValueTask < int > ReadAsyncInternal ( Memory < byte > buffer , CancellationToken cancellationToken = default )
198
+ {
199
+ while ( true )
213
200
{
214
- while ( true )
215
- {
216
- // read data from the underlying stream
217
- int read = await base . ReadAsync ( buffer . AsMemory ( offset , count ) , cancellationToken ) . ConfigureAwait ( false ) ;
201
+ // read data from the underlying stream
202
+ int read = await BaseStream . ReadAsync ( buffer , cancellationToken ) . ConfigureAwait ( false ) ;
218
203
219
- // if the underlying stream returns 0 then there
220
- // is no more data - ust return 0.
221
- if ( read == 0 )
222
- {
223
- return 0 ;
224
- }
204
+ // if the underlying stream returns 0 then there
205
+ // is no more data - just return 0.
206
+ if ( read == 0 )
207
+ {
208
+ return 0 ;
209
+ }
225
210
226
- // while decoding, we may end up not having
227
- // any bytes to return pending additional data
228
- // from the underlying stream.
229
- read = DecodeBytes ( buffer , offset , read ) ;
230
- if ( read > 0 )
231
- {
232
- return read ;
233
- }
211
+ // Decode the read bytes and update the input buffer with decoded bytes
212
+ read = DecodeBytes ( buffer . Span . Slice ( 0 , read ) ) ;
213
+ if ( read > 0 )
214
+ {
215
+ return read ;
234
216
}
235
217
}
236
218
}
237
219
238
- public override void Write ( byte [ ] buffer , int offset , int count )
220
+ protected override void WriteInternal ( ReadOnlySpan < byte > buffer )
239
221
{
240
- ValidateBufferArguments ( buffer , offset , count ) ;
241
-
242
222
int written = 0 ;
243
223
244
224
// do not append a space when writing from a stream since this means
245
225
// it's writing the email body
246
226
while ( true )
247
227
{
248
- written += EncodeBytes ( buffer , offset + written , count - written , false , false ) ;
249
- if ( written < count )
228
+ written += EncodeBytes ( buffer . Slice ( written ) , false , false ) ;
229
+ if ( written < buffer . Length )
250
230
{
251
231
FlushInternal ( ) ;
252
232
}
@@ -257,28 +237,22 @@ public override void Write(byte[] buffer, int offset, int count)
257
237
}
258
238
}
259
239
260
- public override Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
240
+ protected override async ValueTask WriteAsyncInternal ( ReadOnlyMemory < byte > buffer , CancellationToken cancellationToken = default )
261
241
{
262
- ValidateBufferArguments ( buffer , offset, count ) ;
263
- return WriteAsyncCore ( buffer , offset , count , cancellationToken ) ;
242
+ int written = 0 ;
264
243
265
- async Task WriteAsyncCore ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
244
+ // do not append a space when writing from a stream since this means
245
+ // it's writing the email body
246
+ while ( true )
266
247
{
267
- int written = 0 ;
268
-
269
- // do not append a space when writing from a stream since this means
270
- // it's writing the email body
271
- while ( true )
248
+ written += EncodeBytes ( buffer . Span . Slice ( written ) , false , false ) ;
249
+ if ( written < buffer . Length )
272
250
{
273
- written += EncodeBytes ( buffer , offset + written , count - written , false , false ) ;
274
- if ( written < count )
275
- {
276
- await FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
277
- }
278
- else
279
- {
280
- break ;
281
- }
251
+ await FlushInternalAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
252
+ }
253
+ else
254
+ {
255
+ break ;
282
256
}
283
257
}
284
258
}
0 commit comments