private async Task <object> ReadEnumerable(Type type, Stream stream) { var elementType = TypeUtils.GetEnumerableItemType(type); var supportedElementType = true; if (elementType != null) { supportedElementType = TypeUtils.IsSupportedElementType(elementType); } if (elementType != null && supportedElementType) { var isNull = await ReadNullFlag(stream).ConfigureAwait(false); if (!isNull) { var result = TypeUtils.CreateList(elementType); var count = (int) await ReadPrimitive(typeof(int), stream).ConfigureAwait(false); if (count > 0) { TraceUtils.WriteLineFormatted("Begin reading enumerable"); for (var i = 0; i < count; i++) { var item = await ReadPlainObject(elementType, stream).ConfigureAwait(false); result.Add(item); TraceUtils.WriteLineFormatted("Read #{0}/{1} of enumerable", i + 1, count); } TraceUtils.WriteLineFormatted("End reading enumerable"); } else { TraceUtils.WriteLineFormatted("Enumerable is empty"); } if (!type.IsArray) { return(result); } return(ConvertionUtils.ConvertListToArray(result)); } } else if (elementType != null) { TraceUtils.WriteLineFormatted("Unable to read Enumerable of type \"{0}\": Unsupported element type \"{1}\"", type, elementType); } else { TraceUtils.WriteLineFormatted("Unable to read Enumerable of type \"{0}\": Unsupported", type); } return(null); }
private Task WriteBytes(byte[] bytes, int length, Stream stream) { Debug.Assert(length <= bytes.Length); TraceUtils.WriteLineFormatted("Written {0} bytes", length); return(stream.WriteAsync(bytes, 0, length)); }
public async Task <object> Deserialize(Type objectType, Stream stream) { var targetTypeFullName = objectType.AssemblyQualifiedName; TraceUtils.WriteLineFormatted("Read object type..."); var typeFullNameBytes = (byte[])await _reader.ReadObject(typeof(byte[]), stream).ConfigureAwait(false); byte[] targetTypeFullNameBytes; using (var md5 = MD5.Create()) { // ReSharper disable once AssignNullToNotNullAttribute targetTypeFullNameBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(targetTypeFullName)); } if (targetTypeFullNameBytes.SequenceEqual(typeFullNameBytes)) { TraceUtils.WriteLineFormatted("Read object..."); return(await _reader.ReadObject(objectType, stream)); } var targetTypeBinaryString = string.Join("", targetTypeFullNameBytes.Select(x => Convert.ToString(x, 16).PadLeft(2, '0'))); var typeBinaryString = string.Join("", typeFullNameBytes.Select(x => Convert.ToString(x, 16).PadLeft(2, '0'))); throw new ArgumentException($"Unable to deserialize object: Wrong type hash \"{typeBinaryString}\" expected \"{targetTypeBinaryString}\""); }
public async Task WriteObject(object obj, Stream stream) { Debug.Assert(obj != null); Debug.Assert(stream != null); TraceUtils.WriteLineFormatted("*** BEGIN WRITING ***"); await WriteObjectInternal(obj, stream).ConfigureAwait(false); TraceUtils.WriteLineFormatted("*** END WRITING ***"); }
public async Task <object> ReadObject(Type type, Stream stream) { Debug.Assert(stream != null); TraceUtils.WriteLineFormatted("*** BEGIN READING ***"); try { return(await ReadObjectInternal(type, stream).ConfigureAwait(false)); } finally { TraceUtils.WriteLineFormatted("*** END READING ***"); } }
public async Task Serialize(object obj, Stream stream) { var typeFullName = obj.GetType().AssemblyQualifiedName; byte[] typeFullNameBytes; using (var md5 = MD5.Create()) { // ReSharper disable once AssignNullToNotNullAttribute typeFullNameBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(typeFullName)); } TraceUtils.WriteLineFormatted("Write object type..."); await _writer.WriteObject(typeFullNameBytes, stream).ConfigureAwait(false); TraceUtils.WriteLineFormatted("Write object..."); await _writer.WriteObject(obj, stream).ConfigureAwait(false); }
private async Task ReadStream(Stream stream, byte[] dst, int length) { TraceUtils.WriteLineFormatted("Read from stream {0}", length); int readBytes = 0, lastRead; do { lastRead = await stream.ReadAsync(dst, readBytes, length - readBytes); readBytes += lastRead; } while(readBytes < length && lastRead != 0); if (readBytes != length) { throw new SerializationException($"Unable to read data from stream. Except {length} but found only {readBytes} bytes"); } }
private async Task WriteCompositeObject(object obj, Type type, Stream stream) { TraceUtils.WriteLineFormatted("Writing composite object of type: {0}", type.FullName); var props = obj.GetProperties(); if (props.Any()) { foreach (var prop in props) { var value = prop.GetValue(obj); TraceUtils.WriteLineFormatted("Writing sub-object of property {0} with type: {1}", prop.Name, prop.PropertyType.FullName); await WritePlainObject(value, prop.PropertyType, stream).ConfigureAwait(false); } } else { TraceUtils.WriteLineFormatted("Composite object hasn't any read\\write properties"); } }
private async Task <object> ReadObjectInternal(Type type, Stream stream) { if (type != typeof(object)) { object resultObject; var objectType = TypeUtils.DetermineObjectType(type); if (objectType == ObjectType.Class || objectType == ObjectType.Struct) { resultObject = await ReadCompositeObject(type, stream); } else { TraceUtils.WriteLineFormatted("Reading plain object of type: {0}", type.FullName); resultObject = await ReadPlainObject(type, stream); } return(resultObject); } TraceUtils.WriteLineFormatted("Unable to read object of type \"{0}\": Unsupported", type.FullName); return(null); }
private async Task WriteObjectInternal(object obj, Stream stream) { Debug.Assert(obj != null); var type = obj.GetType(); if (type != typeof(object)) { var objectType = TypeUtils.DetermineObjectType(type); if (objectType == ObjectType.Class || objectType == ObjectType.Struct) { await WriteCompositeObject(obj, type, stream).ConfigureAwait(false); } else { TraceUtils.WriteLineFormatted("Writing plain object of type: {0}", type.FullName); await WritePlainObject(obj, type, stream).ConfigureAwait(false); } } else { TraceUtils.WriteLineFormatted("Unable to write object of type \"{0}\": Unsupported", type.FullName); } }
private async Task <object> ReadCompositeObject(Type type, Stream stream) { TraceUtils.WriteLineFormatted("Reading composite object of type: {0}", type.FullName); var resultingObject = Activator.CreateInstance(type); var props = resultingObject.GetProperties(); if (props.Any()) { foreach (var prop in props) { TraceUtils.WriteLineFormatted("Reading sub-object of property {0} with type: {1}", prop.Name, prop.PropertyType.FullName); var value = await ReadPlainObject(prop.PropertyType, stream).ConfigureAwait(false); prop.SetValue(resultingObject, value); } } else { TraceUtils.WriteLineFormatted("Composite object hasn't any read\\write properties"); } return(resultingObject); }
private async Task WritePlainObject(object value, Type type, Stream stream) { Debug.Assert(type != null); Debug.Assert(stream != null); if (value != null) { var objectType = TypeUtils.DetermineObjectType(type); switch (objectType) { case ObjectType.Primitive: await WritePrimitive(value, stream).ConfigureAwait(false); break; case ObjectType.Nullable: await WriteNullableValueType(value, stream).ConfigureAwait(false); break; case ObjectType.String: await WriteString((string)value, stream).ConfigureAwait(false); break; case ObjectType.DateTime: await WriteDateTime((DateTime)value, stream).ConfigureAwait(false); break; case ObjectType.Class: await WriteClass(value, stream).ConfigureAwait(false); break; case ObjectType.Struct: await WriteStruct(value, stream).ConfigureAwait(false); break; case ObjectType.Enumerable: if (value is byte[] bytes) { await WriteByteArray(bytes, stream); } else { await WriteEnumerable(value, type, stream).ConfigureAwait(false); } break; case ObjectType.Enum: await WriteEnum(value, stream).ConfigureAwait(false); break; case ObjectType.Unsupported: TraceUtils.WriteLineFormatted("Unsupported value of type: \"{0}\"", type.FullName); break; } } else { await WriteNullFlag(true, stream).ConfigureAwait(false); } }
private async Task WriteEnumerable(object value, Type type, Stream stream) { var elementType = TypeUtils.GetEnumerableItemType(type); var supportedElementType = true; if (elementType != null) { supportedElementType = TypeUtils.IsSupportedElementType(elementType); } if (elementType != null && supportedElementType) { var enumerable = (IEnumerable)value; // ReSharper disable PossibleMultipleEnumeration var supportedEnumerable = enumerable.Cast <object>().All(item => item == null || item.GetType() == elementType); if (supportedEnumerable) { TraceUtils.WriteLineFormatted("Begin writing enumerable"); await WriteNullFlag(false, stream).ConfigureAwait(false); using (var internalStream = new MemoryStream()) { var count = 0; foreach (var item in enumerable) { await WritePlainObject(item, elementType, internalStream).ConfigureAwait(false); ++count; } await WriteBytes(TemporaryBuffer, ConvertionUtils.Convert(count, TemporaryBuffer), stream).ConfigureAwait(false); if (count > 0) { internalStream.Seek(0, SeekOrigin.Begin); await internalStream.CopyToAsync(stream).ConfigureAwait(false); } } // ReSharper restore PossibleMultipleEnumeration TraceUtils.WriteLineFormatted("End writing enumerable"); } else { await WriteNullFlag(true, stream).ConfigureAwait(false); TraceUtils.WriteLineFormatted("Unable to write Enumerable of type \"{0}\": All elements must be of one type", type); } } else if (elementType != null) { TraceUtils.WriteLineFormatted("Unable to write Enumerable of type \"{0}\": Unsupported element type \"{1}\"", type, elementType); } else { TraceUtils.WriteLineFormatted("Unable to write Enumerable of type \"{0}\": Unsupported", type); } }
private async Task <object> ReadPlainObject(Type type, Stream stream) { Debug.Assert(type != null); Debug.Assert(stream != null); object result = null; var objectType = TypeUtils.DetermineObjectType(type); switch (objectType) { case ObjectType.Primitive: result = await ReadPrimitive(type, stream); break; case ObjectType.Nullable: result = await ReadNullable(type, stream); break; case ObjectType.String: result = await ReadString(stream); break; case ObjectType.DateTime: result = await ReadDateTime(stream); break; case ObjectType.Class: result = await ReadClass(type, stream); break; case ObjectType.Struct: result = await ReadStruct(type, stream); break; case ObjectType.Enumerable: if (type.IsEquivalentTo(typeof(byte[]))) { result = await ReadByteArray(stream); } else { result = await ReadEnumerable(type, stream); } break; case ObjectType.Enum: result = await ReadEnum(type, stream); break; case ObjectType.Unsupported: TraceUtils.WriteLineFormatted("Unsupported value of type: \"{0}\"", type.FullName); result = Task.FromResult <object>(null); break; } return(result); }