/// <summary>
        /// Read all data parts from <see cref="DataPack"/>
        /// </summary>
        /// <param name="dataPack"></param>
        /// <param name="br">Binary reader</param>
        /// <param name="dataPartInfos">List of datapart information</param>
        /// <param name="stream">Stream of transport container</param>
        protected override void ReadDataParts(DataPack dataPack, BinaryReader br, List <DataPartInfo> dataPartInfos, Stream stream)
        {
            foreach (var dataPartInfo in dataPartInfos)
            {
                IDataContainer dataContainer;
                using (var filteredStream = new FilteredStream(stream, dataPartInfo.DataAddress, dataPartInfo.DataSize))
                {
                    dataContainer = new TempFileDataContainer(filteredStream);
                }

                var dataPart = new DataPart(dataContainer);

                if (dataPartInfo.HeadersCount > 0)
                {
                    stream.Seek(dataPartInfo.HeadersAddress, SeekOrigin.Begin);
                    using (var filter = new FilteredStream(stream, dataPartInfo.HeadersAddress, dataPartInfo.HeadersSize))
                    {
                        for (ushort i = 0; i < dataPartInfo.HeadersCount; i++)
                        {
                            dataPart.Headers.Add(Serializer.DeserializeWithLengthPrefix <DataPair>(filter, PrefixStyle.Base128));
                        }
                    }
                }

                if (dataPartInfo.PropertiesCount > 0)
                {
                    stream.Seek(dataPartInfo.PropertiesAddress, SeekOrigin.Begin);
                    using (var filter = new FilteredStream(stream, dataPartInfo.PropertiesAddress, dataPartInfo.PropertiesSize))
                    {
                        for (ushort i = 0; i < dataPartInfo.PropertiesCount; i++)
                        {
                            dataPart.Properties.AddOrReplace(Serializer.DeserializeWithLengthPrefix <DataPair>(filter, PrefixStyle.Base128));
                        }
                    }
                }

                dataPack.DataParts.Add(dataPart);
            }
        }
        /// <summary>
        /// Writes <see cref="DataPack"/> to stream
        /// </summary>
        /// <param name="dataPack">Data</param>
        /// <param name="stream">Stream where <see cref="DataPack"/> is written to</param>
        /// <param name="signAlgorithm">Sign algorithm if needed</param>
        public void Write(DataPack dataPack, Stream stream, ISignAlgorithm signAlgorithm = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (dataPack == null)
            {
                throw new ArgumentNullException("dataPack");
            }

            if (!stream.CanSeek)
            {
                throw new InvalidOperationException("Stream doesn't support seeking.");
            }
            if (!stream.CanWrite)
            {
                throw new InvalidOperationException("Stream doesn't support writing.");
            }

            using (var wrapper = new NonClosingStreamWrapper(stream)) // To prevent source stream from closing by BinaryWriter
                using (var bw = new BinaryWriter(wrapper))
                {
                    // Size of prefix
                    bw.Write(dataPack.PrefixSize);

                    // Prefix of data
                    bw.Write(dataPack.GetPrefix(), 0, dataPack.PrefixSize);

                    uint signInfoAddress = 0;
                    uint dataSizeAddress = 0;
                    if (signAlgorithm == null)
                    {
                        // Stream not signed
                        bw.Write((byte)0);
                    }
                    else
                    {
                        // Stream is signed
                        bw.Write((byte)1);
                        signInfoAddress = GetAddress(bw);
                        bw.Write(0); // Protected data size
                        bw.Write(0); // Sign size
                        dataSizeAddress = GetAddress(bw) - 8;
                    }

                    // Create implicit properties
                    var implicitProperties = new Properties();
                    if (dataPack.DateCreate != null)
                    {
                        implicitProperties["DateCreate"] = dataPack.DateCreate.Value.ToString(Consts.DateTimeFormat, CultureInfo.InvariantCulture);
                    }
                    if (dataPack.FileId != null)
                    {
                        implicitProperties["FileId"] = dataPack.FileId != null
                        ? dataPack.FileId.Value.ToString()
                        : null;
                    }
                    if (dataPack.Description != null)
                    {
                        implicitProperties["Description"] = dataPack.Description;
                    }

                    // Info section implicit properties
                    var properties = implicitProperties.GetPropertiesList();
                    bw.Write(InfoSection);
                    uint address = GetAddress(bw);
                    bw.Write(0u);
                    ushort cnt = (ushort)properties.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, properties[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Info section with data headers info
                    bw.Write(InfoSection);
                    address = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)dataPack.Headers.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, dataPack.Headers[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Header section with data properties info
                    properties = dataPack.Properties.GetPropertiesList();
                    bw.Write(InfoSection);
                    address = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)properties.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, properties[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Header section with data dataPart's info
                    bw.Write(InfoSection);
                    var dataPartAddress = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)dataPack.DataParts.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        bw.Write(0u);
                        bw.Write((ushort)0);
                        bw.Write(0u);
                        bw.Write(0u);
                        bw.Write((ushort)0);
                        bw.Write(0u);
                        bw.Write(0u);
                        bw.Write(0u);
                    }

                    WriteSize(bw, dataPartAddress, dataPartAddress + 4);

                    bw.Write(DataSection);
                    address = GetAddress(bw);
                    bw.Write(0u);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        WriteDataPart(bw, dataPartAddress + 6, i, dataPack);
                    }

                    WriteSize(bw, address, address + 4);

                    bw.Seek(0, SeekOrigin.End);
                    bw.Flush();

                    if (signAlgorithm != null)
                    {
                        uint protectedDataSize = GetAddress(bw) - dataSizeAddress;

                        wrapper.Position = dataSizeAddress;
                        bw.Write(protectedDataSize);
                        bw.Flush();

                        byte[] sign;
                        using (var filter = new FilteredStream(wrapper, dataSizeAddress, protectedDataSize))
                        {
                            sign = signAlgorithm.GetSign(filter);
                        }

                        wrapper.Seek(0, SeekOrigin.End);

                        bw.Write(sign, 0, sign.Length);
                        bw.Flush();

                        wrapper.Position = signInfoAddress;
                        bw.Write((uint)sign.Length);
                        bw.Flush();

                        wrapper.Seek(0, SeekOrigin.End);
                    }
                }
        }
示例#3
0
        /// <summary>
        /// Reads <see cref="DataPack"/> from stream, using prefix if provided
        /// </summary>
        /// <param name="stream">Stream with data to deserialize</param>
        /// <param name="prefix">Byte array with bytes to check before deserialize</param>
        /// <returns></returns>
        public DataPack Read(Stream stream, byte[] prefix = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanSeek)
            {
                throw new InvalidOperationException("Stream doesn't support seeking.");
            }
            if (!stream.CanRead)
            {
                throw new InvalidOperationException("Stream doesn't support reading.");
            }

            DataPack dataPack;

            using (var wrapper = new NonClosingStreamWrapper(stream)) // To prevent source stream from closing by BinaryReader
                using (var br = new BinaryReader(wrapper))
                {
                    byte   prefixSize = br.ReadByte();
                    byte[] dataPrefix = null;
                    if (prefixSize > 0)
                    {
                        dataPrefix = br.ReadBytes(prefixSize);
                    }

                    dataPack = new DataPack(dataPrefix)
                    {
                        DateCreate  = null,
                        Description = null,
                        FileId      = null
                    };

                    if (!dataPack.IsPrefixMatch(prefix))
                    {
                        throw new InvalidOperationException("Data prefix is wrong.");
                    }

                    byte isSignedByte = br.ReadByte();
                    switch (isSignedByte)
                    {
                    case 0: // No sign. Nothing to do
                        break;

                    case 1:
                        // ReSharper disable once UnusedVariable
                        uint protectedDataSize = br.ReadUInt32(); // Protected data size

                        // ReSharper disable once UnusedVariable
                        uint signSize = br.ReadUInt32(); // Sign size

                        break;

                    default:
                        throw new InvalidOperationException("Unknown information about file sign.");
                    }

                    if (br.ReadByte() != InfoSection)
                    {
                        throw new InvalidOperationException("Implicit properties info section not found.");
                    }

                    uint   size            = br.ReadUInt32();
                    ushort propertiesCount = br.ReadUInt16();

                    var implicitProperties = new Properties();
                    using (var filter = new FilteredStream(wrapper, wrapper.Position, size - 2))
                    {
                        for (ushort i = 0; i < propertiesCount; i++)
                        {
                            implicitProperties.AddOrReplace(Serializer.DeserializeWithLengthPrefix <DataPair>(filter, PrefixStyle.Base128));
                        }
                    }

                    var dateCreateString = implicitProperties.TryGetPropertyValue("DateCreate", null);
                    if (dateCreateString != null)
                    {
                        dataPack.DateCreate = DateTime.ParseExact(dateCreateString, Consts.DateTimeFormat, CultureInfo.InvariantCulture);
                    }

                    var fileIdString = implicitProperties.TryGetPropertyValue("FileId", null);
                    if (fileIdString != null)
                    {
#if NET20 || NET30 || NET35
                        dataPack.FileId = new Guid(fileIdString);
#endif

#if NET40 || NET45
                        dataPack.FileId = Guid.Parse(fileIdString);
#endif
                    }

                    var descriptionString = implicitProperties.TryGetPropertyValue("Description", null);
                    if (descriptionString != null)
                    {
                        dataPack.Description = descriptionString;
                    }

                    if (br.ReadByte() != InfoSection)
                    {
                        throw new InvalidOperationException("Headers info section not found.");
                    }

                    size = br.ReadUInt32();
                    ushort headersCount = br.ReadUInt16();

                    using (var filter = new FilteredStream(wrapper, br.BaseStream.Position, size - 2))
                    {
                        for (ushort i = 0; i < headersCount; i++)
                        {
                            dataPack.Headers.Add(Serializer.DeserializeWithLengthPrefix <DataPair>(filter, PrefixStyle.Base128));
                        }
                    }

                    if (br.ReadByte() != InfoSection)
                    {
                        throw new InvalidOperationException("Properties info section not found.");
                    }

                    size            = br.ReadUInt32();
                    propertiesCount = br.ReadUInt16();

                    using (var filter = new FilteredStream(wrapper, br.BaseStream.Position, size - 2))
                    {
                        for (ushort i = 0; i < propertiesCount; i++)
                        {
                            dataPack.Properties.AddOrReplace(Serializer.DeserializeWithLengthPrefix <DataPair>(filter, PrefixStyle.Base128));
                        }
                    }

                    if (br.ReadByte() != InfoSection)
                    {
                        throw new InvalidOperationException("DataPart's info section not found.");
                    }

                    // ReSharper disable once RedundantAssignment
                    size = br.ReadUInt32();
                    ushort dataPartsCount = br.ReadUInt16();
                    var    dataPartInfos  = new List <DataPartInfo>();

                    for (ushort i = 0; i < dataPartsCount; i++)
                    {
                        dataPartInfos.Add(new DataPartInfo
                        {
                            HeadersAddress    = br.ReadUInt32(),
                            HeadersCount      = br.ReadUInt16(),
                            HeadersSize       = br.ReadUInt32(),
                            PropertiesAddress = br.ReadUInt32(),
                            PropertiesCount   = br.ReadUInt16(),
                            PropertiesSize    = br.ReadUInt32(),
                            DataAddress       = br.ReadUInt32(),
                            DataSize          = br.ReadUInt32()
                        });
                    }

                    ReadDataParts(dataPack, br, dataPartInfos, stream);
                }

            return(dataPack);
        }
示例#4
0
        /// <summary>
        /// Sign source <see cref="DataPack"/> stream using given sign algorithm and outputs result to destinationStream
        /// </summary>
        /// <param name="prefixSize">Size of file prefix</param>
        /// <param name="signAlgorithm">Sign algorithm</param>
        /// <param name="sourceStream">Source stream</param>
        /// <param name="destinationStream">Destination stream</param>
        public static void Sign(uint prefixSize, ISignAlgorithm signAlgorithm, Stream sourceStream, Stream destinationStream)
        {
            if (signAlgorithm == null)
            {
                throw new ArgumentNullException("signAlgorithm");
            }
            if (sourceStream == null)
            {
                throw new ArgumentNullException("sourceStream");
            }
            if (destinationStream == null)
            {
                throw new ArgumentNullException("destinationStream");
            }

            var position = sourceStream.Position;

            if (!sourceStream.CanSeek)
            {
                throw new InvalidOperationException("Source stream doesn't support seeking.");
            }
            if (!sourceStream.CanRead)
            {
                throw new InvalidOperationException("Source stream doesn't support reading.");
            }
            if (!destinationStream.CanSeek)
            {
                throw new InvalidOperationException("Destination stream doesn't support seeking.");
            }
            if (!destinationStream.CanRead)
            {
                throw new InvalidOperationException("Destination stream doesn't support reading.");
            }
            if (!destinationStream.CanWrite)
            {
                throw new InvalidOperationException("Destination stream doesn't support writing.");
            }

            sourceStream.Seek(prefixSize + 1, SeekOrigin.Current);
            int isSignedByte = sourceStream.ReadByte();

            if (isSignedByte == 1)
            {
                throw new InvalidOperationException("Source stream already signed.");
            }

            sourceStream.Position = position;

            var buffer = BufferProvider.Current.TakeBuffer();

            try
            {
                int  byteCount;
                uint prefixBytesLeft = prefixSize + 1;
                while ((byteCount = sourceStream.Read(buffer, 0, (int)Math.Min(buffer.Length, prefixBytesLeft))) > 0)
                {
                    destinationStream.Write(buffer, 0, byteCount);
                    prefixBytesLeft -= (uint)byteCount;
                    if (prefixBytesLeft == 0)
                    {
                        break;
                    }
                }

                using (var wrapper = new NonClosingStreamWrapper(destinationStream)) // To prevent stream from closing by BinaryWriter
                    using (var bw = new BinaryWriter(wrapper))
                    {
                        bw.Write((byte)1);

                        uint signInfoAddress = GetAddress(bw);
                        bw.Write(0); // Protected data size
                        bw.Write(0); // Sign size

                        uint dataSizeAddress = GetAddress(bw) - 8;

                        while ((byteCount = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            wrapper.Write(buffer, 0, byteCount);
                        }

                        wrapper.Flush();
                        uint protectedDataSize = GetAddress(bw) - dataSizeAddress;

                        wrapper.Position = dataSizeAddress;
                        bw.Write(protectedDataSize);
                        bw.Flush();

                        byte[] sign;
                        using (var filter = new FilteredStream(wrapper, dataSizeAddress, protectedDataSize))
                        {
                            sign = signAlgorithm.GetSign(filter);
                        }

                        wrapper.Seek(0, SeekOrigin.End);

                        bw.Write(sign, 0, sign.Length);
                        bw.Flush();

                        wrapper.Position = signInfoAddress;
                        bw.Write((uint)sign.Length);
                        bw.Flush();

                        wrapper.Seek(0, SeekOrigin.End);
                    }
            }
            finally
            {
                BufferProvider.Current.ReturnBuffer(buffer);
            }
        }