-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChunkedMemoryStream.cs
More file actions
138 lines (113 loc) · 3.73 KB
/
ChunkedMemoryStream.cs
File metadata and controls
138 lines (113 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System.Diagnostics;
namespace ORCToolKit
{
// why the fuck does Stream mix between 32 and 64 bit integers for counting data???
public class ChunkedMemoryStream: Stream
{
private readonly List<byte[]> _chunks = new List<byte[]>();
private readonly Int32 _chunkSize;
private Int32 _position = 0;
private Int32 _length = 0;
public ChunkedMemoryStream( Int32 ChunkSize, Int32 Capacity = 0 )
{
_chunkSize = ChunkSize;
EnsureChunksAllocated( Capacity );
}
public override bool CanRead { get { return true; } }
public override bool CanWrite { get { return true; } }
public override bool CanSeek { get { return true; } }
public override Int64 Length { get { return _length; } }
public override Int64 Position
{
get { return _position; }
set { _position = Convert.ToInt32( value ); }
}
public override Int64 Seek( Int64 Offset, SeekOrigin Location )
{
switch ( Location )
{
case SeekOrigin.Begin:
{
if ( Offset < 0 )
throw new IOException();
_position = Convert.ToInt32( Offset );
break;
}
case SeekOrigin.Current:
{
if ( _position + Offset < 0 )
throw new IOException();
_position += Convert.ToInt32( Offset );
break;
}
case SeekOrigin.End:
{
if ( _length + Offset < 0 )
throw new IOException();
_position = Convert.ToInt32( _length + Offset );
break;
}
default:
throw new ArgumentException();
}
Debug.Assert( _position >= 0, "_position >= 0" );
return _position;
}
public override Int32 Read( byte[] ByteBuffer, Int32 Offset, Int32 Count )
{
EnsureChunksAllocated( _length );
Int32 BytesToRead = Convert.ToInt32( _length - _position );
if ( BytesToRead > Count )
BytesToRead = Count;
if ( BytesToRead <= 0 )
return 0;
Debug.Assert( _position + BytesToRead >= 0, "_position + BytesToRead >= 0" );
Int32 DataReadSoFar = 0;
while ( DataReadSoFar < BytesToRead )
{
Int32 ChunkNum = _position / _chunkSize;
Int32 ChunkPosition = _position % _chunkSize;
Int32 ChunkCapacity = Int32.Min( _length - (ChunkNum * _chunkSize), _chunkSize );
Int32 ReadableDataThisChunk = Int32.Min( Count - DataReadSoFar, ChunkCapacity - ChunkPosition );
Buffer.BlockCopy( _chunks[ChunkNum], ChunkPosition, ByteBuffer, DataReadSoFar, ReadableDataThisChunk );
DataReadSoFar += ReadableDataThisChunk;
_position += ReadableDataThisChunk;
}
Debug.Assert( DataReadSoFar <= Count, "DataReadSoFar <= Count" );
return DataReadSoFar;
}
public override void Write( byte[] ByteBuffer, Int32 Offset, Int32 Count )
{
if ( _length < _position )
_length = _position;
_length += Count;
EnsureChunksAllocated( _length );
Int32 DataWroteSoFar = 0;
while ( DataWroteSoFar < Count )
{
Int32 ChunkNum = _position / _chunkSize;
Int32 ChunkPosition = _position % _chunkSize;
Int32 WritableDataThisChunk = Int32.Min( Count - DataWroteSoFar, _chunkSize - ChunkPosition );
Buffer.BlockCopy( ByteBuffer, DataWroteSoFar, _chunks[ChunkNum], ChunkPosition, WritableDataThisChunk );
DataWroteSoFar += WritableDataThisChunk;
_position += WritableDataThisChunk;
}
Debug.Assert( DataWroteSoFar <= Count, "DataWroteSoFar <= Count" );
}
public override void Flush() { }
public override void SetLength( Int64 NewLength )
{
if ( NewLength < 0 )
throw new ArgumentOutOfRangeException( nameof( NewLength ) );
_length = Convert.ToInt32( NewLength );
EnsureChunksAllocated( _length );
}
public Int32 GetChunksCount() => _chunks.Count;
private void EnsureChunksAllocated( Int32 Size )
{
// NOTE: this does not remove redundant chunks!
while ( Size > _chunks.Count * _chunkSize )
_chunks.Add( new byte[_chunkSize] );
}
}
}