Quantcast
Channel: Rebex Q&A Forum - Recent questions and answers
Viewing all articles
Browse latest Browse all 3862

Answered: Understanding GetContent and SaveContent

$
0
0

Here is what I came up with, based on the inspiration I got from renestein. Writing the custom stream was trickier than expected (and I'm still not 100% sure if all the locking stuff is correct), but first tests look promising.

So I'm no longer using SaveContent, and my new GetContent looks something like this:

protected override NodeContent GetContent(NodeBase node, NodeContentParameters contentParameters)
{
    if (contentParameters.AccessType == NodeContentAccess.Read)
    {
        return NodeContent.CreateReadOnlyContent(new MemoryStream());
    }
    else
    {
        var stream = new MyFileContentStream();
        MyOwnCode.ProvideStreamSoThatDataSinkCanStartReading(stream);
        return NodeContent.CreateImmediateWriteContent(stream);
    }
}

And this is the new stream class which allows reading from my data sink and writing by your library at the same time:

internal class MyFileContentStream : Stream
{

    private byte[] CurrentBuffer = null;
    private int ReadPointer = 0;

    private readonly AutoResetEvent NotifyBufferEmpty = new AutoResetEvent(true);
    private readonly ManualResetEvent NotifyDataAvailable = new ManualResetEvent(false);

    public override void Write(byte[] buffer, int offset, int count)
    {
        // block until local buffer is empty
        NotifyBufferEmpty.WaitOne();

        // copy bytes
        CurrentBuffer = new byte[count];
        ReadPointer = 0;
        Buffer.BlockCopy(buffer, offset, CurrentBuffer, 0, count);

        // notify new data is available
        NotifyDataAvailable.Set();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        // block until data available
        NotifyDataAvailable.WaitOne();

        // notify end of stream when no more buffer available
        if (CurrentBuffer == null)
            return 0;

        // copy bytes
        var availableBytes = CurrentBuffer.Length - ReadPointer;
        var readBytes = Math.Min(count, availableBytes);
        Buffer.BlockCopy(CurrentBuffer, ReadPointer, buffer, offset, readBytes);
        ReadPointer += readBytes;

        // check if we have copied all bytes of the current buffer
        if (CurrentBuffer.Length == ReadPointer)
        {
            CurrentBuffer = null;

            // make sure we can no longer read
            NotifyDataAvailable.Reset();

            // notify buffer empty
            NotifyBufferEmpty.Set();
        }

        return readBytes;
    }

    public override void Flush()
    {
        NotifyBufferEmpty.WaitOne();
        CurrentBuffer = null;
        ReadPointer = 0;
        NotifyBufferEmpty.Set();
        NotifyDataAvailable.Set();
    }

    protected override void Dispose(bool disposing)
    {
        Flush();
        base.Dispose(disposing);
    }

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => true;

    public override long Length => 0;

    public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }

    public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();

    public override void SetLength(long value) => throw new NotSupportedException();

}

Viewing all articles
Browse latest Browse all 3862

Trending Articles