/// <inheritdoc /> public override void ReverseProcessDataStream(System.IO.Stream inStream, System.IO.Stream outStream, Dictionary <string, string> options, out long writtenBytes) { if (options == null) { throw new ArgumentNullException("options"); } else if (!options.ContainsKey(PasswordOption)) { throw new ArgumentException("Options must contain encryption key", "options"); } if (outStream == null) { throw new ArgumentNullException("outStream"); } Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(options[PasswordOption], SALT); using (var transform = encrypter.CreateDecryptor(pdb.GetBytes(32), pdb.GetBytes(16))) { using (MemoryStream internalStream = new MemoryStream()) { using (CryptoStream csDecrypt = new CryptoStream(internalStream, transform, CryptoStreamMode.Write)) { AsyncStreamCopier.CopyStreamTo(inStream, csDecrypt); inStream.Flush(); csDecrypt.FlushFinalBlock(); internalStream.Seek(0, 0); AsyncStreamCopier.CopyStreamTo(internalStream, outStream); writtenBytes = outStream.Position; } } } }
/// <summary> /// Copy contents of source into destination /// </summary> /// <param name="source"></param> /// <param name="destination"></param> public static void CopyStreamTo(Stream source, Stream destination) { var completedEvent = new ManualResetEvent(false); // copy as usual but listen for completion var copier = new AsyncStreamCopier(); copier.Completed += (s, e) => completedEvent.Set(); copier.Start(source, destination); completedEvent.WaitOne(); }
/// <summary> /// Deserializes data object held as compressed bytes in receivedObjectBytes using compressor if desired type is an array of primitives /// </summary> /// <param name="inputStream">Byte array containing serialized and compressed object</param> /// <param name="dataProcessors">Compression provider to use</param> /// <param name="objType">The <see cref="System.Type"/> of the <see cref="object"/> to be returned</param> /// <param name="options">Options to be used during deserialization and processing of data</param> /// <returns>The deserialized object if it is an array, otherwise null</returns> public static unsafe object DeserialiseArrayObject(MemoryStream inputStream, Type objType, List <DataProcessor> dataProcessors, Dictionary <string, string> options) { if (objType.IsArray) { var elementType = objType.GetElementType(); //No need to do anything for a byte array if (elementType == typeof(byte) && (dataProcessors == null || dataProcessors.Count == 0)) { try { return((object)inputStream.GetBuffer()); } catch (UnauthorizedAccessException) { return((object)inputStream.ToArray()); } } if (elementType.IsPrimitive) { int numElements; if (dataProcessors == null || dataProcessors.Count == 0) { numElements = (int)(inputStream.Length / Marshal.SizeOf(elementType)); } else { byte[] temp = new byte[sizeof(int)]; inputStream.Seek(inputStream.Length - sizeof(int), SeekOrigin.Begin); inputStream.Read(temp, 0, sizeof(int)); numElements = (int)(BitConverter.ToUInt32(temp, 0)); } Array resultArray = Array.CreateInstance(elementType, numElements); GCHandle arrayHandle = GCHandle.Alloc(resultArray, GCHandleType.Pinned); try { IntPtr safePtr = Marshal.UnsafeAddrOfPinnedArrayElement(resultArray, 0); long writtenBytes = 0; using (System.IO.UnmanagedMemoryStream finalOutputStream = new System.IO.UnmanagedMemoryStream((byte *)safePtr, resultArray.Length * Marshal.SizeOf(elementType), resultArray.Length * Marshal.SizeOf(elementType), System.IO.FileAccess.ReadWrite)) { MemoryStream inputBytesStream = null; try { //We hope that the buffer is publicly accessible as otherwise it defeats the point of having a special serializer for arrays inputBytesStream = new MemoryStream(inputStream.GetBuffer(), 0, (int)(inputStream.Length - ((dataProcessors == null || dataProcessors.Count == 0) ? 0 : sizeof(int)))); } catch (UnauthorizedAccessException) { inputBytesStream = new MemoryStream(inputStream.ToArray(), 0, (int)(inputStream.Length - ((dataProcessors == null || dataProcessors.Count == 0) ? 0 : sizeof(int)))); } using (inputBytesStream) { if (dataProcessors != null && dataProcessors.Count > 1) { using (MemoryStream tempStream1 = new MemoryStream()) { dataProcessors[dataProcessors.Count - 1].ReverseProcessDataStream(inputBytesStream, tempStream1, options, out writtenBytes); if (dataProcessors.Count > 2) { using (MemoryStream tempStream2 = new MemoryStream()) { for (int i = dataProcessors.Count - 2; i > 0; i -= 2) { tempStream1.Seek(0, 0); tempStream1.SetLength(writtenBytes); tempStream2.Seek(0, 0); dataProcessors[i].ReverseProcessDataStream(tempStream1, tempStream2, options, out writtenBytes); if (i - 1 > 0) { tempStream1.Seek(0, 0); tempStream2.Seek(0, 0); tempStream2.SetLength(writtenBytes); dataProcessors[i - 1].ReverseProcessDataStream(tempStream2, tempStream1, options, out writtenBytes); } } if (dataProcessors.Count % 2 == 0) { tempStream1.Seek(0, 0); tempStream1.SetLength(writtenBytes); dataProcessors[0].ReverseProcessDataStream(tempStream1, finalOutputStream, options, out writtenBytes); } else { tempStream2.Seek(0, 0); tempStream2.SetLength(writtenBytes); dataProcessors[0].ReverseProcessDataStream(tempStream2, finalOutputStream, options, out writtenBytes); } } } else { tempStream1.Seek(0, 0); tempStream1.SetLength(writtenBytes); dataProcessors[0].ReverseProcessDataStream(tempStream1, finalOutputStream, options, out writtenBytes); } } } else { if (dataProcessors != null && dataProcessors.Count == 1) { dataProcessors[0].ReverseProcessDataStream(inputBytesStream, finalOutputStream, options, out writtenBytes); } else { AsyncStreamCopier.CopyStreamTo(inputBytesStream, finalOutputStream); } } } } } finally { arrayHandle.Free(); } return((object)resultArray); } } return(null); }
/// <summary> /// Serializes objectToSerialize to a byte array using compression provided by compressor if T is an array of primitives. Otherwise returns default value for T. Override /// to serialize other types /// </summary> /// <param name="objectToSerialise">Object to serialize</param> /// <param name="dataProcessors">The compression provider to use</param> /// <param name="options">Options to be used during serialization and processing of data</param> /// <returns>The serialized and compressed bytes of objectToSerialize</returns> public static unsafe StreamSendWrapper SerialiseArrayObject(object objectToSerialise, List <DataProcessor> dataProcessors, Dictionary <string, string> options) { Type objType = objectToSerialise.GetType(); if (objType.IsArray) { var elementType = objType.GetElementType(); //No need to do anything for a byte array if (elementType == typeof(byte) && (dataProcessors == null || dataProcessors.Count == 0)) { byte[] bytesToSerialise = objectToSerialise as byte[]; //return objectToSerialise as byte[]; return(new StreamSendWrapper(new ThreadSafeStream(new MemoryStream(bytesToSerialise, 0, bytesToSerialise.Length, false, true), true))); } else if (elementType.IsPrimitive) { var asArray = objectToSerialise as Array; GCHandle arrayHandle = GCHandle.Alloc(asArray, GCHandleType.Pinned); try { IntPtr safePtr = Marshal.UnsafeAddrOfPinnedArrayElement(asArray, 0); long writtenBytes = 0; MemoryStream tempStream1 = new System.IO.MemoryStream(); using (UnmanagedMemoryStream inputDataStream = new System.IO.UnmanagedMemoryStream((byte *)safePtr, asArray.Length * Marshal.SizeOf(elementType))) { if (dataProcessors == null || dataProcessors.Count == 0) { AsyncStreamCopier.CopyStreamTo(inputDataStream, tempStream1); //return tempStream1.ToArray(); return(new StreamSendWrapper(new ThreadSafeStream(tempStream1, true))); } dataProcessors[0].ForwardProcessDataStream(inputDataStream, tempStream1, options, out writtenBytes); } if (dataProcessors.Count > 1) { MemoryStream tempStream2 = new MemoryStream(); for (int i = 1; i < dataProcessors.Count; i += 2) { tempStream1.Seek(0, 0); tempStream1.SetLength(writtenBytes); tempStream2.Seek(0, 0); dataProcessors[i].ForwardProcessDataStream(tempStream1, tempStream2, options, out writtenBytes); if (i + 1 < dataProcessors.Count) { tempStream1.Seek(0, 0); tempStream2.Seek(0, 0); tempStream2.SetLength(writtenBytes); dataProcessors[i].ForwardProcessDataStream(tempStream2, tempStream1, options, out writtenBytes); } } if (dataProcessors.Count % 2 == 0) { tempStream2.SetLength(writtenBytes + 4); tempStream2.Seek(writtenBytes, 0); tempStream2.Write(BitConverter.GetBytes(asArray.Length), 0, sizeof(int)); //return tempStream2.ToArray(); tempStream1.Dispose(); return(new StreamSendWrapper(new ThreadSafeStream(tempStream2, true))); } else { tempStream1.SetLength(writtenBytes + 4); tempStream1.Seek(writtenBytes, 0); tempStream1.Write(BitConverter.GetBytes(asArray.Length), 0, sizeof(int)); //return tempStream1.ToArray(); tempStream2.Dispose(); return(new StreamSendWrapper(new ThreadSafeStream(tempStream1, true))); } } else { tempStream1.SetLength(writtenBytes + 4); tempStream1.Seek(writtenBytes, 0); tempStream1.Write(BitConverter.GetBytes(asArray.Length), 0, sizeof(int)); //return tempStream1.ToArray(); return(new StreamSendWrapper(new ThreadSafeStream(tempStream1, true))); } } finally { arrayHandle.Free(); } } } return(null); }