Reader.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System;
  2. using System.Collections;
  3. using System.Text;
  4. namespace XGame.Framework.Serialization
  5. {
  6. public class Reader : IReader
  7. {
  8. private byte[] _buffer;
  9. private int _offset;
  10. public Reader(byte[] buffer)
  11. {
  12. _buffer = buffer;
  13. _offset = 0;
  14. }
  15. public bool ReadBool()
  16. {
  17. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadBool: Out of bound of byte array.");
  18. return _buffer[_offset++] != 0;
  19. }
  20. public sbyte ReadSbyte()
  21. {
  22. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadSbyte: Out of bound of byte array.");
  23. return (sbyte)_buffer[_offset++];
  24. }
  25. public byte ReadByte()
  26. {
  27. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadByte: Out of bound of byte array.");
  28. return _buffer[_offset++];
  29. }
  30. public short ReadShort()
  31. {
  32. Assert.IsTrue(_offset + 2 <= _buffer.Length, $"Reader::ReadShort: Out of bound of byte array.");
  33. var value = BitConverter.ToInt16(_buffer, _offset);
  34. _offset += 2;
  35. return value;
  36. }
  37. public ushort ReadUShort()
  38. {
  39. Assert.IsTrue(_offset + 2 <= _buffer.Length, $"Reader::ReadShort: Out of bound of byte array.");
  40. var value = BitConverter.ToUInt16(_buffer, _offset);
  41. _offset += 2;
  42. return value;
  43. }
  44. public int ReadInt()
  45. {
  46. Assert.IsTrue(_offset + 4 <= _buffer.Length, $"Reader::ReadInt: Out of bound of byte array.");
  47. var value = BitConverter.ToInt32(_buffer, _offset);
  48. _offset += 4;
  49. return value;
  50. }
  51. public uint ReadUInt()
  52. {
  53. Assert.IsTrue(_offset + 4 <= _buffer.Length, $"Reader::ReadInt: Out of bound of byte array.");
  54. var value = BitConverter.ToUInt32(_buffer, _offset);
  55. _offset += 4;
  56. return value;
  57. }
  58. public long ReadLong()
  59. {
  60. Assert.IsTrue(_offset + 8 <= _buffer.Length, $"Reader::ReadLong: Out of bound of byte array.");
  61. var value = BitConverter.ToInt64(_buffer, _offset);
  62. _offset += 8;
  63. return value;
  64. }
  65. public ulong ReadULong()
  66. {
  67. Assert.IsTrue(_offset + 8 <= _buffer.Length, $"Reader::ReadLong: Out of bound of byte array.");
  68. var value = BitConverter.ToUInt64(_buffer, _offset);
  69. _offset += 8;
  70. return value;
  71. }
  72. public float ReadFloat()
  73. {
  74. Assert.IsTrue(_offset + 4 <= _buffer.Length, $"Reader::ReadFloat: Out of bound of byte array.");
  75. var value = BitConverter.ToSingle(_buffer, _offset);
  76. _offset += 4;
  77. return value;
  78. }
  79. public double ReadDouble()
  80. {
  81. Assert.IsTrue(_offset + 8 <= _buffer.Length, $"Reader::ReadDouble: Out of bound of byte array.");
  82. var value = BitConverter.ToDouble(_buffer, _offset);
  83. _offset += 8;
  84. return value;
  85. }
  86. public char ReadChar()
  87. {
  88. Assert.IsTrue(_offset + 2 <= _buffer.Length, $"Reader::ReadChar: Out of bound of byte array.");
  89. var value = BitConverter.ToChar(_buffer, _offset);
  90. _offset += 2;
  91. return value;
  92. }
  93. public string ReadString()
  94. {
  95. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadString: Out of bound of byte array.");
  96. var size = ReadInt();
  97. if (size < 0) return null;
  98. if (size == 0) return string.Empty;
  99. Assert.IsTrue(_offset + size <= _buffer.Length, $"Reader::ReadString: Out of bound of byte array.");
  100. var value = Encoding.UTF8.GetString(_buffer, _offset, size);
  101. _offset += size;
  102. return value;
  103. }
  104. public byte[] ReadBytes()
  105. {
  106. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadBytes: Out of bound of byte array.");
  107. var size = ReadInt();
  108. if (size < 0) return null;
  109. Assert.IsTrue(_offset + size <= _buffer.Length, $"Reader::ReadBytes: Out of bound of byte array.");
  110. var blob = new byte[size];
  111. Buffer.BlockCopy(_buffer, _offset, blob, 0, size);
  112. _offset += size;
  113. return blob;
  114. }
  115. public T ReadSerializable<T>() where T : ISerializable, new()
  116. {
  117. return (T)ReadSerializable(typeof(T));
  118. }
  119. public T ReadEnumerable<T>() where T : class, IEnumerable
  120. {
  121. var type = typeof(T);
  122. return ReadEnumerable(type) as T;
  123. }
  124. private object ReadEnumerable(Type type)
  125. {
  126. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadEnumerable: Out of bound of byte array.");
  127. int length = ReadInt();
  128. if (length < 0) return null;
  129. if (type.IsArray) return ReadArray(type, length);
  130. var instance = Activator.CreateInstance(type);
  131. switch (instance)
  132. {
  133. case IList ls:
  134. ReadList(ls, type, length);
  135. break;
  136. case IDictionary dic:
  137. ReadDictionary(dic, type, length);
  138. break;
  139. default:
  140. throw new Exception($"Reader::ReadEnumerable: {type.Name} is unsupported.");
  141. }
  142. return instance;
  143. }
  144. private void ReadDictionary(IDictionary dic, Type type, int length)
  145. {
  146. var genericTypes = type.GetGenericArguments();
  147. Assert.IsTrue(genericTypes.Length == 2, "Reader::ReadDictionary: the count of generic arguments must be 2");
  148. if (genericTypes[0].IsEnum) genericTypes[0] = genericTypes[0].GetEnumUnderlyingType();
  149. if (genericTypes[1].IsEnum) genericTypes[1] = genericTypes[1].GetEnumUnderlyingType();
  150. for (int i = 0; i < length; i++)
  151. {
  152. object key = ReadObject(genericTypes[0]);
  153. object value = ReadObject(genericTypes[1]);
  154. dic.Add(key, value);
  155. }
  156. }
  157. private void ReadList(IList list, Type type, int length)
  158. {
  159. var genericType = type.GetGenericArguments()[0];
  160. if (genericType.IsEnum) genericType = genericType.GetEnumUnderlyingType();
  161. for (int i = 0; i < length; i++)
  162. {
  163. list.Add(ReadObject(genericType));
  164. }
  165. }
  166. private object ReadArray(System.Type type, int length)
  167. {
  168. var elementType = type.GetElementType();
  169. Array array = Array.CreateInstance(elementType, length);
  170. Assert.IsTrue(array.Rank == 1, "Reader::ReadArray: the count of array rank must be 1");
  171. if (elementType.IsEnum) elementType = elementType.GetEnumUnderlyingType();
  172. for (int i = 0; i < length; i++)
  173. {
  174. object value = ReadObject(elementType);
  175. array.SetValue(value, i);
  176. }
  177. return array;
  178. }
  179. private object ReadObject(Type type)
  180. {
  181. if (TypeHelper.Bool == type) return ReadBool();
  182. if (TypeHelper.SByte == type) return ReadSbyte();
  183. if (TypeHelper.Byte == type) return ReadByte();
  184. if (TypeHelper.Short == type) return ReadShort();
  185. if (TypeHelper.UShort == type) return ReadUShort();
  186. if (TypeHelper.Int == type) return ReadInt();
  187. if (TypeHelper.UInt == type) return ReadUInt();
  188. if (TypeHelper.Long == type) return ReadLong();
  189. if (TypeHelper.ULong == type) return ReadULong();
  190. if (TypeHelper.Float == type) return ReadFloat();
  191. if (TypeHelper.Double == type) return ReadDouble();
  192. if (TypeHelper.Char == type) return ReadChar();
  193. if (TypeHelper.String == type) return ReadString();
  194. if (TypeHelper.Bytes == type) return ReadBytes();
  195. if (TypeHelper.IEnumerable.IsAssignableFrom(type)) return ReadEnumerable(type);
  196. if (TypeHelper.ISerializable.IsAssignableFrom(type)) return ReadSerializable(type);
  197. throw new NotSupportedException($"Reader::ReadEnumerable: {type.Name} is unsupported.");
  198. }
  199. private object ReadSerializable(Type type)
  200. {
  201. Assert.IsTrue(_offset < _buffer.Length, $"Reader::ReadSerializable: Out of bound of byte array.");
  202. var isNull = ReadBool();
  203. if (isNull) return null;
  204. var value = Activator.CreateInstance(type);
  205. (value as ISerializable).Deserialize(this);
  206. return value;
  207. }
  208. }
  209. }