Last active
September 28, 2015 23:32
-
-
Save RyuaNerin/222de4fe794d70e867b1 to your computer and use it in GitHub Desktop.
TextReader in range of stream or file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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