unrar5: pull in fast memset code

This commit is contained in:
coderb
2017-12-18 10:18:17 -05:00
parent 59e4383209
commit 122a732206
2 changed files with 52 additions and 5 deletions

View File

@@ -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,

View File

@@ -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>