@@ -317,27 +317,7 @@ private static void DecodeSharedStrings(ReadOnlySpan<byte> sst, ReadOnlySpan<int
317317 pos += 4 ;
318318 }
319319 bool compressed = ( flags & 1 ) == 0 ;
320- int produced = 0 ;
321- bool truncated = false ;
322- for ( int c = 0 ; c < chars ; c ++ )
323- {
324- // Drop boundaries already behind us (splits outside the character array), then
325- // consume the grbit for a boundary that lands exactly on this character.
326- while ( boundaryIdx < boundaries . Length && boundaries [ boundaryIdx ] < pos ) { boundaryIdx ++ ; }
327- if ( boundaryIdx < boundaries . Length && boundaries [ boundaryIdx ] == pos )
328- {
329- if ( pos >= sst . Length ) { truncated = true ; break ; }
330- compressed = ( sst [ pos ] & 1 ) == 0 ;
331- pos ++ ;
332- boundaryIdx ++ ;
333- }
334- int step = compressed ? 1 : 2 ;
335- if ( pos + step > sst . Length ) { truncated = true ; break ; }
336- scratch [ produced ++ ] = compressed
337- ? DecodeCp1252 ( sst [ pos ] )
338- : ( char ) ( sst [ pos ] | ( sst [ pos + 1 ] << 8 ) ) ;
339- pos += step ;
340- }
320+ int produced = DecodeChars ( sst , boundaries , chars , scratch , ref pos , ref boundaryIdx , ref compressed , out bool truncated ) ;
341321 int maxBytes = System . Text . Encoding . UTF8 . GetMaxByteCount ( produced ) ;
342322 EnsureSharedCapacity ( options , ref flat , flatLen + maxBytes ) ;
343323 flatLen += System . Text . Encoding . UTF8 . GetBytes ( scratch . AsSpan ( 0 , produced ) , flat . AsSpan ( flatLen ) ) ;
@@ -360,6 +340,35 @@ private static void DecodeSharedStrings(ReadOnlySpan<byte> sst, ReadOnlySpan<int
360340 }
361341 }
362342
343+ // Decodes one shared string's code units into scratch, advancing the position and boundary
344+ // index and flipping the compression mode at each grbit boundary. Returns the unit count
345+ // produced, and reports truncated when the source ends mid-string.
346+ private static int DecodeChars ( ReadOnlySpan < byte > sst , ReadOnlySpan < int > boundaries , int chars , char [ ] scratch , ref int pos , ref int boundaryIdx , ref bool compressed , out bool truncated )
347+ {
348+ truncated = false ;
349+ int produced = 0 ;
350+ for ( int c = 0 ; c < chars ; c ++ )
351+ {
352+ // Drop boundaries already behind us (splits outside the character array), then
353+ // consume the grbit for a boundary that lands exactly on this character.
354+ while ( boundaryIdx < boundaries . Length && boundaries [ boundaryIdx ] < pos ) { boundaryIdx ++ ; }
355+ if ( boundaryIdx < boundaries . Length && boundaries [ boundaryIdx ] == pos )
356+ {
357+ if ( pos >= sst . Length ) { truncated = true ; break ; }
358+ compressed = ( sst [ pos ] & 1 ) == 0 ;
359+ pos ++ ;
360+ boundaryIdx ++ ;
361+ }
362+ int step = compressed ? 1 : 2 ;
363+ if ( pos + step > sst . Length ) { truncated = true ; break ; }
364+ scratch [ produced ++ ] = compressed
365+ ? DecodeCp1252 ( sst [ pos ] )
366+ : ( char ) ( sst [ pos ] | ( sst [ pos + 1 ] << 8 ) ) ;
367+ pos += step ;
368+ }
369+ return produced ;
370+ }
371+
363372 private static void EnsureSharedCapacity ( ExcelReaderOptions options , ref byte [ ] buffer , int needed )
364373 {
365374 if ( needed <= buffer . Length )
0 commit comments