Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composite Stream Wrapper providing partial MemoryStream and full original Stream

Does anyone know of a composite stream solution that will pre-load the first portion of a Stream in to a MemoryStream and keep the remainder as the original Stream which will be accessed when subsequent parts are required as necessary?

I should imagine some wrapper class would implement the Stream interface and transparently juggle the access between the two streams depending upon which part is accessed.

I'm hoping this is a solution someone may have solved before, maybe to optimize performance of reading a large FileStream.

In my case I'm trying to get around a Windows Phone 8 bug reading large files from the SD card. More detail of the issue I'm trying to circumnavigate is provided in this answer: https://stackoverflow.com/a/17355068/250254

like image 263
Gavin Avatar asked Dec 30 '13 09:12

Gavin


1 Answers

There isn't any reasonable way you can use a MemoryStream to work around the bug, you'll fall over on OutOfMemoryException first. Let's focus a bit on the bug, I'll simplify the code a bit to make it readable:

DistanceToMove = (offset & 0xffffffff00000000L) >> 32;
DistanceToMoveHigh = offset & 0xffffffffL;
SetFilePointer(this.m_handle, lDistanceToMove, ref lDistanceToMoveHigh, begin);

The Microsoft programmer accidentally swapped the low and high values. Well, so can you to undo the bug. Swap them yourself so the bug swaps them back the way you want it:

public static void SeekBugWorkaround(Stream stream, long offset, SeekOrigin origin) {
    ulong uoffset = (ulong)offset;
    ulong fix = ((uoffset & 0xffffffffL) << 32) | ((uoffset & 0xffffffff00000000L) >> 32);
    stream.Seek((long)fix, origin);
}

In case it needs to be said, it apparently does, you do have to count on Microsoft eventually fixing this bug. Hard to predict when so gamble on the next point release. There are some odds you can auto-detect this, albeit that it isn't obvious what Microsoft is going to do since this bug is so breaking. The return value of Seek() as well as the Position property return value suffer from the same bug. So seek to position 1 and verify that you get 1 back.

like image 184
Hans Passant Avatar answered Sep 23 '22 14:09

Hans Passant