using System; using System.Collections; using System.Text; namespace XGame.Framework.Serialization { public class Writer : IWriter { private const int DefaultLength = 2048; private byte[] _buffer; private int _size; public Writer() { _buffer = new byte[DefaultLength]; _size = 0; } public void Write(bool value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(sbyte value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(byte value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(short value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(ushort value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(int value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(uint value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(long value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(ulong value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(float value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(double value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(char value) { var bytes = BitConverter.GetBytes(value); var length = bytes.Length; if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(string value) { if (value == null) { Write(-1); return; } if (value == string.Empty) { Write(0); return; } var bytes = Encoding.UTF8.GetBytes(value); var length = bytes.Length; Write(length); if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(bytes, 0, _buffer, _size, length); _size += length; } public void Write(byte[] value) { if (value == null) { Write(-1); return; } ; var length = value.Length; Write(length); if (_size + length >= _buffer.Length) AllocateMore(); Buffer.BlockCopy(value, 0, _buffer, _size, length); _size += length; } public void Write(ISerializable data) { bool isNull = data == null; Write(isNull); if (isNull) return; data.Serialize(this); } public void Write(IEnumerable enumerable) { if (null == enumerable) { Write(-1); return; } Assert.IsTrue(!(enumerable is Array array) || array.Rank == 1, ""); switch (enumerable) { case IDictionary dic: WriteDictionary(dic); break; case IList ls: // Array & List WriteList(ls); break; default: throw new NotSupportedException($"不支持序列化 {enumerable.GetType()} 类型的字段"); } } public byte[] Finish() { var resBuffer = new byte[_size]; Buffer.BlockCopy(_buffer, 0, resBuffer, 0, _size); _buffer = null; _size = 0; return resBuffer; } private void WriteList(IList list) { Write(list.Count); var e = list.GetEnumerator(); while (e.MoveNext()) { WriteObject(e.Current); } } private void WriteDictionary(IDictionary dic) { Write(dic.Count); var e = dic.GetEnumerator(); while (e.MoveNext()) { WriteObject(e.Key); WriteObject(e.Value); } } private void WriteObject(object data) { if (null == data) { var isNull = true; Write(isNull); return; } if (data.GetType().IsEnum) { var type = data.GetType().GetEnumUnderlyingType(); data = Convert.ChangeType(data, type); } switch (data) { case bool value: Write(value); break; case byte value: Write(value); break; case sbyte value: Write(value); break; case short value: Write(value); break; case ushort value: Write(value); break; case int value: Write(value); break; case uint value: Write(value); break; case long value: Write(value); break; case ulong value: Write(value); break; case float value: Write(value); break; case double value: Write(value); break; case char value: Write(value); break; case string value: Write(value); break; case byte[] value: Write(value); break; case IEnumerable value: Write(value); break; case ISerializable value: Write(value); break; default: throw new NotSupportedException($"Reader::ReadEnumerable: {data.GetType()} is unsupported."); } return; } private void AllocateMore(int length = 0) { var size = _buffer.Length << (length / _buffer.Length / 2 + 1); var array = new byte[size]; if (_buffer != null && _size > 0) { _buffer.CopyTo(array, 0); } _buffer = array; } } }