@@ -197,15 +197,42 @@ private static byte[] GetBytesFromMemoryStream(System.IO.MemoryStream memStream)
197197 return result ;
198198 }
199199
200- // Fallback (position-aware)
201- byte [ ] all = memStream . ToArray ( ) ;
200+ // Fallback (position-aware) without copying the entire stream (MemoryStream.ToArray()).
201+ // Preserve caller's Position semantics.
202+ long originalPos = memStream . CanSeek ? memStream . Position : 0 ;
203+ byte [ ] resultFallback = GC . AllocateUninitializedArray < byte > ( remaining ) ;
202204
203- if ( pos64 == 0 && all . Length == remaining )
204- return all ;
205+ try
206+ {
207+ if ( memStream . CanSeek )
208+ memStream . Position = pos64 ;
205209
206- byte [ ] slice = GC . AllocateUninitializedArray < byte > ( remaining ) ;
207- Buffer . BlockCopy ( all , ( int ) pos64 , slice , 0 , remaining ) ;
208- return slice ;
210+ var totalRead = 0 ;
211+
212+ while ( totalRead < remaining )
213+ {
214+ int read = memStream . Read ( resultFallback , totalRead , remaining - totalRead ) ;
215+ if ( read == 0 )
216+ break ;
217+ totalRead += read ;
218+ }
219+
220+ if ( totalRead != remaining )
221+ {
222+ // Extremely defensive: if stream length changed mid-read (shouldn't happen for MemoryStream),
223+ // return the bytes we did read.
224+ byte [ ] truncated = new byte [ totalRead ] ;
225+ Buffer . BlockCopy ( resultFallback , 0 , truncated , 0 , totalRead ) ;
226+ return truncated ;
227+ }
228+
229+ return resultFallback ;
230+ }
231+ finally
232+ {
233+ if ( memStream . CanSeek )
234+ memStream . Position = originalPos ;
235+ }
209236 }
210237
211238 private async ValueTask < byte [ ] > GetBytesFromNonMemoryStream ( Stream stream , CancellationToken cancellationToken )
0 commit comments