diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs index 54309de4..334bde62 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs @@ -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, diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index a77360fb..8700d4af 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -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 MemsetDelegate = CreateMemsetDelegate(); + + private static Action 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)dynamicMethod.CreateDelegate(typeof(Action)); + } + + 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 + /// /// Fills the array with an specific value. ///