2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
+ using System . Buffers ;
5
6
using System . Diagnostics ;
6
7
using System . Globalization ;
7
8
using Microsoft . Extensions . WebEncoders . Sources ;
@@ -220,6 +221,9 @@ public static string Base64UrlEncode(byte[] input, int offset, int count)
220
221
221
222
ValidateParameters ( input . Length , nameof ( input ) , offset , count ) ;
222
223
224
+ #if NETCOREAPP3_0
225
+ return Base64UrlEncode ( input . AsSpan ( offset , count ) ) ;
226
+ #else
223
227
// Special-case empty input
224
228
if ( count == 0 )
225
229
{
@@ -229,7 +233,8 @@ public static string Base64UrlEncode(byte[] input, int offset, int count)
229
233
var buffer = new char [ GetArraySizeRequiredToEncode ( count ) ] ;
230
234
var numBase64Chars = Base64UrlEncode ( input , offset , buffer , outputOffset : 0 , count : count ) ;
231
235
232
- return new String ( buffer , startIndex : 0 , length : numBase64Chars ) ;
236
+ return new string ( buffer , startIndex : 0 , length : numBase64Chars ) ;
237
+ #endif
233
238
}
234
239
235
240
/// <summary>
@@ -280,6 +285,9 @@ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int o
280
285
nameof ( count ) ) ;
281
286
}
282
287
288
+ #if NETCOREAPP3_0
289
+ return Base64UrlEncode ( input . AsSpan ( offset , count ) , output . AsSpan ( outputOffset ) ) ;
290
+ #else
283
291
// Special-case empty input.
284
292
if ( count == 0 )
285
293
{
@@ -311,6 +319,7 @@ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int o
311
319
}
312
320
313
321
return numBase64Chars ;
322
+ #endif
314
323
}
315
324
316
325
/// <summary>
@@ -327,6 +336,73 @@ public static int GetArraySizeRequiredToEncode(int count)
327
336
return checked ( numWholeOrPartialInputBlocks * 4 ) ;
328
337
}
329
338
339
+ #if NETCOREAPP3_0
340
+ /// <summary>
341
+ /// Encodes <paramref name="input"/> using base64url encoding.
342
+ /// </summary>
343
+ /// <param name="input">The binary input to encode.</param>
344
+ /// <returns>The base64url-encoded form of <paramref name="input"/>.</returns>
345
+ public static string Base64UrlEncode ( ReadOnlySpan < byte > input )
346
+ {
347
+ if ( input . IsEmpty )
348
+ {
349
+ return string . Empty ;
350
+ }
351
+
352
+ int bufferSize = GetArraySizeRequiredToEncode ( input . Length ) ;
353
+
354
+ char [ ] bufferToReturnToPool = null ;
355
+ Span < char > buffer = bufferSize <= 128
356
+ ? stackalloc char [ bufferSize ]
357
+ : bufferToReturnToPool = ArrayPool < char > . Shared . Rent ( bufferSize ) ;
358
+
359
+ var numBase64Chars = Base64UrlEncode ( input , buffer ) ;
360
+ var base64Url = new string ( buffer . Slice ( 0 , numBase64Chars ) ) ;
361
+
362
+ if ( bufferToReturnToPool != null )
363
+ {
364
+ ArrayPool < char > . Shared . Return ( bufferToReturnToPool ) ;
365
+ }
366
+
367
+ return base64Url ;
368
+ }
369
+
370
+ private static int Base64UrlEncode ( ReadOnlySpan < byte > input , Span < char > output )
371
+ {
372
+ Debug . Assert ( output . Length >= GetArraySizeRequiredToEncode ( input . Length ) ) ;
373
+
374
+ if ( input . IsEmpty )
375
+ {
376
+ return 0 ;
377
+ }
378
+
379
+ // Use base64url encoding with no padding characters. See RFC 4648, Sec. 5.
380
+
381
+ Convert . TryToBase64Chars ( input , output , out int charsWritten ) ;
382
+
383
+ // Fix up '+' -> '-' and '/' -> '_'. Drop padding characters.
384
+ for ( var i = 0 ; i < charsWritten ; i ++ )
385
+ {
386
+ var ch = output [ i ] ;
387
+ if ( ch == '+' )
388
+ {
389
+ output [ i ] = '-' ;
390
+ }
391
+ else if ( ch == '/' )
392
+ {
393
+ output [ i ] = '_' ;
394
+ }
395
+ else if ( ch == '=' )
396
+ {
397
+ // We've reached a padding character; truncate the remainder.
398
+ return i ;
399
+ }
400
+ }
401
+
402
+ return charsWritten ;
403
+ }
404
+ #endif
405
+
330
406
private static int GetNumBase64PaddingCharsInString ( string str )
331
407
{
332
408
// Assumption: input contains a well-formed base64 string with no whitespace.
0 commit comments