Skip to content

Instantly share code, notes, and snippets.

@RyuaNerin
Last active September 28, 2015 23:32
Show Gist options
  • Save RyuaNerin/222de4fe794d70e867b1 to your computer and use it in GitHub Desktop.
Save RyuaNerin/222de4fe794d70e867b1 to your computer and use it in GitHub Desktop.
TextReader in range of stream or file.
using System;
using System.IO;
using System.Text;
/* For .NET Framework 4.5
using System.Threading.Tasks;
*/
namespace RyuaNerin
{
[Serializable]
internal class RangeTextReader : TextReader
{
private const int BufferSize = 64;
private Stream m_baseStream;
private int m_position;
private int m_end;
private bool m_leaveOpen;
private byte[] m_buffer = new byte[RangeTextReader.BufferSize];
private char[] m_chars = new char[RangeTextReader.BufferSize];
private int m_charPos;
private int m_charLen;
public RangeTextReader(string filePath, int offset, int length)
: this(new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read), offset, length, false, Encoding.UTF8)
{ }
public RangeTextReader(string filePath, int offset, int length, Encoding encoding)
: this(new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read), offset, length, false, encoding)
{ }
public RangeTextReader(Stream baseStream, int offset, int length, bool leaveOpen = false)
: this(baseStream, offset, length, leaveOpen, Encoding.UTF8)
{ }
public RangeTextReader(Stream baseStream, int offset, int length, Encoding encoding)
: this(baseStream, offset, length, false, encoding)
{ }
public RangeTextReader(Stream baseStream, int offset, int length, bool leaveOpen, Encoding encoding)
{
this.m_baseStream = baseStream;
this.m_position = offset;
this.m_end = offset + length;
this.m_leaveOpen = leaveOpen;
this.Encoding = encoding;
}
public Encoding Encoding { get; set; }
public override void Close()
{
if (!this.m_leaveOpen)
this.m_baseStream.Close();
base.Close();
}
protected override void Dispose(bool disposing)
{
if (!this.m_leaveOpen && this.m_baseStream != null)
{
this.m_baseStream.Dispose();
this.m_baseStream = null;
}
base.Dispose();
}
public override int Peek()
{
if (this.m_baseStream == null) throw new IOException();
if (this.m_charPos == this.m_charLen && this.ReadBuffer() == 0) return -1;
return this.m_chars[this.m_charPos];
}
public override int Read()
{
if (this.m_baseStream == null) throw new IOException();
if (this.m_charPos == this.m_charLen && this.ReadBuffer() == 0) return -1;
return this.m_chars[this.m_charPos++];
}
public override int Read(char[] buffer, int index, int count)
{
if (buffer == null) throw new ArgumentNullException();
if (index < 0 || count < 0) throw new ArgumentOutOfRangeException();
if (buffer.Length - index < count) throw new ArgumentException();
if (this.m_baseStream == null) throw new IOException();
int charsRead = 0;
int readable;
int i;
while (count > 0)
{
readable = this.m_charLen - this.m_charPos;
if (readable == 0 && (readable = this.ReadBuffer()) == 0)
break;
if (readable > count) readable = count;
readable = this.m_charPos + readable;
for (i = this.m_charPos; i < readable; ++i)
buffer[index++] = this.m_chars[this.m_charPos];
count = count - readable;
}
return charsRead;
}
public override int ReadBlock(char[] buffer, int index, int count)
{
if (this.m_baseStream == null) throw new IOException();
if (this.m_charPos == this.m_charLen && this.ReadBuffer() == 0) return -1;
int len = this.m_charPos - this.m_charLen;
len = len > count ? count : len;
int end = this.m_charPos + len;
while (this.m_charPos < end)
buffer[index++] = this.m_chars[this.m_charPos++];
return len;
}
public override string ReadLine()
{
if (this.m_baseStream == null) throw new IOException();
if (this.m_charPos == this.m_charLen && this.ReadBuffer() == 0) return null;
var sb = new StringBuilder();
int i = 0;
char ch;
do
{
do
{
ch = this.m_chars[this.m_charPos++];
if (ch != '\r' && ch != '\n')
sb.Append(ch);
else
{
// \r\n
if (ch == '\r' && (this.m_charPos < this.m_charLen || this.ReadBuffer() > 0))
if (this.m_chars[this.m_charPos] == '\n')
this.m_charPos++;
return sb.ToString();
}
} while (this.m_charPos < this.m_charLen);
i = this.m_charLen - this.m_charPos;
sb.Append(this.m_chars, this.m_charLen, i);
} while (this.ReadBuffer() > 0);
return sb.ToString();
}
public override string ReadToEnd()
{
if (this.m_baseStream == null) throw new IOException();
var sb = new StringBuilder();
do
{
sb.Append(this.m_chars, this.m_charPos, this.m_charLen - this.m_charPos);
this.m_charPos = this.m_charLen;
this.ReadBuffer();
} while (this.m_charLen > 0);
return sb.ToString();
}
/* For .NET Framework 4.5
[Obsolete("Async is not supported")]
public override Task<int> ReadAsync(char[] buffer, int index, int count)
{
throw new NotSupportedException();
}
[Obsolete("Async is not supported")]
public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
{
throw new NotSupportedException();
}
[Obsolete("Async is not supported")]
public override Task<string> ReadLineAsync()
{
throw new NotSupportedException();
}
[Obsolete("Async is not supported")]
public override Task<string> ReadToEndAsync()
{
throw new NotSupportedException();
}
*/
private int ReadBuffer()
{
var p = this.m_baseStream.Position;
var r = this.ReadBufferPriv();
this.m_baseStream.Position = p;
return r;
}
private int ReadBufferPriv()
{
this.m_charLen = 0;
this.m_charPos = 0;
int len;
int read = 0;
do
{
len = RangeTextReader.BufferSize;
if (this.m_position + len >= this.m_end)
len = this.m_end - this.m_position;
if (len == 0) return 0;
this.m_baseStream.Position = this.m_position;
len = this.m_baseStream.Read(this.m_buffer, 0, len);
if (len == 0 || this.m_position >= this.m_end) //EOF
return this.m_charLen;
this.m_position += len;
read = this.Encoding.GetChars(this.m_buffer, 0, len, this.m_chars, this.m_charLen);
this.m_charLen += read;
} while (read == 0);
return this.m_charLen;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment