PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/WorldView/Utilities/BackwardsBinaryReader.cs

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