mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-23 15:34:34 +00:00
unrar5: pull in fast memset code
This commit is contained in:
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
|
||||
|
||||
@@ -73,7 +74,8 @@ void Init(size_t WinSize,bool Solid)
|
||||
// If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
|
||||
// will be 0 because of size_t overflow. Let's issue the memory error.
|
||||
if (WinSize==0)
|
||||
ErrHandler.MemoryError();
|
||||
//ErrHandler.MemoryError();
|
||||
throw new InvalidFormatException("invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)");
|
||||
|
||||
// Minimum window size must be at least twice more than maximum possible
|
||||
// size of filter block, which is 0x10000 in RAR now. If window size is
|
||||
@@ -98,22 +100,24 @@ void Init(size_t WinSize,bool Solid)
|
||||
|
||||
// We do not handle growth for existing fragmented window.
|
||||
if (Grow && Fragmented)
|
||||
throw std::bad_alloc();
|
||||
//throw std::bad_alloc();
|
||||
throw new InvalidFormatException("Grow && Fragmented");
|
||||
|
||||
byte *NewWindow=Fragmented ? null : (byte *)malloc(WinSize);
|
||||
byte[] NewWindow=Fragmented ? null : new byte[WinSize];
|
||||
|
||||
if (NewWindow==null)
|
||||
if (Grow || WinSize<0x1000000)
|
||||
{
|
||||
// We do not support growth for new fragmented window.
|
||||
// Also exclude RAR4 and small dictionaries.
|
||||
throw std::bad_alloc();
|
||||
//throw std::bad_alloc();
|
||||
throw new InvalidFormatException("Grow || WinSize<0x1000000");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Window!=null) // If allocated by preceding files.
|
||||
{
|
||||
free(Window);
|
||||
//free(Window);
|
||||
Window=null;
|
||||
}
|
||||
FragWindow.Init(WinSize);
|
||||
@@ -126,6 +130,7 @@ void Init(size_t WinSize,bool Solid)
|
||||
// RAR files, which may access unused areas of sliding dictionary.
|
||||
memset(NewWindow,0,WinSize);
|
||||
|
||||
|
||||
// If Window is not NULL, it means that window size has grown.
|
||||
// In solid streams we need to copy data to a new window in such case.
|
||||
// RAR archiving code does not allow it in solid streams now,
|
||||
|
||||
@@ -2,6 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NETCORE
|
||||
using SharpCompress.Buffers;
|
||||
#endif
|
||||
@@ -73,6 +76,45 @@ namespace SharpCompress
|
||||
}
|
||||
}
|
||||
|
||||
#if NET45
|
||||
// super fast memset, up to 40x faster than for loop on large arrays
|
||||
// see https://stackoverflow.com/questions/1897555/what-is-the-equivalent-of-memset-in-c
|
||||
private static readonly Action<IntPtr, byte, int> MemsetDelegate = CreateMemsetDelegate();
|
||||
|
||||
private static Action<IntPtr, byte, int> CreateMemsetDelegate() {
|
||||
var dynamicMethod = new DynamicMethod(
|
||||
"Memset",
|
||||
MethodAttributes.Public | MethodAttributes.Static,
|
||||
CallingConventions.Standard,
|
||||
null,
|
||||
new[] { typeof(IntPtr), typeof(byte), typeof(int) },
|
||||
typeof(Utility),
|
||||
true);
|
||||
var generator = dynamicMethod.GetILGenerator();
|
||||
generator.Emit(OpCodes.Ldarg_0);
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldarg_2);
|
||||
generator.Emit(OpCodes.Initblk);
|
||||
generator.Emit(OpCodes.Ret);
|
||||
return (Action<IntPtr, byte, int>)dynamicMethod.CreateDelegate(typeof(Action<IntPtr, byte, int>));
|
||||
}
|
||||
|
||||
public static void Memset(byte[] array, byte what, int length)
|
||||
{
|
||||
var gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
MemsetDelegate(gcHandle.AddrOfPinnedObject(), what, length);
|
||||
gcHandle.Free();
|
||||
}
|
||||
#else
|
||||
public static void Memset(byte[] array, byte what, int length)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = what;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Fills the array with an specific value.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user