@@ -386,64 +386,37 @@ internal static string JavaScriptStringEncode(string? value)
386
386
}
387
387
388
388
[ return : NotNullIfNotNull ( nameof ( bytes ) ) ]
389
- internal static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count , bool alwaysCreateNewReturnValue )
390
- {
391
- byte [ ] ? encoded = UrlEncode ( bytes , offset , count ) ;
392
-
393
- return ( alwaysCreateNewReturnValue && ( encoded != null ) && ( encoded == bytes ) )
394
- ? ( byte [ ] ) encoded . Clone ( )
395
- : encoded ;
396
- }
397
-
398
- [ return : NotNullIfNotNull ( nameof ( bytes ) ) ]
399
- private static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count )
389
+ internal static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count )
400
390
{
401
391
if ( ! ValidateUrlEncodingParameters ( bytes , offset , count ) )
402
392
{
403
393
return null ;
404
394
}
405
395
406
- int cSpaces = 0 ;
407
- int cUnsafe = 0 ;
408
-
409
- // count them first
410
- for ( int i = 0 ; i < count ; i ++ )
411
- {
412
- char ch = ( char ) bytes [ offset + i ] ;
413
-
414
- if ( ch == ' ' )
415
- {
416
- cSpaces ++ ;
417
- }
418
- else if ( ! HttpEncoderUtility . IsUrlSafeChar ( ch ) )
419
- {
420
- cUnsafe ++ ;
421
- }
422
- }
396
+ return UrlEncode ( bytes . AsSpan ( offset , count ) ) ;
397
+ }
423
398
399
+ private static byte [ ] UrlEncode ( ReadOnlySpan < byte > bytes )
400
+ {
424
401
// nothing to expand?
425
- if ( cSpaces == 0 && cUnsafe == 0 )
402
+ if ( ! IsExpandingNeeded ( bytes , out int cUnsafe ) )
426
403
{
427
- // DevDiv 912606: respect "offset" and "count"
428
- if ( 0 == offset && bytes . Length == count )
429
- {
430
- return bytes ;
431
- }
432
- else
433
- {
434
- byte [ ] subarray = new byte [ count ] ;
435
- Buffer . BlockCopy ( bytes , offset , subarray , 0 , count ) ;
436
- return subarray ;
437
- }
404
+ return bytes . ToArray ( ) ;
438
405
}
439
406
407
+ return UrlEncode ( bytes , cUnsafe ) ;
408
+ }
409
+
410
+ private static byte [ ] UrlEncode ( ReadOnlySpan < byte > bytes , int cUnsafe )
411
+ {
412
+ int count = bytes . Length ;
440
413
// expand not 'safe' characters into %XX, spaces to +s
441
414
byte [ ] expandedBytes = new byte [ count + cUnsafe * 2 ] ;
442
415
int pos = 0 ;
443
416
444
417
for ( int i = 0 ; i < count ; i ++ )
445
418
{
446
- byte b = bytes [ offset + i ] ;
419
+ byte b = bytes [ i ] ;
447
420
char ch = ( char ) b ;
448
421
449
422
if ( HttpEncoderUtility . IsUrlSafeChar ( ch ) )
@@ -465,6 +438,51 @@ internal static string JavaScriptStringEncode(string? value)
465
438
return expandedBytes ;
466
439
}
467
440
441
+ private static bool IsExpandingNeeded ( ReadOnlySpan < byte > bytes , out int cUnsafe )
442
+ {
443
+ cUnsafe = 0 ;
444
+
445
+ int cSpaces = 0 ;
446
+ int count = bytes . Length ;
447
+ for ( int i = 0 ; i < count ; i ++ )
448
+ {
449
+ char ch = ( char ) bytes [ i ] ;
450
+
451
+ if ( ch == ' ' )
452
+ {
453
+ cSpaces ++ ;
454
+ }
455
+ else if ( ! HttpEncoderUtility . IsUrlSafeChar ( ch ) )
456
+ {
457
+ cUnsafe ++ ;
458
+ }
459
+ }
460
+
461
+ return cSpaces != 0 || cUnsafe != 0 ;
462
+ }
463
+
464
+ internal static byte [ ] UrlEncode ( string str , Encoding e )
465
+ {
466
+ const int StackallocThreshold = 512 ;
467
+
468
+ if ( e . GetMaxByteCount ( str . Length ) <= StackallocThreshold )
469
+ {
470
+ Span < byte > byteSpan = stackalloc byte [ StackallocThreshold ] ;
471
+ int encodedBytes = e . GetBytes ( str , byteSpan ) ;
472
+
473
+ return UrlEncode ( byteSpan . Slice ( 0 , encodedBytes ) ) ;
474
+ }
475
+
476
+ byte [ ] bytes = e . GetBytes ( str ) ;
477
+ if ( ! IsExpandingNeeded ( bytes , out int cUnsafe ) )
478
+ {
479
+ // return encoded byte[] if nothing to expand
480
+ return bytes ;
481
+ }
482
+
483
+ return UrlEncode ( bytes . AsSpan ( 0 , bytes . Length ) , cUnsafe ) ;
484
+ }
485
+
468
486
// Helper to encode the non-ASCII url characters only
469
487
private static string UrlEncodeNonAscii ( string str , Encoding e )
470
488
{
0 commit comments