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)); }