@@ -15,7 +15,7 @@ namespace Microsoft.DotNet.XHarness.TestRunners.Xunit;
1515
1616internal class WasmXmlResultWriter
1717{
18- #if ! NET || DEBUG
18+ #if DEBUG
1919 public static void WriteOnSingleLine ( XElement assembliesElement )
2020 {
2121 using var ms = new MemoryStream ( ) ;
@@ -29,6 +29,7 @@ public static void WriteOnSingleLine(XElement assembliesElement)
2929 private class ToBase64CharTransform : ICryptoTransform
3030 {
3131 private readonly ToBase64Transform _base64Transform = new ToBase64Transform ( ) ;
32+ private byte [ ] _intermediate = new byte [ 2 ] ;
3233
3334 public int InputBlockSize => _base64Transform . InputBlockSize ; // 3 bytes of input
3435 public int OutputBlockSize => _base64Transform . OutputBlockSize * 2 ; // 4 bytes of base64 output * 2 for UTF-16 encoding
@@ -45,66 +46,71 @@ public int TransformBlock(
4546 byte [ ] inputBuffer , int inputOffset , int inputCount ,
4647 byte [ ] outputBuffer , int outputOffset )
4748 {
48- int totalBytesWritten = 0 ;
49- int inputProcessed = 0 ;
49+ int inputBlocks = Math . DivRem ( inputCount , InputBlockSize , out int inputRemainder ) ;
5050
51- while ( inputProcessed < inputCount )
51+ if ( inputRemainder != 0 )
5252 {
53- int bytesToProcess = Math . Min ( InputBlockSize , inputCount - inputProcessed ) ;
54-
55- /*
56- Input Buffer ("hi mom"):
57- +-----+-----+-----+-----+-----+-----+
58- | 'h' | 'i' | ' ' | 'm' | 'o' | 'm' |
59- +-----+-----+-----+-----+-----+-----+
60- |104 |105 | 32 |109 |111 |109 |
61- +-----+-----+-----+-----+-----+-----+
62-
63- Base64 Encoding Process:
64- - 'hi ' -> 'aGkg'
65- - 'mom' -> 'bW9t'
66-
67- Base64 Encoded Output:
68- | |base64Written | | base64Written |
69- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
70- | \0 | \0 | \0 | \0 |'a' |'G' |'k' |'g' | \0 | \0 | \0 | \0 |'b' |'W' |'9' |'t' |
71- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
72- | 0 | 0 | 0 | 0 | 97 | 71 |107 |103 | 0 | 0 | 0 | 0 | 98 | 87 | 57 |116 |
73- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
74-
75- Expanded Output Buffer (UTF-16 Encoding):
76- | outputChars | outputChars |
77- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
78- | \0 |'a' | \0 |'G' | \0 |'k' | \0 |'g' | \0 |'b' | \0 |'W' | \0 |'9' | \0 |'t' |
79- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
80- | 0 | 97 | 0 | 71 | 0 |107 | 0 |103 | 0 | 98 | 0 | 87 | 0 | 57 | 0 |116 |
81- +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
82-
83- */
84-
85- // Calculate positions in the output buffer
86- int outputStart = outputOffset + totalBytesWritten ;
87- int base64OutputStart = outputStart + OutputBlockSize / 2 ;
88-
89- // write Base64 transformation directly to the second half of the output buffer
90- int base64BytesWritten = _base64Transform . TransformBlock (
91- inputBuffer , inputOffset + inputProcessed , bytesToProcess ,
92- outputBuffer , base64OutputStart ) ;
93-
94- var base64Written = outputBuffer . AsSpan ( base64OutputStart , base64BytesWritten ) ;
95- var outputChars = outputBuffer . AsSpan ( outputStart , OutputBlockSize ) ;
96- for ( int i = 0 ; i < base64BytesWritten ; i ++ )
53+ throw new ArgumentException ( $ "Input count must be a multiple of { InputBlockSize } .", nameof ( inputCount ) ) ;
54+ }
55+
56+ if ( inputCount == 0 )
57+ {
58+ throw new ArgumentException ( "Input count must be greater than 0." , nameof ( inputCount ) ) ;
59+ }
60+
61+ /*
62+ Input Buffer ("hi mom"):
63+ +-----+-----+-----+-----+-----+-----+
64+ | 'h' | 'i' | ' ' | 'm' | 'o' | 'm' |
65+ +-----+-----+-----+-----+-----+-----+
66+ |104 |105 | 32 |109 |111 |109 |
67+ +-----+-----+-----+-----+-----+-----+
68+
69+ Base64 Encoding Process:
70+ - 'hi ' -> 'aGkg'
71+ - 'mom' -> 'bW9t'
72+
73+ Base64 Encoded Output:
74+ | |base64Written | | base64Written |
75+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
76+ | \0 | \0 | \0 | \0 |'a' |'G' |'k' |'g' | \0 | \0 | \0 | \0 |'b' |'W' |'9' |'t' |
77+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
78+ | 0 | 0 | 0 | 0 | 97 | 71 |107 |103 | 0 | 0 | 0 | 0 | 98 | 87 | 57 |116 |
79+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
80+
81+ Expanded Output Buffer (UTF-16 Encoding):
82+ | outputChars | outputChars |
83+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
84+ | \0 |'a' | \0 |'G' | \0 |'k' | \0 |'g' | \0 |'b' | \0 |'W' | \0 |'9' | \0 |'t' |
85+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
86+ | 0 | 97 | 0 | 71 | 0 |107 | 0 |103 | 0 | 98 | 0 | 87 | 0 | 57 | 0 |116 |
87+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
88+
89+ */
90+
91+ // Calculate positions in the output buffer
92+ int base64OutputStart = outputOffset + OutputBlockSize / 2 ;
93+
94+ // write Base64 transformation directly to the second half of the output buffer
95+ int base64BytesWritten = _base64Transform . TransformBlock (
96+ inputBuffer , inputOffset , inputCount ,
97+ outputBuffer , base64OutputStart ) ;
98+
99+ var base64Written = outputBuffer . AsSpan ( base64OutputStart , base64BytesWritten ) ;
100+ var outputChars = outputBuffer . AsSpan ( outputOffset , OutputBlockSize ) ;
101+
102+ for ( int i = 0 ; i < base64BytesWritten ; i ++ )
103+ {
104+ // Expand each ascii byte to a char write it in the same logical position
105+ // as a char in outputChars eventually filling the output buffer
106+ if ( ! BitConverter . TryWriteBytes ( outputChars . Slice ( i * 2 ) , ( char ) base64Written [ i ] ) )
97107 {
98- // Expand each ascii byte to a char write it in the same logical position
99- // as a char in outputChars eventually filling the output buffer
100- BitConverter . TryWriteBytes ( outputChars . Slice ( i * 2 ) , ( char ) base64Written [ i ] ) ;
108+ BitConverter . TryWriteBytes ( _intermediate , ( char ) base64Written [ i ] ) ;
109+ _intermediate . CopyTo ( outputChars . Slice ( i * 2 , 2 ) ) ;
101110 }
102-
103- inputProcessed += bytesToProcess ;
104- totalBytesWritten += base64BytesWritten * 2 ;
105111 }
106112
107- return totalBytesWritten ;
113+ return base64BytesWritten * 2 ;
108114 }
109115
110116 public byte [ ] TransformFinalBlock ( byte [ ] inputBuffer , int inputOffset , int inputCount )
@@ -144,9 +150,9 @@ public static void WriteOnSingleLine(XElement assembliesElement)
144150 // we went to a lot of trouble to put characters in the final buffer
145151 // so that we can avoid a copy here and pass the span directly to the
146152 // string interpolation logic.
147- Span < char > charData = MemoryMarshal . Cast < byte , char > ( bytes ) ;
153+ Span < char > charData = MemoryMarshal . Cast < byte , char > ( bytes . AsSpan ( ) ) ;
148154
149- // Output the result
155+ // Output the result and the the ascii length of the data
150156 Console . WriteLine ( $ "STARTRESULTXML { charData . Length } { charData } ENDRESULTXML") ;
151157 Console . WriteLine ( $ "Finished writing { charData . Length } bytes of RESULTXML") ;
152158 }
0 commit comments