The Stream.ReadByte method is implemented by allocating a 1 byte buffer and calling into Read(byte[], int, int). Override ReadByte in derived classes to avoid needing to allocate this small temp buffer. Also, fix some bugs in the stream implementations. Remove Write capability from MergedStream that didn't make sense. Add guards into SegmentStream to ensure reads and writes belonged to the segment - otherwise a reader or writer could access regions of the base stream that were outside the intended segment.
138 lines
2.8 KiB
C#
138 lines
2.8 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace OpenRA.Primitives
|
|
{
|
|
public class MergedStream : Stream
|
|
{
|
|
public Stream Stream1 { get; set; }
|
|
public Stream Stream2 { get; set; }
|
|
|
|
long VirtualLength { get; }
|
|
long position;
|
|
|
|
public MergedStream(Stream stream1, Stream stream2)
|
|
{
|
|
Stream1 = stream1;
|
|
Stream2 = stream2;
|
|
|
|
VirtualLength = Stream1.Length + Stream2.Length;
|
|
}
|
|
|
|
public override void Flush()
|
|
{
|
|
Stream1.Flush();
|
|
Stream2.Flush();
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
switch (origin)
|
|
{
|
|
case SeekOrigin.Begin:
|
|
position = offset;
|
|
break;
|
|
case SeekOrigin.Current:
|
|
position += offset;
|
|
break;
|
|
case SeekOrigin.End:
|
|
position = Length;
|
|
position += offset;
|
|
break;
|
|
}
|
|
|
|
if (position >= Stream1.Length)
|
|
position = Stream1.Length + Stream2.Seek(offset - Stream1.Length, SeekOrigin.Begin);
|
|
else
|
|
position = Stream1.Seek(offset, SeekOrigin.Begin);
|
|
|
|
return position;
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public override int ReadByte()
|
|
{
|
|
int value;
|
|
|
|
if (position >= Stream1.Length)
|
|
value = Stream2.ReadByte();
|
|
else
|
|
value = Stream1.ReadByte();
|
|
|
|
position++;
|
|
|
|
return value;
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
int bytesRead;
|
|
|
|
if (position >= Stream1.Length)
|
|
bytesRead = Stream2.Read(buffer, offset, count);
|
|
else if (count > Stream1.Length)
|
|
{
|
|
bytesRead = Stream1.Read(buffer, offset, (int)Stream1.Length);
|
|
bytesRead += Stream2.Read(buffer, (int)Stream1.Length, count - (int)Stream1.Length);
|
|
}
|
|
else
|
|
bytesRead = Stream1.Read(buffer, offset, count);
|
|
|
|
position += bytesRead;
|
|
|
|
return bytesRead;
|
|
}
|
|
|
|
public override void WriteByte(byte value)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public override bool CanRead
|
|
{
|
|
get { return Stream1.CanRead && Stream2.CanRead; }
|
|
}
|
|
|
|
public override bool CanSeek
|
|
{
|
|
get { return Stream1.CanSeek && Stream2.CanSeek; }
|
|
}
|
|
|
|
public override bool CanWrite
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override long Length
|
|
{
|
|
get { return VirtualLength; }
|
|
}
|
|
|
|
public override long Position
|
|
{
|
|
get { return position; }
|
|
set { Seek(value, SeekOrigin.Begin); }
|
|
}
|
|
}
|
|
}
|