Esempio n. 1
0
        internal object GetFileHeader(long startPosition)
        {
            if (startPosition < 0)
            {
                throw new ArgumentNullException("startPosition");
            }

            //читаем системный заголовок
            this.BlobStream.Seek(startPosition, SeekOrigin.Begin);
            byte[] systemHeaderBytes = new byte[BlobStreamAdapter.SystemHeaderLength];
            this.BlobStream.Read(systemHeaderBytes, 0, BlobStreamAdapter.SystemHeaderLength);

            //проверка целостности системного заголовка
            for (int i = 0; i < SystemHeaderFixedBytes.Length; i++)
            {
                if (SystemHeaderFixedBytes[i] != systemHeaderBytes[i])
                {
                    throw new Exception(string.Format("Битый заголовок файла (позиция {0}). Не удалось прочитать системный заголовок файла.",
                                                      i));
                }
            }

            //целостность системного заголовока не нарушена, значит можно поднять заголовок файла
            //сразу за фиксированной частью системного заголовка есть 4 байта, в которых указана длина заголовка файла
            //длина заголовка файла
            int headerLength = BitConverter.ToInt32(systemHeaderBytes, SystemHeaderFixedBytes.Length);

            if (headerLength < 1)
            {
                throw new Exception(string.Format("Не удалось считать длину заголовка файла"));
            }

            byte[] headerBytes = new byte[headerLength];
            this.BlobStream.Seek(startPosition + BlobStreamAdapter.SystemHeaderLength, SeekOrigin.Begin);
            this.BlobStream.Read(headerBytes, 0, headerBytes.Length);

            int    headerVersionNumber = BitConverter.ToInt32(systemHeaderBytes, SystemHeaderFixedBytes.Length + BlobConsts.BlobFile.HeaderSizeBytesLength + BlobConsts.BlobFile.AllHashBytesLength);
            object header = null;

            using (MemoryStream headerStream = new MemoryStream(headerBytes))
            {
                headerStream.Position = 0;
                JsonBlobFileHeaderV1 typedHeader = JsonDataSerializer.Deserialize <JsonBlobFileHeaderV1>(headerStream);
                typedHeader.HeaderLength = headerLength;

                if (typedHeader.ContentLength == 0)
                {
                    //длина на момент записи заголовка не была вычислина (потоковая передача)
                    //смотрим эту длину по системному заголовку
                    long contentLengBytesAbsolutePosition = FileStructure.GetContentLengBytesAbsolutePosition();
                    typedHeader.ContentLength = BitConverter.ToInt64(systemHeaderBytes, (int)contentLengBytesAbsolutePosition);
                }

                header = typedHeader;
            }

            return(header);
        }
Esempio n. 2
0
        private object GetFileHeader(byte[] contentWithHeadersData)
        {
            if (contentWithHeadersData == null)
            {
                throw new ArgumentNullException("fileData");
            }

            object header = null;

            //сразу за системным заголовком 4 байта, в которых указана длина заголовка файла
            //длина заголовка файла
            int headerLength = BitConverter.ToInt32(contentWithHeadersData, SystemHeaderFixedBytes.Length);

            if (headerLength < 1)
            {
                throw new Exception(string.Format("Не удалось считать длину заголовка файла"));
            }

            byte[] headerBytes = new byte[headerLength];
            Array.Copy(contentWithHeadersData, BlobStreamAdapter.SystemHeaderLength, headerBytes, 0, headerLength);

            int headerVersionNumber = BitConverter.ToInt32(contentWithHeadersData, SystemHeaderFixedBytes.Length + BlobConsts.BlobFile.HeaderSizeBytesLength + BlobConsts.BlobFile.AllHashBytesLength);

            using (MemoryStream headerStream = new MemoryStream(headerBytes))
            {
                headerStream.Position = 0;
                JsonBlobFileHeaderV1 typedHeader = JsonDataSerializer.Deserialize <JsonBlobFileHeaderV1>(headerStream);
                typedHeader.HeaderLength = headerLength;

                if (typedHeader.ContentLength == 0)
                {
                    //длина на момент записи заголовка не была вычислина (потоковая передача)
                    //смотрим эту длину по системному заголовку
                    long contentLengBytesAbsolutePosition = FileStructure.GetContentLengBytesAbsolutePosition();
                    typedHeader.ContentLength = BitConverter.ToInt64(contentWithHeadersData, (int)contentLengBytesAbsolutePosition);
                }

                header = typedHeader;
            }

            return(header);
        }
Esempio n. 3
0
        /// <summary>
        /// Сохраняет содержимое файла с заголовками в поток.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <param name="versionTimeCreated">Дата создания версии файла.</param>
        internal void Write(IBlobFileMetadata fileMetadata, Stream stream, DateTime versionTimeCreated)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.UniqueID == Guid.Empty)
            {
                throw new ArgumentNullException("fileMetadata.UniqueID");
            }

            if (string.IsNullOrEmpty(fileMetadata.Name))
            {
                throw new ArgumentNullException("fileMetadata.Name");
            }

            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!this.BlobStream.CanWrite)
            {
                throw new Exception(string.Format("Для сохранения файла в поток необходимо передать поток с правами на запись"));
            }

            bool contentLengthCalculated = false;
            long contentLength           = 0;

            if (stream.CanSeek)
            {
                contentLength           = stream.Length;
                contentLengthCalculated = true;
            }

            byte[] systemHeaderInfoBytes = new byte[BlobStreamAdapter.SystemHeaderLength];
            byte[] headerBytes           = null;
            int    headerLength          = 0;

            //запись текущей версии заголовка
            long blobOffset = this.BlobStream.Position;

            using (MemoryStream fileHeaderStream = new MemoryStream())
            {
                //сериализация заголовка
                this.SerializeHeader(fileHeaderStream, fileMetadata, contentLength, versionTimeCreated);

                //после сериализации заголовка становится известна длина
                headerLength = (int)fileHeaderStream.Length;
                headerBytes  = new byte[headerLength];
                fileHeaderStream.Position = 0;
                fileHeaderStream.Read(headerBytes, 0, headerLength);
            }

            //хеш заголовка и содерижмого
            byte[] headerHash = this.HashAlgorithm.ComputeHash(headerBytes);

            //длина заголовка
            byte[] headerLengthBytes = BitConverter.GetBytes(headerLength);
            //номер версии заголовка
            byte[] headerVersionBytes = BitConverter.GetBytes(BlobConsts.BlobFile.FileHeaderCurrentVersion);


            //заполнение системного заголовка
            //а - фиксированные байты
            int headerCursor = 0;

            Array.Copy(SystemHeaderFixedBytes, 0, systemHeaderInfoBytes, headerCursor, SystemHeaderFixedBytes.Length);
            headerCursor += SystemHeaderFixedBytes.Length;

            //б - размер заголовка файла
            Array.Copy(headerLengthBytes, 0, systemHeaderInfoBytes, headerCursor, headerLengthBytes.Length);
            headerCursor += headerLengthBytes.Length;

            //в - хеш заголовка файла
            Array.Copy(headerHash, 0, systemHeaderInfoBytes, headerCursor, headerHash.Length);
            headerCursor += headerHash.Length;

            //г - хеш содержимого файла
            long tmpcontentHashPosition = this.BlobStream.Position + headerCursor; //абсолютная позиция в файле байтов длины содержимого

            //пустой хеш содержимого, рассчитывается после записи
            byte[] contentHash = new byte[16];
            Array.Copy(contentHash, 0, systemHeaderInfoBytes, headerCursor, contentHash.Length);
            headerCursor += contentHash.Length;

            //д - версия заголовка файла
            Array.Copy(headerVersionBytes, 0, systemHeaderInfoBytes, headerCursor, headerVersionBytes.Length);
            headerCursor += headerVersionBytes.Length;

            //е - размер содержимого файла
            long tmpContentSizePosition = this.BlobStream.Position + headerCursor; //абсолютная позиция в файле байтов длины содержимого

            byte[] contentLengthBytes = BitConverter.GetBytes(contentLength);
            Array.Copy(contentLengthBytes, 0, systemHeaderInfoBytes, headerCursor, contentLengthBytes.Length);
            headerCursor += contentLengthBytes.Length;

            //1 - запись системного заголовка
            this.BlobStream.Write(systemHeaderInfoBytes, 0, systemHeaderInfoBytes.Length);

            //2 - запись заголовка файла
            this.BlobStream.Write(headerBytes, 0, headerBytes.Length);

            //3 - запись содержимого
            long startContentPosition = this.BlobStream.Position;

            int readBufferSize = 4 * 1024;

            byte[]        buffer           = new byte[readBufferSize];
            int           read             = 0;
            HashAlgorithm tmpHashAlgorithm = this.CreateHashAlgorithm();

            byte[] writeBuffer = new byte[readBufferSize];

            int writePosition = 0;

            while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                tmpHashAlgorithm.TransformBlock(buffer, 0, read, null, 0);

                if ((writePosition + read) >= writeBuffer.Length)
                {
                    //дозаполняем буфер
                    int restBufferSize = writeBuffer.Length - writePosition;
                    Array.Copy(buffer, 0, writeBuffer, writePosition, restBufferSize);
                    writePosition += restBufferSize;

                    //скидываем буфер записи на диск
                    this.BlobStream.Write(writeBuffer, 0, writePosition);

                    int newSessionPosition = read - restBufferSize;
                    if (newSessionPosition > 0)
                    {
                        //остальные данные опять загоняем в буфер
                        Array.Copy(buffer, restBufferSize, writeBuffer, 0, newSessionPosition);
                    }

                    writePosition = newSessionPosition;
                }
                else
                {
                    //записываем только в буфер, на диск не скидываем
                    Array.Copy(buffer, 0, writeBuffer, writePosition, read);
                    writePosition += read;
                }
            }

            if (writePosition > 0)
            {
                this.BlobStream.Write(writeBuffer, 0, writePosition);
            }

            tmpHashAlgorithm.TransformFinalBlock(buffer, 0, read);


            //физически записанная длина файла
            long endContentPosition = this.BlobStream.Position;

            contentLength = endContentPosition - startContentPosition;

            //4 - переписываем 16 пустых байт хеша содержимого, после его вычисления
            contentHash = tmpHashAlgorithm.Hash;
            long contentHashBytesAbsolutePosition = FileStructure.GetContentHashBytesAbsolutePosition(blobOffset);

            this.BlobStream.Seek(contentHashBytesAbsolutePosition, SeekOrigin.Begin);
            this.BlobStream.Write(contentHash, 0, contentHash.Length);


            //5 - в 100 зарезервированных байт пишем длину содержимого (ранее была в заголовке)
            //теперь обязательно есть в системном заголовке, а в файловом заголовке есть, если пришел буферный поток
            //делаем это только в случае потоковой передачи, если длина известна сразу, то она и запишется сразу
            if (!contentLengthCalculated)
            {
                long contentLengBytesAbsolutePosition = FileStructure.GetContentLengBytesAbsolutePosition(blobOffset);
                contentLengthBytes = BitConverter.GetBytes(contentLength);
                this.BlobStream.Seek(contentLengBytesAbsolutePosition, SeekOrigin.Begin);
                this.BlobStream.Write(contentLengthBytes, 0, contentLengthBytes.Length);
            }

            fileMetadata.Size = contentLength;
        }