/// <summary> /// Creates or opens a TransactedCompoundFile using the filename specified. /// </summary> public TransactedCompoundFile(Options options) { _options = options.Clone(); _sync = new object(); BlockSize = _options.BlockSize; BlocksPerSection = BlockSize >> 2; SectionSize = BlockSize * BlocksPerSection; _freeHandles = new OrdinalList(); _freeBlocks = new OrdinalList(); _reservedBlocks = new OrdinalList(); _stream = new FileStream( _options.FilePath, _options.CreateNew ? FileMode.Create : FileMode.Open, _options.ReadOnly ? FileAccess.Read : FileAccess.ReadWrite, _options.ReadOnly ? FileShare.ReadWrite : FileShare.Read, 8, _options.FileOptions ); _fcommit = _fput = fput; _fget = ReadBytes; try { LoadSections(_stream); if (_sections.Length == 0) { AddSection(); } } catch { _stream.Dispose(); throw; } if (!_options.CommitOnWrite) { _fcommit = null; } _readers = new StreamCache( new FileStreamFactory(_options.FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 8, FileOptions.None), 4); }
public void GetFree(ICollection <int> freeHandles, ICollection <int> usedBlocks, FGet fget) { int baseHandle = unchecked (BlocksPerSection * _sectionIndex); //reserved: first and last block usedBlocks.Add(baseHandle); usedBlocks.Add(baseHandle + BlocksPerSection - 1); for (int handle = 1; handle < BlocksPerSection - 1; handle++) { uint data = ReadUInt32(handle); if (data == 0) { freeHandles.Add(baseHandle + handle); } else { BlockRef block = new BlockRef(data, BlockSize); int blockId = (int)block.Identity & 0x0FFFFFFF; if (block.Count == 16) { long position = (long)BlocksPerSection * BlockSize * block.Section; position += BlockSize * block.Offset; byte[] header = new byte[BlockHeaderSize]; if (BlockHeaderSize != fget(position, header, 0, header.Length)) { throw new InvalidDataException(); } block.ActualBlocks = (int)GetUInt32(header, OffsetOfBlockCount); } for (uint i = 0; i < block.ActualBlocks; i++) { usedBlocks.Add(blockId++); } } } }
public Stream Read(ref BlockRef block, bool headerOnly, FGet fget) { bool retry; byte[] bytes; int readBytes, headerSize, length; do { retry = false; long position = _sectionPosition + (BlockSize * block.Offset); bytes = new byte[headerOnly ? BlockHeaderSize : block.ActualBlocks * BlockSize]; readBytes = fget(position, bytes, 0, bytes.Length); if (readBytes < BlockHeaderSize) { throw new InvalidDataException(); } headerSize = bytes[OffsetOfHeaderSize]; length = (int)GetUInt32(bytes, OffsetOfLength) & 0x00FFFFFF; block.ActualBlocks = (int)GetUInt32(bytes, OffsetOfBlockCount); uint blockId = GetUInt32(bytes, OffsetOfBlockId); if (headerSize < BlockHeaderSize || blockId != block.Identity || ((block.Count < 16 && block.ActualBlocks != block.Count) || (block.Count == 16 && block.ActualBlocks < 16))) { throw new InvalidDataException(); } if (block.ActualBlocks != Math.Max(1, (length + headerSize + BlockSize - 1) / BlockSize)) { throw new InvalidDataException(); } if (headerOnly) { return(null); } if (readBytes < length + headerSize) { retry = bytes.Length != block.ActualBlocks * BlockSize; } } while (retry); if (readBytes < length + headerSize) { throw new InvalidDataException(); } Crc32 crc = new Crc32(); crc.Add(bytes, headerSize, length); if ((uint)crc.Value != GetUInt32(bytes, OffsetOfCrc32)) { throw new InvalidDataException(); } return(new MemoryStream(bytes, headerSize, length, false, false)); }