mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-09 02:26:47 +00:00
179 lines
4.8 KiB
C#
179 lines
4.8 KiB
C#
#nullable disable
|
|
|
|
using System;
|
|
using System.Buffers;
|
|
using SharpCompress.Common;
|
|
using size_t = System.UInt32;
|
|
|
|
namespace SharpCompress.Compressors.Rar.UnpackV2017;
|
|
|
|
internal partial class FragmentedWindow
|
|
{
|
|
public FragmentedWindow()
|
|
{
|
|
//memset(Mem,0,sizeof(Mem));
|
|
//memset(MemSize,0,sizeof(MemSize));
|
|
}
|
|
|
|
//FragmentedWindow::~FragmentedWindow()
|
|
//{
|
|
// Reset();
|
|
//}
|
|
|
|
public void Reset()
|
|
{
|
|
for (uint I = 0; I < Mem.Length; I++)
|
|
{
|
|
if (Mem[I] != null)
|
|
{
|
|
ArrayPool<byte>.Shared.Return(Mem[I]);
|
|
Mem[I] = null;
|
|
}
|
|
MemSize[I] = 0;
|
|
}
|
|
}
|
|
|
|
public void Init(size_t WinSize)
|
|
{
|
|
Reset();
|
|
|
|
uint BlockNum = 0;
|
|
size_t TotalSize = 0; // Already allocated.
|
|
while (TotalSize < WinSize && BlockNum < Mem.Length)
|
|
{
|
|
var Size = WinSize - TotalSize; // Size needed to allocate.
|
|
|
|
// Minimum still acceptable block size. Next allocations cannot be larger
|
|
// than current, so we do not need blocks if they are smaller than
|
|
// "size left / attempts left". Also we do not waste time to blocks
|
|
// smaller than some arbitrary constant.
|
|
var MinSize = Math.Max(Size / (size_t)(Mem.Length - BlockNum), 0x400000);
|
|
|
|
byte[] NewMem = null;
|
|
while (Size >= MinSize)
|
|
{
|
|
NewMem = ArrayPool<byte>.Shared.Rent(checked((int)Size));
|
|
if (NewMem != null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Size -= Size / 32;
|
|
}
|
|
|
|
// Clean the window to generate the same output when unpacking corrupt
|
|
// RAR files, which may access to unused areas of sliding dictionary.
|
|
// sharpcompress: don't need this, freshly allocated above
|
|
//Utility.Memset(NewMem,0,Size);
|
|
|
|
Mem[BlockNum] = NewMem ?? throw new ArchiveOperationException();
|
|
TotalSize += Size;
|
|
MemSize[BlockNum] = TotalSize;
|
|
BlockNum++;
|
|
}
|
|
if (TotalSize < WinSize) // Not found enough free blocks.
|
|
//throw std::bad_alloc();
|
|
{
|
|
throw new ArchiveOperationException();
|
|
}
|
|
}
|
|
|
|
public byte this[size_t Item]
|
|
{
|
|
get
|
|
{
|
|
if (Item < MemSize[0])
|
|
{
|
|
return Mem[0][Item];
|
|
}
|
|
|
|
for (uint I = 1; I < MemSize.Length; I++)
|
|
{
|
|
if (Item < MemSize[I])
|
|
{
|
|
return Mem[I][Item - MemSize[I - 1]];
|
|
}
|
|
}
|
|
|
|
return Mem[0][0]; // Must never happen;
|
|
}
|
|
set
|
|
{
|
|
if (Item < MemSize[0])
|
|
{
|
|
Mem[0][Item] = value;
|
|
return;
|
|
}
|
|
for (uint I = 1; I < MemSize.Length; I++)
|
|
{
|
|
if (Item < MemSize[I])
|
|
{
|
|
Mem[I][Item - MemSize[I - 1]] = value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
Mem[0][0] = value; // Must never happen;
|
|
}
|
|
}
|
|
|
|
// sharpcompress: added the following code
|
|
public void GetBuffer(size_t Item, out byte[] buf, out uint offset)
|
|
{
|
|
if (Item < MemSize[0])
|
|
{
|
|
//return Mem[0][Item];
|
|
buf = Mem[0];
|
|
offset = Item;
|
|
return;
|
|
}
|
|
for (uint I = 1; I < MemSize.Length; I++)
|
|
{
|
|
if (Item < MemSize[I])
|
|
{
|
|
//return Mem[I][Item-MemSize[I-1]];
|
|
buf = Mem[I];
|
|
offset = Item - MemSize[I - 1];
|
|
return;
|
|
}
|
|
}
|
|
//return Mem[0][0]; // Must never happen;
|
|
buf = Mem[0];
|
|
offset = 0;
|
|
return; // Must never happen;
|
|
}
|
|
|
|
public void CopyString(uint Length, uint Distance, ref size_t UnpPtr, size_t MaxWinMask)
|
|
{
|
|
var SrcPtr = UnpPtr - Distance;
|
|
while (Length-- > 0)
|
|
{
|
|
this[UnpPtr] = this[SrcPtr++ & MaxWinMask];
|
|
// We need to have masked UnpPtr after quit from loop, so it must not
|
|
// be replaced with '(*this)[UnpPtr++ & MaxWinMask]'
|
|
UnpPtr = (UnpPtr + 1) & MaxWinMask;
|
|
}
|
|
}
|
|
|
|
public void CopyData(byte[] Dest, size_t destOffset, size_t WinPos, size_t Size)
|
|
{
|
|
for (size_t I = 0; I < Size; I++)
|
|
{
|
|
Dest[destOffset + I] = this[WinPos + I];
|
|
}
|
|
}
|
|
|
|
public size_t GetBlockSize(size_t StartPos, size_t RequiredSize)
|
|
{
|
|
for (uint I = 0; I < MemSize.Length; I++)
|
|
{
|
|
if (StartPos < MemSize[I])
|
|
{
|
|
return Math.Min(MemSize[I] - StartPos, RequiredSize);
|
|
}
|
|
}
|
|
|
|
return 0; // Must never be here.
|
|
}
|
|
}
|