public static MemoryStreamAdapter GetMemoryStreamAdapter(MemoryStream memoryStream) { MemoryStreamAdapter adapter = new MemoryStreamAdapter(); // If the MemoryStream's inner buffer is visible, mark it as such in the proxy object. // We'll also try to avoid the copy of the MemoryStream's inner buffer, but we can // only do this if there's no leading or trailing data surrounding the real to-be-serialized // segment. if (memoryStream.TryGetBuffer(out ArraySegment <byte> innerBuffer)) { adapter.Exposable = true; if (innerBuffer.Count == innerBuffer.Array !.Length) { adapter.Buffer = innerBuffer.Array; } } adapter.Buffer ??= memoryStream.ToArray(); // couldn't get the inner buffer; clone it now // Copy additional information to the proxy object adapter.Length = checked ((int)memoryStream.Length); adapter.Capacity = memoryStream.Capacity; adapter.Position = checked ((int)memoryStream.Position); adapter.Writable = memoryStream.CanWrite; adapter.Origin = 0; // Length, Capacity, and Position are already offset appropriately // Properties below are needed for Full Framework back-compat. adapter.Expandable = false; // we have no way of knowing this, so default it to false adapter.IsOpen = true; // we know this is true because the earlier prop accessors didn't throw return(adapter); }
public static MemoryStream GetMemoryStream(MemoryStreamAdapter value) { // The input may be coming from an untrusted payload, so we perform a few extra // checks. We'll slice the buffer ourselves to validate that origin and length are // accurate, creating a new buffer that doesn't have any leading or trailing data. // The AsSpan method performs argument validation on our behalf. We'll also validate // that the desired Position is not beyond the end of the buffer, otherwise subsequent // accesses to the buffer may cause unintended allocations. Some properties (Capacity, // IsOpen, etc.) are ignored since we allow the MemoryStream ctor to set them itself. byte[] buffer = value.Buffer !; // we don't expect this to be null, but if it is we'll throw NRE below Span <byte> slicedBuffer = value.Buffer.AsSpan(value.Origin, value.Length - value.Origin); if (slicedBuffer.Length < buffer.Length) { buffer = slicedBuffer.ToArray(); // trim leading and trailing data } MemoryStream memoryStream = new MemoryStream( buffer: buffer, index: 0, count: buffer.Length, writable: value.Writable, publiclyVisible: value.Exposable); int desiredPosition = value.Position - value.Origin; if (desiredPosition < 0 || desiredPosition > memoryStream.Length) { throw new InvalidOperationException(); } memoryStream.Position = desiredPosition; return(memoryStream); }
private static object ResolveAdapterType(object obj, ClassDataContract classContract) { Type type = obj.GetType(); if (type == Globals.TypeOfDateTimeOffset) { obj = DateTimeOffsetAdapter.GetDateTimeOffsetAdapter((DateTimeOffset)obj); } else if (type == Globals.TypeOfMemoryStream) { obj = MemoryStreamAdapter.GetMemoryStreamAdapter((MemoryStream)obj); } return(obj); }
private static object ResolveAdapterType(object obj, ClassDataContract classContract) { Type type = obj.GetType(); if (type == Globals.TypeOfDateTimeOffset) { obj = DateTimeOffsetAdapter.GetDateTimeOffsetAdapter((DateTimeOffset)obj); } else if (type == Globals.TypeOfMemoryStream) { obj = MemoryStreamAdapter.GetMemoryStreamAdapter((MemoryStream)obj); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePair) { obj = classContract.KeyValuePairAdapterConstructorInfo !.Invoke(new object[] { obj }); } return(obj); }