context: // HtmlAgilityPack V1.3.1.0 - Simon Mourier <simonm@microsoft.com>
  using System;
  using System.Diagnostics;
  using System.IO;
  using System.Text;
  
  namespace HtmlAgilityPack
  {
  	/// <summary>
  	/// Represents a rewindable buffered TextReader specifically well suited for parsing operations.
  	/// </summary>
  	public class ParseReader: Stream
  	{
  		private StringBuilder _sb;
  		private int _baseReaderPosition;
  		private int _maxReaderPosition;
  		private int _position;
  		private TextReader _baseReader;
  
  		/// <summary>
  		/// Initializes an instance of the ParserReader class, based on an existing TextReader instance.
  		/// </summary>
  		/// <param name="baseReader">The TextReader to base parsing on. Must not be null.</param>
  		public ParseReader(TextReader baseReader)
  		{
  			if (baseReader == null)
  				throw new ArgumentNullException("baseReader");
  
  			_baseReader = baseReader;
  			_sb = new StringBuilder();
  			_position = 0;
  			_baseReaderPosition = 0;
  			_maxReaderPosition = int.MaxValue;
  		}
  
  		/// <summary>
  		/// Gets the length in bytes of the stream.
  		/// Always throws a NotSupportedException for the ParserReader class.
  		/// </summary>
  		public override long Length
  		{
  			get
  			{
  				throw new NotSupportedException();
  			}
  		}
  
  		/// <summary>
  		/// Gets or sets the position within the stream.
  		/// </summary>
  		public override long Position
  		{
  			get
  			{
  				return _position;
  			}
  			set
  			{
  				if (value < 0)
  					throw new ArgumentException("value is negative: " + value + ".");
  				if (value > int.MaxValue)
  					throw new ArgumentException("value must not be larger than int32 MaxValue.");
  				_position = (int)value;
  			}
  		}
  
  		/// <summary>
  		/// Checks the length of the underlying stream.
  		/// </summary>
  		/// <param name="length">The required length.</param>
  		/// <returns>true if the underlying stream's length is greater than the required length, false otherwise.</returns>
  		public bool CheckLength(int length)
  		{
  			if (length <= 0)
  				throw new ArgumentException("length must be greater than zero.");
  
  			if (BufferedTextLength >= length)
  				return true;
  
  			Seek(length, SeekOrigin.Begin);
  			return (BufferedTextLength >= length);
  		}
  
  		/// <summary>
  		/// Gets a value indicating whether the current stream supports seeking.
  		/// Always returns true for the ParserReader class.
  		/// </summary>
  		public override bool CanSeek
  		{
  			get
  			{
  				return true;
  			}
  		}
  
  		/// <summary>
  		/// Gets a value indicating whether the current stream supports reading.
  		/// Always returns true for the ParserReader class.
  		/// </summary>
  		public override bool CanRead
  		{
  			get
  			{
  				return true;
  			}
  		}
  
  		/// <summary>
  		/// Gets a value indicating whether the current stream supports writing.
  		/// Always returns false for the ParserReader class.
  		/// </summary>
  		public override bool CanWrite
  		{
  			get
  			{
  				return false;
  			}
  		}
  
  		/// <summary>
  		/// Sets the length of the current stream.
  		/// Always throws a NotSupportedException for the ParserReader class.
  		/// </summary>
  		/// <param name="value">The desired length of the current stream in bytes.</param>
  		public override void SetLength(long value)
  		{
  			throw new NotSupportedException();
  		}
  
  		/// <summary>
  		/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
  		/// </summary>
  		public override void Flush()
  		{
  			// nothing to do
  		}
  
  		/// <summary>
  		/// Gets the position within the underlying stream.
  		/// </summary>
  		public int BaseReaderPosition
  		{
  			get
  			{
  				return _baseReaderPosition;
  			}
  		}
  
  		/// <summary>
  		/// Gets the maximum position within the underlying stream.
  		/// </summary>
  		public int MaxReaderPosition
  		{
  			get
  			{
  				return _maxReaderPosition;
  			}
  		}
  
  		private void CheckBaseReader()
  		{
  			if (_baseReader == null)
  				throw new InvalidOperationException("Cannot read from a closed ParseReader.");
  		}
  
  		/// <summary>
  		/// Closes the current underlying stream.
  		/// </summary>
  		public void CloseBaseReader()
  		{
  			if (_maxReaderPosition != int.MaxValue) // we have already closed it
  				return;
  
  			CheckBaseReader();
  
  			_baseReader.Close();
  			_baseReader = null;
  		}
  
  		private void InternalCloseBaseReader()
  		{
  			CloseBaseReader();
  			_maxReaderPosition = _position;
  		}
  
  		/// <summary>
  		/// Returns the next available character but does not consume it.
  		/// </summary>
  		/// <returns>The next character to be read, or -1 if no more characters are available.</returns>
  		public int Peek()
  		{
  			if (_position < _baseReaderPosition)
  				return Convert.ToInt32(this[_position]);
  
  			if (_position == _maxReaderPosition)
  				return -1;
  
  			CheckBaseReader();
  			int i = _baseReader.Peek();
  			if (i < 0)
  			{
  				InternalCloseBaseReader();
  				return i;
  			}
  
  			Debug.Assert(_position >= _baseReaderPosition);
  			if (_position == _baseReaderPosition)
  			{
  				if (_sb.Length < (_position + 1))
  				{
  					_sb.Append(Convert.ToChar(i));
  				}
  			}
  			return i;
  		}
  
  		/// <summary>
  		/// Reads the next character and advances the character position by one character.
  		/// </summary>
  		/// <returns>The next character represented as an Int32, or -1 if no more characters are available.</returns>
  		public int Read()
  		{
  			int i;
  			if (_position < _baseReaderPosition)
  			{
  				i =  Convert.ToInt32(_sb[_position]);
  				_position++;
  				return i;
  			}
  
  			if (_position == _maxReaderPosition)
  				return -1;
  
  			CheckBaseReader();
  			i = _baseReader.Read();
  			if (i < 0)
  			{
  				InternalCloseBaseReader();
  				return i;
  			}
  
  			if (_position >= _baseReaderPosition)
  			{
  				if (_sb.Length < (_position + 1))
  				{
  					_sb.Append(Convert.ToChar(i));
  				}
  			}
  			_baseReaderPosition++;
  			_position++;
  			return i;
  		}
  
  		/// <summary>
  		/// Move the position starting from the current position.
  		/// </summary>
  		/// <param name="count">A character offset relative to the current position.</param>
  		/// <returns>The new position.</returns>
  		public int Seek(int count)
  		{
  			int i;
  			if (count < 0)
  			{
  				if ((_position + count ) < 0)
  				{
  					i = _position;
  					_position = 0;
  					return i;
  				}
  				else
  				{
  					_position += count;
  					return - count;
  				}
  			}
  			for(i=0;i<count;i++)
  			{
  				int c = Read();
  				if (c < 0)
  				{
  					break;
  				}
  			}
  			return i;
  		}
  
  		/// <summary>
  		/// Reads a string from the current position.
  		/// </summary>
  		/// <param name="count">The number of characters to read.</param>
  		/// <returns>The read string or null, if an error occurred.</returns>
  		public string ReadString(int count)
  		{
  			int first = (int)Position;
  			Seek(count);
  
gt: 			int last = (int)Position;