Files
sharpcompress/src/SharpCompress/IO/DataDescriptorStream.cs
2024-01-08 09:18:34 +00:00

155 lines
4.1 KiB
C#

using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace SharpCompress.IO;
public class DataDescriptorStream : Stream
{
private readonly Stream _stream;
private long _start;
private int _search_position;
private bool _isDisposed;
private bool _done;
private static byte[] DataDescriptorMarker = new byte[] { 0x50, 0x4b, 0x07, 0x08 };
private static long DataDescriptorSize = 24;
public DataDescriptorStream(Stream stream)
{
_stream = stream;
_start = _stream.Position;
_search_position = 0;
_done = false;
}
internal bool IsRecording { get; private set; }
protected override void Dispose(bool disposing)
{
if (_isDisposed)
{
return;
}
_isDisposed = true;
base.Dispose(disposing);
if (disposing)
{
_stream.Dispose();
}
}
public override bool CanRead => true;
public override bool CanSeek => _stream.CanSeek;
public override bool CanWrite => false;
public override void Flush() { }
public override long Length => _stream.Length;
public override long Position
{
get => _stream.Position - _start;
set => _stream.Position = value;
}
private bool validate_data_descriptor(Stream stream, long size)
{
var br = new BinaryReader(stream);
br.ReadUInt32();
br.ReadUInt32(); // CRC32 can be checked if we calculate it
var compressed_size = br.ReadUInt32();
var uncompressed_size = br.ReadUInt32();
var uncompressed_64bit = br.ReadInt64();
stream.Position -= DataDescriptorSize;
var test_64bit = ((long)uncompressed_size << 32) | compressed_size;
if (test_64bit == size && test_64bit == uncompressed_64bit)
{
return true;
}
if (compressed_size == size && compressed_size == uncompressed_size)
{
return true;
}
return false;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (count == 0 || _done)
{
return 0;
}
int read = _stream.Read(buffer, offset, count);
for (int i = 0; i < read; i++)
{
if (buffer[offset + i] == DataDescriptorMarker[_search_position])
{
_search_position++;
if (_search_position == 4)
{
_search_position = 0;
if (read - i > DataDescriptorSize)
{
var check = new MemoryStream(
buffer,
offset + i - 3,
(int)DataDescriptorSize
);
_done = validate_data_descriptor(
check,
_stream.Position - read + i - 3 - _start
);
if (_done)
{
_stream.Position = _stream.Position - read + i - 3;
return i - 3;
}
}
else
{
_stream.Position = _stream.Position - read + i - 3;
_done = validate_data_descriptor(_stream, _stream.Position - _start);
return i - 3;
}
}
}
else
{
_search_position = 0;
}
}
if (_search_position > 0)
{
read -= _search_position;
_stream.Position -= _search_position;
_search_position = 0;
}
return read;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) =>
throw new NotSupportedException();
}