Example #1
0
        /// <summary>
        /// Serialize the block into the given stream.
        /// </summary>
        /// <param name="stream">Stream to write to.</param>
        /// <param name="serializer"></param>
        public static async Task <BlockHandle> WriteBlockAsync(Stream stream, Action <BinaryWriter> serializer)
        {
            using (var memoryStream = new MemoryStream(DefaultMemoryStreamSize))
                using (var memoryWriter = new BinaryWriter(memoryStream))
                {
                    // Serialize the table section.
                    serializer.Invoke(memoryWriter);

                    var blockSize = checked ((int)memoryStream.Position);

                    // Calculate the checksum.
                    var checksum = CRC64.ToCRC64(memoryStream.GetBuffer(), 0, blockSize);

                    // Get the position and size of this section within the stream.
                    var sectionHandle = new BlockHandle(stream.Position, blockSize);

                    // Write the checksum.
                    memoryWriter.Write(checksum);

                    var blockSizeWithChecksum = checked ((int)memoryStream.Position);
                    //Utility.Assert((blockSizeWithChecksum - blockSize) == 8, "unexpected block size.");

                    // Write the buffer and checksum to the stream.
                    await stream.WriteAsync(memoryStream.GetBuffer(), 0, blockSizeWithChecksum).ConfigureAwait(false);

                    return(sectionHandle);
                }
        }
Example #2
0
        /// <summary>
        /// Deserialize a block from the given stream.
        /// </summary>
        /// <param name="stream">Stream to read from.</param>
        /// <param name="blockHandle"></param>
        /// <param name="deserializer"></param>
        /// <returns>The block read from the stream.</returns>
        public static async Task <TBlock> ReadBlockAsync <TBlock>(
            Stream stream,
            BlockHandle blockHandle,
            Func <BinaryReader, BlockHandle, TBlock> deserializer)
        {
            // Data validation.
            if (blockHandle.Offset < 0)
            {
                throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_FileBlock_Corrupt, SR.Error_Negative_StreamOffset));
            }

            if (blockHandle.Size < 0)
            {
                throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_FileBlock_Corrupt, SR.Error_Negative_BlockSize));
            }

            if (blockHandle.EndOffset + sizeof(ulong) > stream.Length)
            {
                throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_FileBlock_Corrupt, SR.Error_Block_Beyond_Stream));
            }

            // Move the stream to the block's position within the stream.
            stream.Position = blockHandle.Offset;
            var blockSize             = checked ((int)blockHandle.Size);
            var blockSizeWithChecksum = blockSize + sizeof(ulong);

            // Read the bytes for the block, to calculate the checksum.
            var blockBytes = new byte[blockSizeWithChecksum];
            await stream.ReadAsync(blockBytes, 0, blockBytes.Length).ConfigureAwait(false);

            // Calculate the checksum.
            var blockChecksum = CRC64.ToCRC64(blockBytes, 0, blockSize);

            // Read the actual checksum (checksum is after the block bytes).
            var checksum = BitConverter.ToUInt64(blockBytes, blockSize);

            // Verify the checksum.
            if (checksum != blockChecksum)
            {
                throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_FileBlock_Corrupt, SR.Error_Checksum_Mismatch));
            }

            // Deserialize the actual file block.
            using (var memoryStream = new MemoryStream(blockBytes, 0, blockSize, writable: false))
                using (var memoryReader = new BinaryReader(memoryStream))
                {
                    return(deserializer.Invoke(memoryReader, new BlockHandle(0, blockHandle.Size)));
                }
        }