PageRenderTime 528ms CodeModel.GetById 241ms app.highlight 12ms RepoModel.GetById 273ms app.codeStats 0ms

/WorldView/Utilities/BackwardsBinaryReader.cs

#
C# | 254 lines | 177 code | 56 blank | 21 comment | 41 complexity | 9a816083e022927139903b2195cdd3c2 MD5 | raw file
  1using System;
  2using System.IO;
  3
  4namespace MoreTerra.Utilities
  5{
  6	class BackwardsBinaryReader : BinaryReader
  7	{
  8		private long oldPosition;
  9		Stream inStream;
 10
 11		#region Constructors
 12		public BackwardsBinaryReader(Stream input) : base(input)
 13		{
 14			oldPosition = input.Position;
 15			inStream = input;
 16		}
 17		#endregion
 18
 19		/// <summary>
 20		/// Attempts to read in a string of a specific size.
 21		/// Only handles up to 16k byte strings.
 22		/// Only checks for a # that correctly matches with the size of what would be the string afterwords.
 23		/// </summary>
 24		/// <param name="readSize">Used when you know the size of the string already.  Runs faster.
 25		/// <returns>The string or null if one was not found.</returns>
 26		public String ReadSetSizeBackwardsString(Int32 readSize)
 27		{
 28			Int32 peekSpot;
 29			String retStr = null;
 30			long localOldPosition = inStream.Position;
 31			long newPosition;
 32
 33			// There's not enough in the stream to cover the size we requested or we asked for a 0 length.
 34			if (readSize == 0 || readSize > inStream.Length || readSize > 0x3FFF)
 35				return null;
 36
 37			inStream.Seek(-(readSize + 1), SeekOrigin.Current);
 38
 39			if (readSize > 127)
 40			{
 41				newPosition = oldPosition - (readSize + 2);
 42			}
 43			else
 44			{
 45				peekSpot = base.PeekChar();
 46
 47				// We have a match, let's give this a shot.
 48				if (peekSpot == readSize)
 49				{
 50					retStr = base.ReadString();
 51					newPosition = localOldPosition - (readSize + 1);
 52				}
 53				else
 54				{
 55					inStream.Seek(localOldPosition, SeekOrigin.Begin);
 56					return null;
 57				}
 58			}
 59
 60			inStream.Seek(newPosition, SeekOrigin.Begin);
 61
 62			return retStr;
 63		}
 64
 65		/// <summary>
 66		/// Reads a string in from the end.
 67		/// Only handles 127 bytes unless you specifically tell it to go further.  Not recommended
 68		/// to set maxSize to high values unless you absolutely believe there will be that big of string.
 69		/// Does no processing on the string to see if it is all in printable characters.
 70		/// Only checks for a # that correctly matches with the size of what would be the string afterwords.
 71		/// </summary>
 72		/// <param name="allowEmpty">Whether an empty string is an ok thing to return.</param>
 73		/// <param name="maxSize">The highest size string we can attempt to read.</param>
 74		/// <returns>The string or null if one was not found.</returns>
 75		public String ReadBackwardsString(Boolean allowEmpty = false, Int32 maxSize = 127, Int32 verificationByte = -1)
 76		{
 77			Int32 peekSpot;
 78			Int32 readEnd = 128;
 79			String retStr = null;
 80			long localOldPosition = inStream.Position;
 81			Int32 i = 0;
 82			Byte lowByte;
 83
 84			if (maxSize > 0x3FFF)
 85				return null;
 86
 87			if (localOldPosition < maxSize)
 88				maxSize = (int)localOldPosition - 1;
 89
 90			if (maxSize < readEnd)
 91				readEnd = maxSize + 1;
 92
 93			inStream.Seek(-1, SeekOrigin.Current);
 94
 95			if (allowEmpty == true)
 96			{
 97				peekSpot = base.PeekChar();
 98
 99				if (peekSpot == 0)
100					return "";
101			}
102
103			for (i = 1; i < readEnd; i++)
104			{
105				inStream.Seek(-1, SeekOrigin.Current);
106				peekSpot = base.PeekChar();
107
108				if (peekSpot == 0)
109					return null;
110
111				if (peekSpot == i)
112				{
113					peekSpot = PeekBackwardsByte();
114
115					if ((verificationByte == -1) || (peekSpot == verificationByte))
116					{
117						retStr = base.ReadString();
118						break;
119					}
120				}
121
122			}
123
124			// We didn't find it in the first 127.  Let's go the rest of the way.
125			if (maxSize > 128 && i == readEnd)
126			{
127				lowByte = ReadBackwardsByte();
128				readEnd = maxSize;
129
130				for (i = 128; i < readEnd; i++)
131				{
132					peekSpot = lowByte * 128;
133
134					lowByte = ReadBackwardsByte();
135
136					// If the low byte doesn't have it's high bit set we know it's not a two byte UTF7 number.
137					if (lowByte < 128)
138						continue;
139
140					peekSpot += (lowByte - 128);
141
142					if (peekSpot == i)
143					{
144						retStr = base.ReadString();
145						break;
146					}
147				}
148			}
149
150			if (i == readEnd)
151			{
152				inStream.Seek(localOldPosition, SeekOrigin.Begin);
153				return null;
154			}
155
156			inStream.Seek(localOldPosition - (i + ((i < 128) ? 1 : 2)), SeekOrigin.Begin);
157
158			return retStr;
159		}
160
161		public Boolean ReadBackwardsBoolean()
162		{
163			if (inStream.Position < sizeof(Boolean))
164				throw new EndOfStreamException();
165
166			inStream.Seek(-1, SeekOrigin.Current);
167
168			if (base.PeekChar() == 0)
169				return false;
170			else
171				return true;
172		}
173
174		public Byte ReadBackwardsByte()
175		{
176			Int32 retByte;
177
178			if (inStream.Position < sizeof(Boolean))
179				throw new EndOfStreamException();
180
181			inStream.Seek(-1, SeekOrigin.Current);
182			retByte = base.ReadByte();
183			inStream.Seek(-1, SeekOrigin.Current);
184
185			return (Byte)retByte;
186		}
187
188		public Byte PeekBackwardsByte()
189		{
190
191			if (inStream.Position < sizeof(Boolean))
192				throw new EndOfStreamException();
193
194			inStream.Seek(-1, SeekOrigin.Current);
195			return base.ReadByte();
196		}
197
198		public Single ReadBackwardsSingle()
199		{
200			Single retVal;
201
202			if (inStream.Position < sizeof(Single))
203				throw new EndOfStreamException();
204
205			inStream.Seek(-sizeof(Single), SeekOrigin.Current);
206			retVal = base.ReadSingle();
207			inStream.Seek(-sizeof(Single), SeekOrigin.Current);
208
209			return retVal;
210		}
211
212		public Double ReadBackwardsDouble()
213		{
214			Double retVal;
215
216			if (inStream.Position < sizeof(Double))
217				throw new EndOfStreamException();
218
219			inStream.Seek(-sizeof(Double), SeekOrigin.Current);
220			retVal = base.ReadDouble();
221			inStream.Seek(-sizeof(Double), SeekOrigin.Current);
222
223			return retVal;
224		}
225
226		public Int16 ReadBackwardsInt16()
227		{
228			Int16 retVal;
229
230			if (inStream.Position < sizeof(Int16))
231				throw new EndOfStreamException();
232
233			inStream.Seek(-sizeof(Int16), SeekOrigin.Current);
234			retVal = base.ReadInt16();
235			inStream.Seek(-sizeof(Int16), SeekOrigin.Current);
236
237			return retVal;
238		}
239
240		public Int32 ReadBackwardsInt32()
241		{
242			Int32 retVal;
243
244			if (inStream.Position < sizeof(Int32))
245				throw new EndOfStreamException();
246
247			inStream.Seek(-sizeof(Int32), SeekOrigin.Current);
248			retVal = base.ReadInt32();
249			inStream.Seek(-sizeof(Int32), SeekOrigin.Current);
250
251			return retVal;
252		}
253	}
254}