PsdBinaryReader.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Photoshop PSD FileType Plugin for Paint.NET
  4. // http://psdplugin.codeplex.com/
  5. //
  6. // This software is provided under the MIT License:
  7. // Copyright (c) 2006-2007 Frank Blumenberg
  8. // Copyright (c) 2010-2013 Tao Yue
  9. //
  10. // Portions of this file are provided under the BSD 3-clause License:
  11. // Copyright (c) 2006, Jonas Beckeman
  12. //
  13. // See LICENSE.txt for complete licensing and attribution information.
  14. //
  15. /////////////////////////////////////////////////////////////////////////////////
  16. using System;
  17. using PDNWrapper;
  18. using System.IO;
  19. using System.Text;
  20. namespace PhotoshopFile
  21. {
  22. /// <summary>
  23. /// Reads PSD data types in big-endian byte order.
  24. /// </summary>
  25. internal class PsdBinaryReader : IDisposable
  26. {
  27. private BinaryReader reader;
  28. private Encoding encoding;
  29. public Stream BaseStream
  30. {
  31. get { return reader.BaseStream; }
  32. }
  33. public PsdBinaryReader(Stream stream, PsdBinaryReader reader)
  34. : this(stream, reader.encoding)
  35. {
  36. }
  37. public PsdBinaryReader(Stream stream, Encoding encoding)
  38. {
  39. this.encoding = encoding;
  40. // ReadPascalString and ReadUnicodeString handle encoding explicitly.
  41. // BinaryReader.ReadString() is never called, so it is constructed with
  42. // ASCII encoding to make accidental usage obvious.
  43. reader = new BinaryReader(stream, Encoding.ASCII);
  44. }
  45. public byte ReadByte()
  46. {
  47. return reader.ReadByte();
  48. }
  49. public byte[] ReadBytes(int count)
  50. {
  51. return reader.ReadBytes(count);
  52. }
  53. public bool ReadBoolean()
  54. {
  55. return reader.ReadBoolean();
  56. }
  57. public Int16 ReadInt16()
  58. {
  59. var val = reader.ReadInt16();
  60. byte[] b = BitConverter.GetBytes(val);
  61. {
  62. Util.SwapBytes(b, 0, 2);
  63. }
  64. val = BitConverter.ToInt16(b, 0);
  65. return val;
  66. }
  67. public Int32 ReadInt32()
  68. {
  69. var val = reader.ReadInt32();
  70. byte[] b = BitConverter.GetBytes(val);
  71. {
  72. Util.SwapBytes(b, 0, 4);
  73. }
  74. val = BitConverter.ToInt32(b, 0);
  75. return val;
  76. }
  77. public Int64 ReadInt64()
  78. {
  79. var val = reader.ReadInt64();
  80. var b = BitConverter.GetBytes(val);
  81. {
  82. Util.SwapBytes(b, 0, 8);
  83. }
  84. val = BitConverter.ToInt64(b, 0);
  85. return val;
  86. }
  87. public UInt16 ReadUInt16()
  88. {
  89. var val = reader.ReadUInt16();
  90. var b = BitConverter.GetBytes(val);
  91. {
  92. Util.SwapBytes(b, 0, 2);
  93. }
  94. val = BitConverter.ToUInt16(b, 0);
  95. return val;
  96. }
  97. public UInt32 ReadUInt32()
  98. {
  99. var val = reader.ReadUInt32();
  100. var b = BitConverter.GetBytes(val);
  101. {
  102. Util.SwapBytes(b, 0, 4);
  103. }
  104. val = BitConverter.ToUInt32(b, 0);
  105. return val;
  106. }
  107. public UInt64 ReadUInt64()
  108. {
  109. var val = reader.ReadUInt64();
  110. var b = BitConverter.GetBytes(val);
  111. {
  112. Util.SwapBytes(b, 0, 8);
  113. }
  114. val = BitConverter.ToUInt64(b, 0);
  115. return val;
  116. }
  117. //////////////////////////////////////////////////////////////////
  118. /// <summary>
  119. /// Read padding to get to the byte multiple for the block.
  120. /// </summary>
  121. /// <param name="startPosition">Starting position of the padded block.</param>
  122. /// <param name="padMultiple">Byte multiple that the block is padded to.</param>
  123. public void ReadPadding(long startPosition, int padMultiple)
  124. {
  125. // Pad to specified byte multiple
  126. var totalLength = reader.BaseStream.Position - startPosition;
  127. var padBytes = Util.GetPadding((int)totalLength, padMultiple);
  128. ReadBytes(padBytes);
  129. }
  130. public Rectangle ReadRectangle()
  131. {
  132. var rect = new Rectangle();
  133. rect.Y = ReadInt32();
  134. rect.X = ReadInt32();
  135. rect.Height = ReadInt32() - rect.Y;
  136. rect.Width = ReadInt32() - rect.X;
  137. return rect;
  138. }
  139. /// <summary>
  140. /// Read a fixed-length ASCII string.
  141. /// </summary>
  142. public string ReadAsciiChars(int count)
  143. {
  144. var bytes = reader.ReadBytes(count);
  145. var s = Encoding.ASCII.GetString(bytes);
  146. return s;
  147. }
  148. /// <summary>
  149. /// Read a Pascal string using the specified encoding.
  150. /// </summary>
  151. /// <param name="padMultiple">Byte multiple that the Pascal string is padded to.</param>
  152. public string ReadPascalString(int padMultiple)
  153. {
  154. var startPosition = reader.BaseStream.Position;
  155. byte stringLength = ReadByte();
  156. var bytes = ReadBytes(stringLength);
  157. ReadPadding(startPosition, padMultiple);
  158. // Default decoder uses best-fit fallback, so it will not throw any
  159. // exceptions if unknown characters are encountered.
  160. var str = encoding.GetString(bytes);
  161. return str;
  162. }
  163. public string ReadUnicodeString()
  164. {
  165. var numChars = ReadInt32();
  166. var length = 2 * numChars;
  167. var data = ReadBytes(length);
  168. var str = Encoding.BigEndianUnicode.GetString(data, 0, length);
  169. return str;
  170. }
  171. //////////////////////////////////////////////////////////////////
  172. #region IDisposable
  173. private bool disposed = false;
  174. public void Dispose()
  175. {
  176. Dispose(true);
  177. GC.SuppressFinalize(this);
  178. }
  179. protected virtual void Dispose(bool disposing)
  180. {
  181. // Check to see if Dispose has already been called.
  182. if (disposed)
  183. return;
  184. if (disposing)
  185. {
  186. if (reader != null)
  187. {
  188. // BinaryReader.Dispose() is protected.
  189. reader.Close();
  190. reader = null;
  191. }
  192. }
  193. disposed = true;
  194. }
  195. #endregion
  196. }
  197. }