-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathAlignedStream.cs
152 lines (131 loc) · 4.59 KB
/
AlignedStream.cs
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
using System;
using System.IO;
namespace XboxWinFsp
{
// Kinda hacky stream that will only read the basestream from the given alignment
// (eg. only reads in 512-byte blocks, at 512-byte offsets)
//
// This should be transparent to the user of the stream, eg. allowing a 3-byte read from any offset
// Reading seems to work pretty well right now, hopefully support for writing can be added later
public class AlignedStream : Stream
{
Stream Stream;
int Alignment = 0x200;
public AlignedStream(Stream stream, int alignment)
{
Stream = stream;
Alignment = alignment;
Position = stream.Position;
}
public override bool CanRead { get { return true; } }
public override bool CanWrite { get { return true; } }
public override bool CanSeek { get { return true; } }
byte[] AlignmentBuffer;
long AlignmentPosition = 0;
private long position;
bool FillBuffer = false;
public override long Position
{
get
{
return position;
}
set
{
position = value;
long alignedPosition = (position / Alignment) * Alignment;
FillBuffer = false;
if (alignedPosition != AlignmentPosition)
{
Stream.Position = alignedPosition;
FillBuffer = true;
}
}
}
int BufferCurrentOffset
{
get
{
return (int)(Position % Alignment);
}
}
int BufferBytesRemaining
{
get
{
return Alignment - BufferCurrentOffset;
}
}
public override long Length => Stream.Length;
public override void SetLength(long value)
{
Stream.SetLength(value);
}
public override void Flush()
{
Stream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
Position = offset;
else if (origin == SeekOrigin.Current)
Position = Position + offset;
else if (origin == SeekOrigin.End)
Position = Length - offset;
return Position;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (AlignmentBuffer == null)
AlignmentBuffer = new byte[Alignment];
if (FillBuffer)
{
AlignmentPosition = Stream.Position;
Stream.Read(AlignmentBuffer, 0, Alignment);
FillBuffer = false;
}
int bufferOffset = BufferCurrentOffset;
// Do we have the data requested in the buffer?
if (count <= BufferBytesRemaining)
{
Array.Copy(AlignmentBuffer, bufferOffset, buffer, offset, count);
// Did we just finish reading all of the buffer?
if (BufferCurrentOffset == 0)
FillBuffer = true; // Make it read a new buffer next turn
Position += count;
}
else
{
// We don't have the data here
// Is the data bigger than our alignment?
if (count > Alignment)
{
// It is - read in each alignment block
int numBlocks = ((count + Alignment - 1) / Alignment);
for (int i = 0; i < numBlocks; i++)
{
int read = (i + 1) >= numBlocks ? (count % Alignment) : Alignment;
if (read == 0)
read = Alignment;
Read(buffer, offset + (i * Alignment), read);
}
}
else
{
// It isn't - must mean the data spans over two alignment buffers
// Read in the remainder of this alignment
int remainder = BufferBytesRemaining;
Read(buffer, offset, remainder);
// Then read in anything afterward:
Read(buffer, offset + remainder, count - remainder);
}
}
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
}