1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-09 03:33:29 +08:00
Files
DSP_Mods/CompressSave/Wrapper/DecompressionStream.cs
2022-11-20 16:36:02 +08:00

148 lines
4.3 KiB
C#

using System;
using System.IO;
namespace CompressSave.Wrapper;
public class DecompressionStream : Stream
{
public WrapperDefines wrapper;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => inStream.Length;
public override long Position
{ get => readPos;
set
{
if (value < readPos)
ResetStream();
else
value -= readPos;
byte[] tmpBuffer = new byte[1024];
while (value > 0)
{
value -= Read(tmpBuffer, 0, (int)(value < 1024 ? value : 1024));
}
}
}
public Stream inStream;
IntPtr dctx = IntPtr.Zero;
readonly ByteSpan srcBuffer;
readonly ByteSpan dcmpBuffer;
private bool decompressFinish = false;
readonly long startPos = 0;
long readPos = 0; //sum of readlen
public DecompressionStream(WrapperDefines wrap, Stream inStream,int extraBufferSize = 512*1024)
{
this.wrapper = wrap;
this.inStream = inStream;
startPos = inStream.Position;
srcBuffer = new ByteSpan(new byte[extraBufferSize]);
int len = Fill();
long expect = wrapper.DecompressBegin(ref dctx, srcBuffer.Buffer, ref len, out var blockSize);
srcBuffer.Position += len;
if (expect < 0) throw new Exception(expect.ToString());
dcmpBuffer = new ByteSpan(new byte[blockSize]);
}
public void ResetStream()
{
inStream.Seek(startPos, SeekOrigin.Begin);
decompressFinish = false;
srcBuffer.Clear();
dcmpBuffer.Clear();
wrapper.DecompressContextReset(dctx);
readPos = 0;
}
public int Fill()
{
int suplus = srcBuffer.Length - srcBuffer.Position;
if (srcBuffer.Length> 0 && srcBuffer.Position >= suplus)
{
Array.Copy(srcBuffer, srcBuffer.Position, srcBuffer, 0, suplus);
srcBuffer.Length -= srcBuffer.Position;
srcBuffer.Position = 0;
}
if (srcBuffer.IdleCapacity > 0)
{
var readlen = inStream.Read(srcBuffer, srcBuffer.Length, srcBuffer.IdleCapacity);
srcBuffer.Length += readlen;
}
return srcBuffer.Length - srcBuffer.Position;
}
public override void Flush()
{
}
protected override void Dispose(bool disposing)
{
wrapper.DecompressEnd(dctx);
dctx = IntPtr.Zero;
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count)
{
int readlen = 0;
while (count > (readlen += dcmpBuffer.Read(buffer, offset + readlen, count - readlen)) && !decompressFinish)
{
var buffSize = Fill();
if (buffSize <= 0) return readlen;
var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position,buffSize);
if (rt.Expect < 0) throw new Exception(rt.Expect.ToString());
if (rt.Expect == 0) decompressFinish = true;
srcBuffer.Position += (int)rt.ReadLen;
dcmpBuffer.Position = 0;
dcmpBuffer.Length = (int)rt.WriteLen;
}
readPos += readlen;
return readlen;
}
public int PeekByte()
{
if (dcmpBuffer.Length <= dcmpBuffer.Position)
{
var buffSize = Fill();
if (buffSize <= 0) return -1;
var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position, buffSize);
if (rt.Expect < 0) throw new Exception(rt.Expect.ToString());
if (rt.Expect == 0) decompressFinish = true;
srcBuffer.Position += (int)rt.ReadLen;
dcmpBuffer.Position = 0;
dcmpBuffer.Length = (int)rt.WriteLen;
}
return dcmpBuffer.Buffer[dcmpBuffer.Position];
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}