@@ -952,6 +952,90 @@ public static void UTF8toUTF16(ReadOnlySpan<byte> utf8, CharsRef chars)
952952 chars . Length = out_offset - chars . Offset ;
953953 }
954954
955+ /// <summary>
956+ /// Interprets the given byte array as UTF-8 and converts to UTF-16. The <see cref="CharsRef"/> will be extended if
957+ /// it doesn't provide enough space to hold the worst case of each byte becoming a UTF-16 codepoint.
958+ /// <para/>
959+ /// NOTE: This method will replace any invalid UTF-8 byte sequences with the Unicode replacement character U+FFFD.
960+ /// </summary>
961+ /// <remarks>
962+ /// LUCENENET specific, for use in ToString() where we want to avoid throwing exceptions.
963+ /// </remarks>
964+ /// <seealso cref="UTF8toUTF16WithFallback(ReadOnlySpan{byte}, CharsRef)"/>
965+ // TODO: broken if chars.offset != 0
966+ public static void UTF8toUTF16WithFallback ( byte [ ] utf8 , int offset , int length , CharsRef chars )
967+ {
968+ UTF8toUTF16 ( utf8 . AsSpan ( offset , length ) , chars ) ;
969+ }
970+
971+ /// <summary>
972+ /// Interprets the given byte span as UTF-8 and converts to UTF-16. The <see cref="CharsRef"/> will be extended if
973+ /// it doesn't provide enough space to hold the worst case of each byte becoming a UTF-16 codepoint.
974+ /// <para/>
975+ /// NOTE: This method will replace any invalid UTF-8 byte sequences with the Unicode replacement character U+FFFD.
976+ /// </summary>
977+ /// <remarks>
978+ /// LUCENENET specific, for use in ToString() where we want to avoid throwing exceptions.
979+ /// </remarks>
980+ // TODO: broken if chars.offset != 0
981+ public static void UTF8toUTF16WithFallback ( ReadOnlySpan < byte > utf8 , CharsRef chars )
982+ {
983+ int out_offset = chars . Offset = 0 ;
984+ char [ ] @out = chars . Chars = ArrayUtil . Grow ( chars . Chars , utf8 . Length ) ;
985+ int i = 0 ;
986+
987+ while ( i < utf8 . Length )
988+ {
989+ int b = utf8 [ i ++ ] & 0xff ;
990+ if ( b < 0xc0 )
991+ {
992+ if ( Debugging . AssertsEnabled ) Debugging . Assert ( b < 0x80 ) ;
993+ @out [ out_offset ++ ] = ( char ) b ;
994+ }
995+ else if ( b < 0xe0 )
996+ {
997+ if ( utf8 . Length <= i )
998+ {
999+ @out [ out_offset ++ ] = ( char ) 0xfffd ;
1000+ continue ;
1001+ }
1002+ @out [ out_offset ++ ] = ( char ) ( ( ( b & 0x1f ) << 6 ) + ( utf8 [ i ++ ] & 0x3f ) ) ;
1003+ }
1004+ else if ( b < 0xf0 )
1005+ {
1006+ if ( utf8 . Length <= i + 1 )
1007+ {
1008+ @out [ out_offset ++ ] = ( char ) 0xfffd ;
1009+ break ;
1010+ }
1011+ @out [ out_offset ++ ] = ( char ) ( ( ( b & 0xf ) << 12 ) + ( ( utf8 [ i ] & 0x3f ) << 6 ) + ( utf8 [ i + 1 ] & 0x3f ) ) ;
1012+ i += 2 ;
1013+ }
1014+ else
1015+ {
1016+ if ( utf8 . Length <= i + 2 )
1017+ {
1018+ @out [ out_offset ++ ] = ( char ) 0xfffd ;
1019+ break ;
1020+ }
1021+ if ( Debugging . AssertsEnabled ) Debugging . Assert ( b < 0xf8 , "b = 0x{0:x}" , b ) ;
1022+ int ch = ( ( b & 0x7 ) << 18 ) + ( ( utf8 [ i ] & 0x3f ) << 12 ) + ( ( utf8 [ i + 1 ] & 0x3f ) << 6 ) + ( utf8 [ i + 2 ] & 0x3f ) ;
1023+ i += 3 ;
1024+ if ( ch < UNI_MAX_BMP )
1025+ {
1026+ @out [ out_offset ++ ] = ( char ) ch ;
1027+ }
1028+ else
1029+ {
1030+ int chHalf = ch - 0x0010000 ;
1031+ @out [ out_offset ++ ] = ( char ) ( ( chHalf >> 10 ) + 0xD800 ) ;
1032+ @out [ out_offset ++ ] = ( char ) ( ( chHalf & HALF_MASK ) + 0xDC00 ) ;
1033+ }
1034+ }
1035+ }
1036+ chars . Length = out_offset - chars . Offset ;
1037+ }
1038+
9551039 /// <summary>
9561040 /// Tries to interpret the given byte span as UTF-8 and convert to UTF-16, providing the result in a new <see cref="CharsRef"/>.
9571041 /// <para/>
@@ -983,12 +1067,6 @@ public static bool TryUTF8toUTF16(ReadOnlySpan<byte> utf8, [NotNullWhen(true)] o
9831067
9841068 while ( i < utf8 . Length )
9851069 {
986- if ( utf8 . Length <= i )
987- {
988- chars = null ;
989- return false ;
990- }
991-
9921070 int b = utf8 [ i ++ ] & 0xff ;
9931071 if ( b < 0xc0 )
9941072 {
0 commit comments