mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Internal Fixes, etc. (#20)
* Start removing mixed usages
* Check for directories before opening
* Fix writing
* Kinda fix rebuild
* One more try
* Better internal handling
* Slighty fix a couple more things
* Update RVWorld Compress code to db7d750bba
* Fix build
Co-authored-by: Matt Nadareski <mnadareski@mparticle.com>
This commit is contained in:
@@ -4064,7 +4064,7 @@ namespace SabreTools.Library.DatFiles
|
||||
foreach (BaseFile entry in entries)
|
||||
{
|
||||
DatItem datItem = Utilities.GetDatItem(entry);
|
||||
usedInternally &= RebuildIndividualFile(datItem, file, outDir, date, inverse, outputFormat,
|
||||
usedInternally |= RebuildIndividualFile(datItem, file, outDir, date, inverse, outputFormat,
|
||||
romba, updateDat, !isTorrentGzip /* isZip */, headerToCheckAgainst);
|
||||
}
|
||||
}
|
||||
@@ -4094,8 +4094,8 @@ namespace SabreTools.Library.DatFiles
|
||||
private bool RebuildIndividualFile(DatItem datItem, string file, string outDir, bool date,
|
||||
bool inverse, OutputFormat outputFormat, bool romba, bool updateDat, bool? isZip, string headerToCheckAgainst)
|
||||
{
|
||||
// Set the output value
|
||||
bool rebuilt = true;
|
||||
// Set the initial output value
|
||||
bool rebuilt = false;
|
||||
|
||||
// If the DatItem is a Disk, force rebuilding to a folder except if TGZ
|
||||
if (datItem.ItemType == ItemType.Disk && outputFormat != OutputFormat.TorrentGzip)
|
||||
@@ -4152,14 +4152,12 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
File.Copy(file, outDir);
|
||||
rebuilt &= true;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
rebuilt = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return rebuilt;
|
||||
}
|
||||
|
||||
// Get a generic stream for the file
|
||||
@@ -4237,14 +4235,12 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
File.Copy(file, outDir);
|
||||
rebuilt &= true;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
rebuilt = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return rebuilt;
|
||||
}
|
||||
|
||||
// Get a generic stream for the file
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace SabreTools.Library.Data
|
||||
/// <summary>
|
||||
/// The current toolset version to be used by all child applications
|
||||
/// </summary>
|
||||
public readonly static string Version = "v1.0.0-" + Assembly.GetExecutingAssembly().GetLinkerTime().ToString("yyyy-MM-dd HH:mm:ss");
|
||||
public readonly static string Version = "v1.0.0-" + File.GetCreationTime(Assembly.GetExecutingAssembly().Location).ToString("yyyy-MM-dd HH:mm:ss");
|
||||
public const int HeaderHeight = 3;
|
||||
|
||||
#region 0-byte file constants
|
||||
|
||||
@@ -231,18 +231,6 @@ namespace SabreTools.Library.Data
|
||||
LastAccessTimePresent = 1 << 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zipfile special status
|
||||
/// </summary>
|
||||
/// <remarks>https://github.com/gjefferyes/RomVault/blob/5a93500001f0d068f32cf77a048950717507f733/ROMVault2/SupportedFiles/ZipEnums.cs</remarks>
|
||||
[Flags]
|
||||
public enum ZipStatus
|
||||
{
|
||||
None = 0x00,
|
||||
TorrentZip = 1 << 0,
|
||||
ExtraData = 1 << 1
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DatFile related
|
||||
|
||||
@@ -21,9 +21,6 @@ namespace SabreTools.Library.Data
|
||||
|
||||
private static Logger _logger = null;
|
||||
private static int _maxDegreeOfParallelism = System.Environment.ProcessorCount;
|
||||
private static string _exeName = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath;
|
||||
private static string _exeDir = Path.GetDirectoryName(_exeName);
|
||||
private static string _args = string.Join(" ", Environment.GetCommandLineArgs());
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -41,11 +38,13 @@ namespace SabreTools.Library.Data
|
||||
}
|
||||
set { _logger = value; }
|
||||
}
|
||||
|
||||
public static int MaxThreads
|
||||
{
|
||||
get { return _maxDegreeOfParallelism; }
|
||||
set { _maxDegreeOfParallelism = value; }
|
||||
}
|
||||
|
||||
public static ParallelOptions ParallelOptions
|
||||
{
|
||||
get
|
||||
@@ -56,26 +55,20 @@ namespace SabreTools.Library.Data
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static string ExeName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _exeName;
|
||||
}
|
||||
get { return new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath; }
|
||||
}
|
||||
|
||||
public static string ExeDir
|
||||
{
|
||||
get
|
||||
{
|
||||
return _exeDir;
|
||||
}
|
||||
get { return Path.GetDirectoryName(ExeName); }
|
||||
}
|
||||
|
||||
public static string CommandLineArgs
|
||||
{
|
||||
get
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
get { return string.Join(" ", Environment.GetCommandLineArgs()); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Compress.File
|
||||
|
||||
|
||||
|
||||
public void ZipFileAddDirectory()
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Compress
|
||||
string ZipFilename { get; }
|
||||
long TimeStamp { get; }
|
||||
|
||||
void ZipFileAddDirectory();
|
||||
void ZipFileAddZeroLengthFile();
|
||||
|
||||
ZipReturn ZipFileCreate(string newFilename);
|
||||
ZipReturn ZipFileCloseWriteStream(byte[] crc32);
|
||||
|
||||
194
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardDictionary.cs
vendored
Normal file
194
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardDictionary.cs
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// A Zstandard dictionary improves the compression ratio and speed on small data dramatically.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Zstandard dictionary is calculated with a high number of small sample data.
|
||||
/// Please refer to the Zstandard documentation for more details.
|
||||
/// </remarks>
|
||||
/// <seealso cref="System.IDisposable" />
|
||||
public sealed class ZstandardDictionary : IDisposable
|
||||
{
|
||||
private byte[] dictionary;
|
||||
private IntPtr ddict;
|
||||
private Dictionary<int, IntPtr> cdicts = new Dictionary<int, IntPtr>();
|
||||
private object lockObject = new object();
|
||||
private bool isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary raw data.</param>
|
||||
public ZstandardDictionary(byte[] dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryPath">The dictionary path.</param>
|
||||
public ZstandardDictionary(string dictionaryPath)
|
||||
{
|
||||
this.dictionary = File.ReadAllBytes(dictionaryPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryStream">The dictionary stream.</param>
|
||||
public ZstandardDictionary(Stream dictionaryStream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
dictionaryStream.CopyTo(memoryStream);
|
||||
this.dictionary = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
~ZstandardDictionary()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
private void Dispose(bool dispose)
|
||||
{
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
this.isDisposed = true;
|
||||
|
||||
if (this.ddict != IntPtr.Zero)
|
||||
{
|
||||
Interop.ZSTD_freeDDict(this.ddict);
|
||||
this.ddict = IntPtr.Zero;
|
||||
}
|
||||
|
||||
foreach (var kv in this.cdicts.ToList())
|
||||
{
|
||||
Interop.ZSTD_freeCDict(kv.Value);
|
||||
this.cdicts.Remove(kv.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compression dictionary for the specified compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.cdicts.TryGetValue(compressionLevel, out var cdict) == false)
|
||||
{
|
||||
this.cdicts[compressionLevel] = cdict = this.CreateCompressionDictionary(compressionLevel);
|
||||
}
|
||||
|
||||
return cdict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetDecompressionDictionary()
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.ddict == IntPtr.Zero)
|
||||
{
|
||||
this.ddict = this.CreateDecompressionDictionary();
|
||||
}
|
||||
|
||||
return this.ddict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new compression dictionary.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createCDict(dictBuffer, dictSize, compressionLevel);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateDecompressionDictionary()
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createDDict(dictBuffer, dictSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardInterop.cs
vendored
Normal file
143
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardInterop.cs
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
internal static class ZstandardInterop
|
||||
{
|
||||
static ZstandardInterop()
|
||||
{
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
{
|
||||
var root = Path.GetDirectoryName(typeof(ZstandardInterop).Assembly.Location);
|
||||
var path = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
var file = Path.Combine(root, path, "libzstd.dll");
|
||||
LoadLibraryEx(file, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class Buffer
|
||||
{
|
||||
public IntPtr Data = IntPtr.Zero;
|
||||
public UIntPtr Size = UIntPtr.Zero;
|
||||
public UIntPtr Position = UIntPtr.Zero;
|
||||
}
|
||||
|
||||
public static void ThrowIfError(UIntPtr code)
|
||||
{
|
||||
if (ZSTD_isError(code))
|
||||
{
|
||||
var errorPtr = ZSTD_getErrorName(code);
|
||||
var errorMsg = Marshal.PtrToStringAnsi(errorPtr);
|
||||
throw new IOException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[Flags]
|
||||
private enum LoadLibraryFlags : uint
|
||||
{
|
||||
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
|
||||
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
|
||||
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
|
||||
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
|
||||
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
|
||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
|
||||
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
|
||||
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
|
||||
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
|
||||
}
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint ZSTD_versionNumber();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int ZSTD_maxCLevel();
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream(IntPtr zcs, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCStream(IntPtr zcs);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_compressStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCDict(IntPtr dictBuffer, UIntPtr dictSize, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCDict(IntPtr cdict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream_usingCDict(IntPtr zcs, IntPtr cdict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_decompressStream(IntPtr zds, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDDict(IntPtr dictBuffer, UIntPtr dictSize);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDDict(IntPtr ddict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream_usingDDict(IntPtr zds, IntPtr ddict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_flushStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_endStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern bool ZSTD_isError(UIntPtr code);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr ZSTD_getErrorName(UIntPtr code);
|
||||
}
|
||||
}
|
||||
398
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardStream.cs
vendored
Normal file
398
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardStream.cs
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods and properties for compressing and decompressing streams by using the Zstandard algorithm.
|
||||
/// </summary>
|
||||
public class ZstandardStream : Stream
|
||||
{
|
||||
private Stream stream;
|
||||
private CompressionMode mode;
|
||||
private Boolean leaveOpen;
|
||||
private Boolean isClosed = false;
|
||||
private Boolean isDisposed = false;
|
||||
private Boolean isInitialized = false;
|
||||
|
||||
private IntPtr zstream;
|
||||
private uint zstreamInputSize;
|
||||
private uint zstreamOutputSize;
|
||||
|
||||
private byte[] data;
|
||||
private bool dataDepleted = false;
|
||||
private bool dataSkipRead = false;
|
||||
private int dataPosition = 0;
|
||||
private int dataSize = 0;
|
||||
|
||||
private long position = 0;
|
||||
|
||||
private Interop.Buffer outputBuffer = new Interop.Buffer();
|
||||
private Interop.Buffer inputBuffer = new Interop.Buffer();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression mode, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="mode">One of the enumeration values that indicates whether to compress or decompress the stream.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, CompressionMode mode, bool leaveOpen = false)
|
||||
{
|
||||
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
this.mode = mode;
|
||||
this.leaveOpen = leaveOpen;
|
||||
position = 0;
|
||||
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_CStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_CStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createCStream();
|
||||
this.data = new byte[(int)this.zstreamOutputSize];
|
||||
}
|
||||
|
||||
if (mode == CompressionMode.Decompress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_DStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_DStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createDStream();
|
||||
this.data = new byte[(int)this.zstreamInputSize];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression level, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, int compressionLevel, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
|
||||
{
|
||||
this.CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The version of the native Zstd library.
|
||||
/// </summary>
|
||||
public static Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
var version = (int)Interop.ZSTD_versionNumber();
|
||||
return new Version((version / 10000) % 100, (version / 100) % 100, version % 100);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum compression level supported by the native Zstd library.
|
||||
/// </summary>
|
||||
public static int MaxCompressionLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return Interop.ZSTD_maxCLevel();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression level to use, the default is 6.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To get the maximum compression level see <see cref="MaxCompressionLevel"/>.
|
||||
/// </remarks>
|
||||
public int CompressionLevel { get; set; } = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression dictionary tp use, the default is null.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The compression dictionary.
|
||||
/// </value>
|
||||
public ZstandardDictionary CompressionDictionary { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead => this.stream.CanRead && this.mode == CompressionMode.Decompress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite => this.stream.CanWrite && this.mode == CompressionMode.Compress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the stream.
|
||||
/// </summary>
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the current stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get => position;
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
if (!this.isClosed) ReleaseResources(flushStream: false);
|
||||
this.isDisposed = true;
|
||||
this.data = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (this.isClosed) return;
|
||||
|
||||
try
|
||||
{
|
||||
ReleaseResources(flushStream: true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isClosed = true;
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseResources(bool flushStream)
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (flushStream)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_endStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interop.ZSTD_freeCStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
else if (this.mode == CompressionMode.Decompress)
|
||||
{
|
||||
Interop.ZSTD_freeDStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanRead == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var length = 0;
|
||||
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initDStream(this.zstream)
|
||||
: Interop.ZSTD_initDStream_usingDDict(this.zstream, this.CompressionDictionary.GetDecompressionDictionary());
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = this.dataSize - this.dataPosition;
|
||||
|
||||
// read data from input stream
|
||||
if (inputSize <= 0 && !this.dataDepleted && !this.dataSkipRead)
|
||||
{
|
||||
this.dataSize = this.stream.Read(this.data, 0, (int)this.zstreamInputSize);
|
||||
this.dataDepleted = this.dataSize <= 0;
|
||||
this.dataPosition = 0;
|
||||
inputSize = this.dataDepleted ? 0 : this.dataSize;
|
||||
|
||||
// skip stream.Read until the internal buffer is depleted
|
||||
// avoids a Read timeout for applications that know the exact number of bytes in the stream
|
||||
this.dataSkipRead = true;
|
||||
}
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = inputSize <= 0 ? IntPtr.Zero : Marshal.UnsafeAddrOfPinnedArrayElement(this.data, this.dataPosition);
|
||||
this.inputBuffer.Size = inputSize <= 0 ? UIntPtr.Zero : new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.outputBuffer.Size = new UIntPtr((uint)count);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// decompress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// calculate progress in outputBuffer
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
if (outputBufferPosition == 0)
|
||||
{
|
||||
// the internal buffer is depleted, we're either done
|
||||
if (this.dataDepleted) break;
|
||||
|
||||
// or we need more bytes
|
||||
this.dataSkipRead = false;
|
||||
}
|
||||
length += outputBufferPosition;
|
||||
offset += outputBufferPosition;
|
||||
count -= outputBufferPosition;
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)inputBuffer.Position.ToUInt32();
|
||||
this.dataPosition += inputBufferPosition;
|
||||
}
|
||||
|
||||
position += length;
|
||||
return length;
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanWrite == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initCStream(this.zstream, this.CompressionLevel)
|
||||
: Interop.ZSTD_initCStream_usingCDict(this.zstream, this.CompressionDictionary.GetCompressionDictionary(this.CompressionLevel));
|
||||
|
||||
Interop.ThrowIfError(result);
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = Math.Min((uint)count, this.zstreamInputSize);
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.inputBuffer.Size = new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// compress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_compressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// write data to output stream
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)this.inputBuffer.Position.ToUInt32();
|
||||
offset += inputBufferPosition;
|
||||
count -= inputBufferPosition;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
byte[] tmpBuff = new byte[1024];
|
||||
long sizeToGo = offset;
|
||||
while (sizeToGo > 0)
|
||||
{
|
||||
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
|
||||
Read(tmpBuff, 0, sizenow);
|
||||
sizeToGo -= sizenow;
|
||||
}
|
||||
|
||||
position += offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
private void ProcessStream(Action<IntPtr, Interop.Buffer> outputAction)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
outputAction(this.zstream, this.outputBuffer);
|
||||
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,18 +26,24 @@ namespace Compress.SevenZip.Filters
|
||||
int end = offset + count - 5;
|
||||
int i;
|
||||
|
||||
for (i = offset; i <= end; ++i) {
|
||||
for (i = offset; i <= end; ++i)
|
||||
{
|
||||
if ((buffer[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prevPos = i - prevPos;
|
||||
if ((prevPos & ~3) != 0) { // (unsigned)prevPos > 3
|
||||
if ((prevPos & ~3) != 0)
|
||||
{ // (unsigned)prevPos > 3
|
||||
prevMask = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << (prevPos - 1)) & 7;
|
||||
if (prevMask != 0) {
|
||||
if (prevMask != 0)
|
||||
{
|
||||
if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte(
|
||||
buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) {
|
||||
buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]]))
|
||||
{
|
||||
prevPos = i;
|
||||
prevMask = (prevMask << 1) | 1;
|
||||
continue;
|
||||
@@ -47,13 +53,15 @@ namespace Compress.SevenZip.Filters
|
||||
|
||||
prevPos = i;
|
||||
|
||||
if (test86MSByte(buffer[i + 4])) {
|
||||
if (test86MSByte(buffer[i + 4]))
|
||||
{
|
||||
int src = buffer[i + 1]
|
||||
| (buffer[i + 2] << 8)
|
||||
| (buffer[i + 3] << 16)
|
||||
| (buffer[i + 4] << 24);
|
||||
int dest;
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
if (isEncoder)
|
||||
dest = src + (pos + i - offset);
|
||||
else
|
||||
@@ -74,7 +82,9 @@ namespace Compress.SevenZip.Filters
|
||||
buffer[i + 3] = (byte)(dest >> 16);
|
||||
buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1));
|
||||
i += 4;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.BZip2;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Compress.PPmd;
|
||||
using Compress.SevenZip.Filters;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public class SevenZ : ICompress
|
||||
public partial class SevenZ : ICompress
|
||||
{
|
||||
public static bool supportZstd
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static void TestForZstd()
|
||||
{
|
||||
supportZstd = RVIO.File.Exists("libzstd.dll");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class LocalFile
|
||||
{
|
||||
public string FileName;
|
||||
public ulong UncompressedSize;
|
||||
public bool IsDirectory;
|
||||
public byte[] CRC;
|
||||
public int StreamIndex;
|
||||
public ulong StreamOffset;
|
||||
public ZipReturn FileStatus = ZipReturn.ZipUntested;
|
||||
}
|
||||
|
||||
|
||||
private List<LocalFile> _localFiles = new List<LocalFile>();
|
||||
|
||||
private FileInfo _zipFileInfo;
|
||||
@@ -105,186 +122,13 @@ namespace Compress.SevenZip
|
||||
}
|
||||
|
||||
|
||||
public void ZipFileAddDirectory(string filename)
|
||||
{
|
||||
string fName = filename;
|
||||
if (fName.Substring(fName.Length - 1, 1) == @"/")
|
||||
fName = fName.Substring(0, fName.Length - 1);
|
||||
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = fName,
|
||||
UncompressedSize = 0,
|
||||
IsDirectory = true,
|
||||
StreamOffset = 0
|
||||
};
|
||||
_localFiles.Add(lf);
|
||||
}
|
||||
|
||||
private class LocalFile
|
||||
{
|
||||
public string FileName;
|
||||
public ulong UncompressedSize;
|
||||
public bool IsDirectory;
|
||||
public byte[] CRC;
|
||||
public int StreamIndex;
|
||||
public ulong StreamOffset;
|
||||
public ZipReturn FileStatus = ZipReturn.ZipUntested;
|
||||
}
|
||||
|
||||
#region open 7z files
|
||||
|
||||
public ZipReturn ZipFileOpen(string filename, long timestamp, bool readHeaders)
|
||||
{
|
||||
ZipFileClose();
|
||||
Debug.WriteLine(filename);
|
||||
#region open file stream
|
||||
|
||||
try
|
||||
{
|
||||
if (!RVIO.File.Exists(filename))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
_zipFileInfo = new FileInfo(filename);
|
||||
if ((timestamp != -1) && (_zipFileInfo.LastWriteTime != timestamp))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
int errorCode = FileStream.OpenFileRead(filename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpen(Stream inStream)
|
||||
{
|
||||
ZipFileClose();
|
||||
_zipFileInfo = null;
|
||||
_zipFs = inStream;
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
private ZipReturn ZipFileReadHeaders()
|
||||
{
|
||||
try
|
||||
{
|
||||
SignatureHeader signatureHeader = new SignatureHeader();
|
||||
if (!signatureHeader.Read(_zipFs))
|
||||
{
|
||||
return ZipReturn.ZipSignatureError;
|
||||
}
|
||||
|
||||
_baseOffset = _zipFs.Position;
|
||||
|
||||
//_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
//byte[] mainHeader = new byte[signatureHeader.NextHeaderSize];
|
||||
//_zipFs.Read(mainHeader, 0, (int)signatureHeader.NextHeaderSize);
|
||||
//if (!CRC.VerifyDigest(signatureHeader.NextHeaderCRC, mainHeader, 0, (uint)signatureHeader.NextHeaderSize))
|
||||
// return ZipReturn.Zip64EndOfCentralDirError;
|
||||
|
||||
if (signatureHeader.NextHeaderSize != 0)
|
||||
{
|
||||
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
ZipReturn zr = Header.ReadHeaderOrPackedHeader(_zipFs, _baseOffset, out _header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
_zipFs.Seek(_baseOffset + (long)(signatureHeader.NextHeaderOffset + signatureHeader.NextHeaderSize), SeekOrigin.Begin);
|
||||
|
||||
ZipStatus = ZipStatus.None;
|
||||
|
||||
ZipStatus |= IsRomVault7Z() ? ZipStatus.TrrntZip : ZipStatus.None;
|
||||
ZipStatus |= Istorrent7Z() ? ZipStatus.Trrnt7Zip : ZipStatus.None;
|
||||
PopulateLocalFiles(out _localFiles);
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorReadingFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void PopulateLocalFiles(out List<LocalFile> localFiles)
|
||||
{
|
||||
int emptyFileIndex = 0;
|
||||
int folderIndex = 0;
|
||||
int unpackedStreamsIndex = 0;
|
||||
ulong streamOffset = 0;
|
||||
localFiles = new List<LocalFile>();
|
||||
|
||||
if (_header == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
|
||||
{
|
||||
LocalFile lf = new LocalFile { FileName = _header.FileInfo.Names[i] };
|
||||
|
||||
if ((_header.FileInfo.EmptyStreamFlags == null) || !_header.FileInfo.EmptyStreamFlags[i])
|
||||
{
|
||||
lf.StreamIndex = folderIndex;
|
||||
lf.StreamOffset = streamOffset;
|
||||
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
|
||||
lf.CRC = Util.uinttobytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
|
||||
|
||||
streamOffset += lf.UncompressedSize;
|
||||
unpackedStreamsIndex++;
|
||||
|
||||
if (unpackedStreamsIndex >= _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo.Length)
|
||||
{
|
||||
folderIndex++;
|
||||
unpackedStreamsIndex = 0;
|
||||
streamOffset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lf.UncompressedSize = 0;
|
||||
lf.CRC = new byte[] { 0, 0, 0, 0 };
|
||||
lf.IsDirectory = (_header.FileInfo.EmptyFileFlags == null) || !_header.FileInfo.EmptyFileFlags[emptyFileIndex++];
|
||||
|
||||
if (lf.IsDirectory)
|
||||
{
|
||||
if (lf.FileName.Substring(lf.FileName.Length - 1, 1) != "/")
|
||||
{
|
||||
lf.FileName += "/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localFiles.Add(lf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ZipFileClose()
|
||||
@@ -312,6 +156,7 @@ namespace Compress.SevenZip
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
|
||||
private Header _header;
|
||||
|
||||
public StringBuilder HeaderReport()
|
||||
@@ -328,755 +173,5 @@ namespace Compress.SevenZip
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
// not finalized yet, so do not use
|
||||
private void WriteRomVault7Zip(BinaryWriter bw, ulong headerPos, ulong headerLength, uint headerCRC)
|
||||
{
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] RV7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
// RomVault 7Zip torrent header
|
||||
// 12 bytes : RomVault7Zip
|
||||
// 4 bytes : HeaderCRC
|
||||
// 8 bytes : HeaderPos
|
||||
// 8 bytes : HeaderLength
|
||||
|
||||
bw.Write(RV7Zid);
|
||||
bw.Write(headerCRC);
|
||||
bw.Write(headerPos);
|
||||
bw.Write(headerLength);
|
||||
|
||||
ZipStatus = ZipStatus.TrrntZip;
|
||||
}
|
||||
|
||||
|
||||
private bool IsRomVault7Z()
|
||||
{
|
||||
long length = _zipFs.Length;
|
||||
if (length < 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_zipFs.Seek(length - 32, SeekOrigin.Begin);
|
||||
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] rv7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
byte[] header = new byte[12];
|
||||
_zipFs.Read(header, 0, 12);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if (header[i] != rv7Zid[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint headerCRC;
|
||||
ulong headerOffset;
|
||||
ulong headerSize;
|
||||
using (BinaryReader br = new BinaryReader(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
headerCRC = br.ReadUInt32();
|
||||
headerOffset = br.ReadUInt64();
|
||||
headerSize = br.ReadUInt64();
|
||||
}
|
||||
|
||||
if ((ulong)length < headerOffset)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_zipFs.Seek((long)headerOffset, SeekOrigin.Begin);
|
||||
|
||||
byte[] mainHeader = new byte[headerSize];
|
||||
int bytesread = _zipFs.Read(mainHeader, 0, (int)headerSize);
|
||||
|
||||
return ((ulong)bytesread == headerSize) &&
|
||||
Utils.CRC.VerifyDigest(headerCRC, mainHeader, 0, (uint)headerSize);
|
||||
|
||||
}
|
||||
|
||||
private bool Istorrent7Z()
|
||||
{
|
||||
const int crcsz = 128;
|
||||
const int t7ZsigSize = 16 + 1 + 9 + 4 + 4;
|
||||
byte[] kSignature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
int kSignatureSize = kSignature.Length;
|
||||
const string sig = "\xa9\x9f\xd1\x57\x08\xa9\xd7\xea\x29\x64\xb2\x36\x1b\x83\x52\x33\x01torrent7z_0.9beta";
|
||||
byte[] t7Zid = Util.Enc.GetBytes(sig);
|
||||
int t7ZidSize = t7Zid.Length;
|
||||
|
||||
const int tmpbufsize = 256 + t7ZsigSize + 8 + 4;
|
||||
byte[] buffer = new byte[tmpbufsize];
|
||||
|
||||
// read fist 128 bytes, pad with zeros if less bytes
|
||||
int bufferPos = 0;
|
||||
_zipFs.Seek(0, SeekOrigin.Begin);
|
||||
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
|
||||
if (ar < crcsz)
|
||||
{
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
}
|
||||
bufferPos = crcsz;
|
||||
|
||||
long foffs = _zipFs.Length;
|
||||
int endReadLength = crcsz + t7ZsigSize + 4;
|
||||
foffs = foffs < endReadLength ? 0 : foffs - endReadLength;
|
||||
|
||||
_zipFs.Seek(foffs, SeekOrigin.Begin);
|
||||
|
||||
ar = _zipFs.Read(buffer, bufferPos, endReadLength);
|
||||
if (ar < endReadLength)
|
||||
{
|
||||
if (ar >= t7ZsigSize + 4)
|
||||
{
|
||||
ar -= t7ZsigSize + 4;
|
||||
}
|
||||
if (ar < kSignatureSize)
|
||||
{
|
||||
ar = kSignatureSize;
|
||||
}
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
|
||||
}
|
||||
|
||||
foffs = _zipFs.Length;
|
||||
foffs -= t7ZsigSize + 4;
|
||||
|
||||
//memcpy(buffer, crcsz * 2, &foffs, 8);
|
||||
buffer[crcsz * 2 + 0] = (byte)((foffs >> 0) & 0xff);
|
||||
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
||||
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
||||
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
||||
buffer[crcsz * 2 + 4] = 0;
|
||||
buffer[crcsz * 2 + 5] = 0;
|
||||
buffer[crcsz * 2 + 6] = 0;
|
||||
buffer[crcsz * 2 + 7] = 0;
|
||||
|
||||
if (Util.memcmp(buffer, 0, kSignature, kSignatureSize))
|
||||
{
|
||||
t7Zid[16] = buffer[crcsz * 2 + 4 + 8 + 16];
|
||||
if (Util.memcmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
|
||||
{
|
||||
uint inCrc32 = (uint)(buffer[crcsz * 2 + 8 + 0] +
|
||||
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
||||
(buffer[crcsz * 2 + 8 + 2] << 16) +
|
||||
(buffer[crcsz * 2 + 8 + 3] << 24));
|
||||
|
||||
buffer[crcsz * 2 + 8 + 0] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 1] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 3] = 0xff;
|
||||
|
||||
uint calcCrc32 = Utils.CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
|
||||
|
||||
if (inCrc32 == calcCrc32)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region read 7z file
|
||||
|
||||
private int _streamIndex = -1;
|
||||
private Stream _stream;
|
||||
|
||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
|
||||
{
|
||||
Debug.WriteLine("Opening File " + _localFiles[index].FileName);
|
||||
stream = null;
|
||||
unCompressedSize = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.OpenRead)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
if (IsDirectory(index))
|
||||
{
|
||||
return ZipReturn.ZipTryingToAccessADirectory;
|
||||
}
|
||||
|
||||
unCompressedSize = _localFiles[index].UncompressedSize;
|
||||
int thisStreamIndex = _localFiles[index].StreamIndex;
|
||||
ulong streamOffset = _localFiles[index].StreamOffset;
|
||||
|
||||
if ((thisStreamIndex == _streamIndex) && (streamOffset >= (ulong)_stream.Position))
|
||||
{
|
||||
stream = _stream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset - _stream.Position, SeekOrigin.Current);
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
ZipFileCloseReadStream();
|
||||
_streamIndex = thisStreamIndex;
|
||||
|
||||
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
// first make the List of Decompressors streams
|
||||
int codersNeeded = folder.Coders.Length;
|
||||
|
||||
List<InStreamSourceInfo> allInputStreams = new List<InStreamSourceInfo>();
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
folder.Coders[i].DecoderStream = null;
|
||||
allInputStreams.AddRange(folder.Coders[i].InputStreamsSourceInfo);
|
||||
}
|
||||
|
||||
// now use the binding pairs to links the outputs to the inputs
|
||||
int bindPairsCount = folder.BindPairs.Length;
|
||||
for (int i = 0; i < bindPairsCount; i++)
|
||||
{
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamSource = InStreamSource.CompStreamOutput;
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamIndex = folder.BindPairs[i].OutIndex;
|
||||
folder.Coders[(int)folder.BindPairs[i].OutIndex].OutputUsedInternally = true;
|
||||
}
|
||||
|
||||
// next use the stream indises to connect the remaining input streams from the sourcefile
|
||||
int packedStreamsCount = folder.PackedStreamIndices.Length;
|
||||
for (int i = 0; i < packedStreamsCount; i++)
|
||||
{
|
||||
ulong packedStreamIndex = (ulong)i + folder.PackedStreamIndexBase;
|
||||
|
||||
// create and open the source file stream if needed
|
||||
if (_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream == null)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream = CloneStream(_zipFs);
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream.Seek(
|
||||
_baseOffset + (long)_header.StreamsInfo.PackedStreams[packedStreamIndex].StreamPosition, SeekOrigin.Begin);
|
||||
|
||||
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamSource = InStreamSource.FileStream;
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
|
||||
}
|
||||
|
||||
List<Stream> inputCoders = new List<Stream>();
|
||||
|
||||
bool allCodersComplete = false;
|
||||
while (!allCodersComplete)
|
||||
{
|
||||
allCodersComplete = true;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
|
||||
// check is decoder already processed
|
||||
if (coder.DecoderStream != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
inputCoders.Clear();
|
||||
for (int j = 0; j < (int)coder.NumInStreams; j++)
|
||||
{
|
||||
if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.FileStream)
|
||||
{
|
||||
inputCoders.Add(_header.StreamsInfo.PackedStreams[coder.InputStreamsSourceInfo[j].InStreamIndex].PackedStream);
|
||||
}
|
||||
else if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.CompStreamOutput)
|
||||
{
|
||||
if (folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
inputCoders.Add(folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown input type so error
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputCoders.Count == (int)coder.NumInStreams)
|
||||
{
|
||||
// all inputs streams are available to make the decoder stream
|
||||
switch (coder.DecoderType)
|
||||
{
|
||||
case DecompressType.Stored:
|
||||
coder.DecoderStream = inputCoders[0];
|
||||
break;
|
||||
case DecompressType.Delta:
|
||||
coder.DecoderStream = new Delta(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA2:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.PPMd:
|
||||
coder.DecoderStream = new PpmdStream(new PpmdProperties(folder.Coders[i].Properties), inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BZip2:
|
||||
coder.DecoderStream = new CBZip2InputStream(inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BCJ:
|
||||
coder.DecoderStream = new BCJFilter(false, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.BCJ2:
|
||||
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
|
||||
break;
|
||||
default:
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
// if skipped a coder need to loop round again
|
||||
if (coder.DecoderStream == null)
|
||||
{
|
||||
allCodersComplete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// find the final output stream and return it.
|
||||
int outputStream = -1;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
if (!coder.OutputUsedInternally)
|
||||
{
|
||||
outputStream = i;
|
||||
}
|
||||
}
|
||||
|
||||
stream = folder.Coders[outputStream].DecoderStream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
||||
|
||||
_stream = stream;
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Stream CloneStream(Stream s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case System.IO.FileStream _:
|
||||
int errorCode = FileStream.OpenFileRead(ZipFilename, out Stream streamOut);
|
||||
return errorCode != 0 ? null : streamOut;
|
||||
|
||||
case MemoryStream memStream:
|
||||
long pos = memStream.Position;
|
||||
memStream.Position = 0;
|
||||
byte[] newStream = new byte[memStream.Length];
|
||||
memStream.Read(newStream, 0, (int)memStream.Length);
|
||||
MemoryStream ret = new MemoryStream(newStream, false);
|
||||
memStream.Position = pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseReadStream()
|
||||
{
|
||||
if (_streamIndex != -1)
|
||||
{
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
foreach (Coder c in folder.Coders)
|
||||
{
|
||||
Stream ds = c?.DecoderStream;
|
||||
if (ds == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ds.Close();
|
||||
ds.Dispose();
|
||||
c.DecoderStream = null;
|
||||
}
|
||||
}
|
||||
_streamIndex = -1;
|
||||
|
||||
if (_header?.StreamsInfo != null)
|
||||
{
|
||||
foreach (PackedStreamInfo psi in _header.StreamsInfo.PackedStreams)
|
||||
{
|
||||
if (psi?.PackedStream == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
psi.PackedStream.Close();
|
||||
psi.PackedStream.Dispose();
|
||||
psi.PackedStream = null;
|
||||
}
|
||||
}
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region write 7z File
|
||||
|
||||
private LzmaStream _lzmaStream;
|
||||
private ulong _packStreamStart;
|
||||
private ulong _packStreamSize;
|
||||
private ulong _unpackedStreamSize;
|
||||
private byte[] _codeMSbytes;
|
||||
|
||||
|
||||
public void ZipFileAddDirectory()
|
||||
{
|
||||
// do nothing here for 7zip
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename)
|
||||
{
|
||||
return ZipFileCreate(newFilename, true);
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCreateFromUncompressedSize(string newFilename, ulong unCompressedSize)
|
||||
{
|
||||
return ZipFileCreate(newFilename,true, GetDictionarySizeFromUncompressedSize(unCompressedSize));
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename, bool compressOutput, int dictionarySize = 1 << 24, int numFastBytes = 64)
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
DirUtil.CreateDirForFile(newFilename);
|
||||
_zipFileInfo = new FileInfo(newFilename);
|
||||
|
||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
|
||||
_signatureHeader = new SignatureHeader();
|
||||
_header = new Header();
|
||||
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
_signatureHeader.Write(bw);
|
||||
}
|
||||
|
||||
_compressed = compressOutput;
|
||||
|
||||
_unpackedStreamSize = 0;
|
||||
if (_compressed)
|
||||
{
|
||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, dictionarySize, numFastBytes);
|
||||
_lzmaStream = new LzmaStream(ep, false, _zipFs);
|
||||
_codeMSbytes = _lzmaStream.Properties;
|
||||
_packStreamStart = (ulong)_zipFs.Position;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream)
|
||||
{
|
||||
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
|
||||
}
|
||||
|
||||
private ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
|
||||
{
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = filename,
|
||||
UncompressedSize = uncompressedSize,
|
||||
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
|
||||
};
|
||||
|
||||
_unpackedStreamSize += uncompressedSize;
|
||||
|
||||
_localFiles.Add(lf);
|
||||
stream = _compressed ? _lzmaStream : _zipFs;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
||||
{
|
||||
_localFiles[_localFiles.Count - 1].CRC = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
private void CloseWriting7Zip()
|
||||
{
|
||||
if (_compressed)
|
||||
{
|
||||
_lzmaStream.Close();
|
||||
}
|
||||
|
||||
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
|
||||
|
||||
Create7ZStructure();
|
||||
|
||||
byte[] newHeaderByte;
|
||||
using (Stream headerMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
||||
{
|
||||
_header.WriteHeader(headerBw);
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
}
|
||||
}
|
||||
|
||||
uint mainHeaderCRC = Utils.CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
|
||||
ulong headerpos = (ulong)_zipFs.Position;
|
||||
_zipFs.Write(newHeaderByte,0,newHeaderByte.Length);
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
_signatureHeader.WriteFinal(bw, headerpos, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
WriteRomVault7Zip(bw, headerpos, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
}
|
||||
_zipFs.Flush();
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void Create7ZStructure()
|
||||
{
|
||||
int fileCount = _localFiles.Count;
|
||||
|
||||
//FileInfo
|
||||
_header.FileInfo = new Structure.FileInfo
|
||||
{
|
||||
Names = new string[fileCount]
|
||||
};
|
||||
|
||||
ulong emptyStreamCount = 0;
|
||||
ulong emptyFileCount = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
_header.FileInfo.Names[i] = _localFiles[i].FileName;
|
||||
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_localFiles[i].IsDirectory)
|
||||
{
|
||||
emptyFileCount += 1;
|
||||
}
|
||||
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags = null;
|
||||
_header.FileInfo.EmptyFileFlags = null;
|
||||
_header.FileInfo.Attributes = null;
|
||||
|
||||
if (emptyStreamCount > 0)
|
||||
{
|
||||
if (emptyStreamCount != emptyFileCount) //then we found directories and need to set the attributes
|
||||
{
|
||||
_header.FileInfo.Attributes = new uint[fileCount];
|
||||
}
|
||||
|
||||
if (emptyFileCount > 0)
|
||||
{
|
||||
_header.FileInfo.EmptyFileFlags = new bool[emptyStreamCount];
|
||||
}
|
||||
|
||||
emptyStreamCount = 0;
|
||||
_header.FileInfo.EmptyStreamFlags = new bool[fileCount];
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_localFiles[i].IsDirectory)
|
||||
{
|
||||
if (_header.FileInfo.Attributes != null)
|
||||
_header.FileInfo.Attributes[i] = 0x10; // set attributes to directory
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_header.FileInfo.EmptyFileFlags != null)
|
||||
_header.FileInfo.EmptyFileFlags[emptyStreamCount] = true; // set empty file flag
|
||||
}
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags[i] = true;
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//StreamsInfo
|
||||
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
||||
|
||||
//StreamsInfo.PackedStreamsInfo
|
||||
if (_compressed)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
||||
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
||||
}
|
||||
}
|
||||
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
||||
|
||||
if (_compressed)
|
||||
{
|
||||
//StreamsInfo.Folders
|
||||
_header.StreamsInfo.Folders = new Folder[1];
|
||||
|
||||
Folder folder = new Folder { Coders = new Coder[1] };
|
||||
|
||||
//StreamsInfo.Folders.Coder
|
||||
// flags 0x23
|
||||
folder.Coders[0] = new Coder
|
||||
{
|
||||
Method = new byte[] { 3, 1, 1 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = _codeMSbytes
|
||||
};
|
||||
folder.BindPairs = null;
|
||||
folder.PackedStreamIndices = new[] { (ulong)0 };
|
||||
folder.UnpackedStreamSizes = new[] { _unpackedStreamSize };
|
||||
folder.UnpackCRC = null;
|
||||
|
||||
folder.UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
||||
{
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
};
|
||||
folder.UnpackedStreamInfo[fileIndex++] = unpackedStreamInfo;
|
||||
}
|
||||
_header.StreamsInfo.Folders[0] = folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.Folders = new Folder[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Folder folder = new Folder { Coders = new Coder[1] };
|
||||
|
||||
//StreamsInfo.Folders.Coder
|
||||
// flags 0x01
|
||||
folder.Coders[0] = new Coder
|
||||
{
|
||||
Method = new byte[] { 0 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = null
|
||||
};
|
||||
|
||||
folder.BindPairs = null;
|
||||
folder.PackedStreamIndices = new[] { (ulong)i };
|
||||
folder.UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize };
|
||||
folder.UnpackCRC = null;
|
||||
|
||||
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
|
||||
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
||||
{
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
};
|
||||
folder.UnpackedStreamInfo[0] = unpackedStreamInfo;
|
||||
|
||||
_header.StreamsInfo.Folders[fileIndex++] = folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private static readonly int[] DictionarySizes =
|
||||
{
|
||||
0x10000,
|
||||
0x18000,
|
||||
0x20000,
|
||||
0x30000,
|
||||
0x40000,
|
||||
0x60000,
|
||||
0x80000,
|
||||
0xc0000,
|
||||
|
||||
0x100000,
|
||||
0x180000,
|
||||
0x200000,
|
||||
0x300000,
|
||||
0x400000,
|
||||
0x600000,
|
||||
0x800000,
|
||||
0xc00000,
|
||||
|
||||
0x1000000,
|
||||
0x1800000,
|
||||
0x2000000,
|
||||
0x3000000,
|
||||
0x4000000,
|
||||
0x6000000
|
||||
};
|
||||
|
||||
|
||||
private static int GetDictionarySizeFromUncompressedSize(ulong unCompressedSize)
|
||||
{
|
||||
foreach (int v in DictionarySizes)
|
||||
{
|
||||
if ((ulong)v >= unCompressedSize)
|
||||
return v;
|
||||
}
|
||||
|
||||
return DictionarySizes[DictionarySizes.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
170
SabreTools.Library/External/Compress/SevenZip/SevenZipOpen.cs
vendored
Normal file
170
SabreTools.Library/External/Compress/SevenZip/SevenZipOpen.cs
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
public ZipReturn ZipFileOpen(string filename, long timestamp, bool readHeaders)
|
||||
{
|
||||
ZipFileClose();
|
||||
Debug.WriteLine(filename);
|
||||
#region open file stream
|
||||
|
||||
try
|
||||
{
|
||||
if (!RVIO.File.Exists(filename))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
_zipFileInfo = new FileInfo(filename);
|
||||
if ((timestamp != -1) && (_zipFileInfo.LastWriteTime != timestamp))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
int errorCode = FileStream.OpenFileRead(filename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileOpen(Stream inStream)
|
||||
{
|
||||
ZipFileClose();
|
||||
_zipFileInfo = null;
|
||||
_zipFs = inStream;
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ZipReturn ZipFileReadHeaders()
|
||||
{
|
||||
try
|
||||
{
|
||||
SignatureHeader signatureHeader = new SignatureHeader();
|
||||
if (!signatureHeader.Read(_zipFs))
|
||||
{
|
||||
return ZipReturn.ZipSignatureError;
|
||||
}
|
||||
|
||||
_baseOffset = _zipFs.Position;
|
||||
|
||||
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
byte[] mainHeader = new byte[signatureHeader.NextHeaderSize];
|
||||
_zipFs.Read(mainHeader, 0, (int)signatureHeader.NextHeaderSize);
|
||||
if (!CRC.VerifyDigest(signatureHeader.NextHeaderCRC, mainHeader, 0, (uint)signatureHeader.NextHeaderSize))
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
|
||||
if (signatureHeader.NextHeaderSize != 0)
|
||||
{
|
||||
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
ZipReturn zr = Header.ReadHeaderOrPackedHeader(_zipFs, _baseOffset, out _header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ZipStatus = ZipStatus.None;
|
||||
ZipStatus |= IsRomVault7Z(_baseOffset, signatureHeader.NextHeaderOffset, signatureHeader.NextHeaderSize, signatureHeader.NextHeaderCRC) ? ZipStatus.TrrntZip : ZipStatus.None;
|
||||
|
||||
_zipFs.Seek(_baseOffset + (long)(signatureHeader.NextHeaderOffset + signatureHeader.NextHeaderSize), SeekOrigin.Begin);
|
||||
ZipStatus |= Istorrent7Z() ? ZipStatus.Trrnt7Zip : ZipStatus.None;
|
||||
PopulateLocalFiles(out _localFiles);
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorReadingFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void PopulateLocalFiles(out List<LocalFile> localFiles)
|
||||
{
|
||||
int emptyFileIndex = 0;
|
||||
int folderIndex = 0;
|
||||
int unpackedStreamsIndex = 0;
|
||||
ulong streamOffset = 0;
|
||||
localFiles = new List<LocalFile>();
|
||||
|
||||
if (_header == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
|
||||
{
|
||||
LocalFile lf = new LocalFile { FileName = _header.FileInfo.Names[i] };
|
||||
|
||||
if ((_header.FileInfo.EmptyStreamFlags == null) || !_header.FileInfo.EmptyStreamFlags[i])
|
||||
{
|
||||
lf.StreamIndex = folderIndex;
|
||||
lf.StreamOffset = streamOffset;
|
||||
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
|
||||
lf.CRC = Util.uinttobytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
|
||||
|
||||
streamOffset += lf.UncompressedSize;
|
||||
unpackedStreamsIndex++;
|
||||
|
||||
if (unpackedStreamsIndex >= _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo.Length)
|
||||
{
|
||||
folderIndex++;
|
||||
unpackedStreamsIndex = 0;
|
||||
streamOffset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lf.UncompressedSize = 0;
|
||||
lf.CRC = new byte[] { 0, 0, 0, 0 };
|
||||
lf.IsDirectory = (_header.FileInfo.EmptyFileFlags == null) || !_header.FileInfo.EmptyFileFlags[emptyFileIndex++];
|
||||
|
||||
if (lf.IsDirectory)
|
||||
{
|
||||
if (lf.FileName.Substring(lf.FileName.Length - 1, 1) != "/")
|
||||
{
|
||||
lf.FileName += "/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localFiles.Add(lf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
260
SabreTools.Library/External/Compress/SevenZip/SevenZipOpenRead.cs
vendored
Normal file
260
SabreTools.Library/External/Compress/SevenZip/SevenZipOpenRead.cs
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using Compress.SevenZip.Compress.BZip2;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Compress.PPmd;
|
||||
using Compress.SevenZip.Filters;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Zstandard.Net;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private int _streamIndex = -1;
|
||||
private Stream _stream;
|
||||
|
||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
|
||||
{
|
||||
Debug.WriteLine("Opening File " + _localFiles[index].FileName);
|
||||
stream = null;
|
||||
unCompressedSize = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.OpenRead)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
if (IsDirectory(index))
|
||||
{
|
||||
return ZipReturn.ZipTryingToAccessADirectory;
|
||||
}
|
||||
|
||||
unCompressedSize = _localFiles[index].UncompressedSize;
|
||||
int thisStreamIndex = _localFiles[index].StreamIndex;
|
||||
ulong streamOffset = _localFiles[index].StreamOffset;
|
||||
|
||||
if ((thisStreamIndex == _streamIndex) && (streamOffset >= (ulong)_stream.Position))
|
||||
{
|
||||
stream = _stream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset - _stream.Position, SeekOrigin.Current);
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
ZipFileCloseReadStream();
|
||||
_streamIndex = thisStreamIndex;
|
||||
|
||||
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
// first make the List of Decompressors streams
|
||||
int codersNeeded = folder.Coders.Length;
|
||||
|
||||
List<InStreamSourceInfo> allInputStreams = new List<InStreamSourceInfo>();
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
folder.Coders[i].DecoderStream = null;
|
||||
allInputStreams.AddRange(folder.Coders[i].InputStreamsSourceInfo);
|
||||
}
|
||||
|
||||
// now use the binding pairs to links the outputs to the inputs
|
||||
int bindPairsCount = folder.BindPairs.Length;
|
||||
for (int i = 0; i < bindPairsCount; i++)
|
||||
{
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamSource = InStreamSource.CompStreamOutput;
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamIndex = folder.BindPairs[i].OutIndex;
|
||||
folder.Coders[(int)folder.BindPairs[i].OutIndex].OutputUsedInternally = true;
|
||||
}
|
||||
|
||||
// next use the stream indises to connect the remaining input streams from the sourcefile
|
||||
int packedStreamsCount = folder.PackedStreamIndices.Length;
|
||||
for (int i = 0; i < packedStreamsCount; i++)
|
||||
{
|
||||
ulong packedStreamIndex = (ulong)i + folder.PackedStreamIndexBase;
|
||||
|
||||
// create and open the source file stream if needed
|
||||
if (_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream == null)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream = CloneStream(_zipFs);
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream.Seek(
|
||||
_baseOffset + (long)_header.StreamsInfo.PackedStreams[packedStreamIndex].StreamPosition, SeekOrigin.Begin);
|
||||
|
||||
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamSource = InStreamSource.FileStream;
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
|
||||
}
|
||||
|
||||
List<Stream> inputCoders = new List<Stream>();
|
||||
|
||||
bool allCodersComplete = false;
|
||||
while (!allCodersComplete)
|
||||
{
|
||||
allCodersComplete = true;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
|
||||
// check is decoder already processed
|
||||
if (coder.DecoderStream != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
inputCoders.Clear();
|
||||
for (int j = 0; j < (int)coder.NumInStreams; j++)
|
||||
{
|
||||
if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.FileStream)
|
||||
{
|
||||
inputCoders.Add(_header.StreamsInfo.PackedStreams[coder.InputStreamsSourceInfo[j].InStreamIndex].PackedStream);
|
||||
}
|
||||
else if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.CompStreamOutput)
|
||||
{
|
||||
if (folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
inputCoders.Add(folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown input type so error
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputCoders.Count == (int)coder.NumInStreams)
|
||||
{
|
||||
// all inputs streams are available to make the decoder stream
|
||||
switch (coder.DecoderType)
|
||||
{
|
||||
case DecompressType.Stored:
|
||||
coder.DecoderStream = inputCoders[0];
|
||||
break;
|
||||
case DecompressType.Delta:
|
||||
coder.DecoderStream = new Delta(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA2:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.PPMd:
|
||||
coder.DecoderStream = new PpmdStream(new PpmdProperties(folder.Coders[i].Properties), inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BZip2:
|
||||
coder.DecoderStream = new CBZip2InputStream(inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BCJ:
|
||||
coder.DecoderStream = new BCJFilter(false, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.BCJ2:
|
||||
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
|
||||
break;
|
||||
case DecompressType.ZSTD:
|
||||
coder.DecoderStream = new ZstandardStream(inputCoders[0], CompressionMode.Decompress, true);
|
||||
break;
|
||||
default:
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
// if skipped a coder need to loop round again
|
||||
if (coder.DecoderStream == null)
|
||||
{
|
||||
allCodersComplete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// find the final output stream and return it.
|
||||
int outputStream = -1;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
if (!coder.OutputUsedInternally)
|
||||
{
|
||||
outputStream = i;
|
||||
}
|
||||
}
|
||||
|
||||
stream = folder.Coders[outputStream].DecoderStream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
||||
|
||||
_stream = stream;
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Stream CloneStream(Stream s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case System.IO.FileStream _:
|
||||
int errorCode = FileStream.OpenFileRead(ZipFilename, out Stream streamOut);
|
||||
return errorCode != 0 ? null : streamOut;
|
||||
|
||||
case MemoryStream memStream:
|
||||
long pos = memStream.Position;
|
||||
memStream.Position = 0;
|
||||
byte[] newStream = new byte[memStream.Length];
|
||||
memStream.Read(newStream, 0, (int)memStream.Length);
|
||||
MemoryStream ret = new MemoryStream(newStream, false);
|
||||
memStream.Position = pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseReadStream()
|
||||
{
|
||||
if (_streamIndex != -1)
|
||||
{
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
foreach (Coder c in folder.Coders)
|
||||
{
|
||||
Stream ds = c?.DecoderStream;
|
||||
if (ds == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ds.Close();
|
||||
ds.Dispose();
|
||||
c.DecoderStream = null;
|
||||
}
|
||||
}
|
||||
_streamIndex = -1;
|
||||
|
||||
if (_header?.StreamsInfo != null)
|
||||
{
|
||||
foreach (PackedStreamInfo psi in _header.StreamsInfo.PackedStreams)
|
||||
{
|
||||
if (psi?.PackedStream == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
psi.PackedStream.Close();
|
||||
psi.PackedStream.Dispose();
|
||||
psi.PackedStream = null;
|
||||
}
|
||||
}
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
157
SabreTools.Library/External/Compress/SevenZip/SevenZipTorrent.cs
vendored
Normal file
157
SabreTools.Library/External/Compress/SevenZip/SevenZipTorrent.cs
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
// not finalized yet, so do not use
|
||||
private void WriteRomVault7Zip(BinaryWriter bw, ulong headerPos, ulong headerLength, uint headerCRC)
|
||||
{
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] RV7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
// RomVault 7Zip torrent header
|
||||
// 12 bytes : RomVault7Zip
|
||||
// 4 bytes : HeaderCRC
|
||||
// 8 bytes : HeaderPos
|
||||
// 8 bytes : HeaderLength
|
||||
|
||||
bw.Write(RV7Zid);
|
||||
bw.Write(headerCRC);
|
||||
bw.Write(headerPos);
|
||||
bw.Write(headerLength);
|
||||
|
||||
ZipStatus = ZipStatus.TrrntZip;
|
||||
}
|
||||
|
||||
private bool IsRomVault7Z(long testBaseOffset, ulong testHeaderPos, ulong testHeaderLength, uint testHeaderCRC)
|
||||
{
|
||||
long length = _zipFs.Length;
|
||||
if (length < 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_zipFs.Seek(_baseOffset + (long)testHeaderPos - 32, SeekOrigin.Begin);
|
||||
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] rv7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
byte[] header = new byte[12];
|
||||
_zipFs.Read(header, 0, 12);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if (header[i] != rv7Zid[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint headerCRC;
|
||||
ulong headerOffset; // is location of header in file
|
||||
ulong headerSize;
|
||||
using (BinaryReader br = new BinaryReader(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
headerCRC = br.ReadUInt32();
|
||||
headerOffset = br.ReadUInt64();
|
||||
headerSize = br.ReadUInt64();
|
||||
}
|
||||
|
||||
if (headerCRC != testHeaderCRC)
|
||||
return false;
|
||||
|
||||
if (headerOffset != testHeaderPos + (ulong)testBaseOffset)
|
||||
return false;
|
||||
|
||||
return headerSize == testHeaderLength;
|
||||
}
|
||||
private bool Istorrent7Z()
|
||||
{
|
||||
const int crcsz = 128;
|
||||
const int t7ZsigSize = 16 + 1 + 9 + 4 + 4;
|
||||
byte[] kSignature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
int kSignatureSize = kSignature.Length;
|
||||
const string sig = "\xa9\x9f\xd1\x57\x08\xa9\xd7\xea\x29\x64\xb2\x36\x1b\x83\x52\x33\x01torrent7z_0.9beta";
|
||||
byte[] t7Zid = Util.Enc.GetBytes(sig);
|
||||
int t7ZidSize = t7Zid.Length;
|
||||
|
||||
const int tmpbufsize = 256 + t7ZsigSize + 8 + 4;
|
||||
byte[] buffer = new byte[tmpbufsize];
|
||||
|
||||
// read fist 128 bytes, pad with zeros if less bytes
|
||||
int bufferPos = 0;
|
||||
_zipFs.Seek(0, SeekOrigin.Begin);
|
||||
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
|
||||
if (ar < crcsz)
|
||||
{
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
}
|
||||
bufferPos = crcsz;
|
||||
|
||||
long foffs = _zipFs.Length;
|
||||
int endReadLength = crcsz + t7ZsigSize + 4;
|
||||
foffs = foffs < endReadLength ? 0 : foffs - endReadLength;
|
||||
|
||||
_zipFs.Seek(foffs, SeekOrigin.Begin);
|
||||
|
||||
ar = _zipFs.Read(buffer, bufferPos, endReadLength);
|
||||
if (ar < endReadLength)
|
||||
{
|
||||
if (ar >= t7ZsigSize + 4)
|
||||
{
|
||||
ar -= t7ZsigSize + 4;
|
||||
}
|
||||
if (ar < kSignatureSize)
|
||||
{
|
||||
ar = kSignatureSize;
|
||||
}
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
|
||||
}
|
||||
|
||||
foffs = _zipFs.Length;
|
||||
foffs -= t7ZsigSize + 4;
|
||||
|
||||
//memcpy(buffer, crcsz * 2, &foffs, 8);
|
||||
buffer[crcsz * 2 + 0] = (byte)((foffs >> 0) & 0xff);
|
||||
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
||||
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
||||
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
||||
buffer[crcsz * 2 + 4] = 0;
|
||||
buffer[crcsz * 2 + 5] = 0;
|
||||
buffer[crcsz * 2 + 6] = 0;
|
||||
buffer[crcsz * 2 + 7] = 0;
|
||||
|
||||
if (Util.memcmp(buffer, 0, kSignature, kSignatureSize))
|
||||
{
|
||||
t7Zid[16] = buffer[crcsz * 2 + 4 + 8 + 16];
|
||||
if (Util.memcmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
|
||||
{
|
||||
uint inCrc32 = (uint)(buffer[crcsz * 2 + 8 + 0] +
|
||||
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
||||
(buffer[crcsz * 2 + 8 + 2] << 16) +
|
||||
(buffer[crcsz * 2 + 8 + 3] << 24));
|
||||
|
||||
buffer[crcsz * 2 + 8 + 0] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 1] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 3] = 0xff;
|
||||
|
||||
uint calcCrc32 = Utils.CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
|
||||
|
||||
if (inCrc32 == calcCrc32)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
176
SabreTools.Library/External/Compress/SevenZip/SevenZipWrite.cs
vendored
Normal file
176
SabreTools.Library/External/Compress/SevenZip/SevenZipWrite.cs
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private Stream _lzmaStream;
|
||||
private ulong _packStreamStart;
|
||||
private ulong _packStreamSize;
|
||||
private ulong _unpackedStreamSize;
|
||||
private byte[] _codeMSbytes;
|
||||
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename)
|
||||
{
|
||||
return ZipFileCreate(newFilename, true);
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCreateFromUncompressedSize(string newFilename, ulong unCompressedSize)
|
||||
{
|
||||
return ZipFileCreate(newFilename, true, GetDictionarySizeFromUncompressedSize(unCompressedSize));
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename, bool compressOutput, int dictionarySize = 1 << 24, int numFastBytes = 64)
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
DirUtil.CreateDirForFile(newFilename);
|
||||
_zipFileInfo = new FileInfo(newFilename);
|
||||
|
||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
|
||||
_signatureHeader = new SignatureHeader();
|
||||
_header = new Header();
|
||||
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
_signatureHeader.Write(bw);
|
||||
}
|
||||
|
||||
_baseOffset = _zipFs.Position;
|
||||
|
||||
_compressed = compressOutput;
|
||||
|
||||
_unpackedStreamSize = 0;
|
||||
if (_compressed)
|
||||
{
|
||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, dictionarySize, numFastBytes);
|
||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
||||
_codeMSbytes = lzs.Properties;
|
||||
_lzmaStream = lzs;
|
||||
|
||||
|
||||
/*
|
||||
ZstandardStream zss = new ZstandardStream(_zipFs, 22, true);
|
||||
_codeMSbytes = new byte[] { 1, 4, 18, 0, 0 };
|
||||
_lzmaStream = zss;
|
||||
*/
|
||||
_packStreamStart = (ulong)_zipFs.Position;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public void ZipFileAddDirectory(string filename)
|
||||
{
|
||||
string fName = filename;
|
||||
if (fName.Substring(fName.Length - 1, 1) == @"/")
|
||||
fName = fName.Substring(0, fName.Length - 1);
|
||||
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = fName,
|
||||
UncompressedSize = 0,
|
||||
IsDirectory = true,
|
||||
StreamOffset = 0
|
||||
};
|
||||
_localFiles.Add(lf);
|
||||
}
|
||||
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
// do nothing here for 7zip
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream)
|
||||
{
|
||||
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
|
||||
}
|
||||
|
||||
private ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
|
||||
{
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = filename,
|
||||
UncompressedSize = uncompressedSize,
|
||||
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
|
||||
};
|
||||
if (uncompressedSize == 0 && filename.Substring(filename.Length - 1, 1) == "/")
|
||||
{
|
||||
lf.FileName = filename.Substring(0, filename.Length - 1);
|
||||
lf.IsDirectory = true;
|
||||
}
|
||||
|
||||
_unpackedStreamSize += uncompressedSize;
|
||||
|
||||
_localFiles.Add(lf);
|
||||
stream = _compressed ? _lzmaStream : _zipFs;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
||||
{
|
||||
_localFiles[_localFiles.Count - 1].CRC = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
private static readonly int[] DictionarySizes =
|
||||
{
|
||||
0x10000,
|
||||
0x18000,
|
||||
0x20000,
|
||||
0x30000,
|
||||
0x40000,
|
||||
0x60000,
|
||||
0x80000,
|
||||
0xc0000,
|
||||
|
||||
0x100000,
|
||||
0x180000,
|
||||
0x200000,
|
||||
0x300000,
|
||||
0x400000,
|
||||
0x600000,
|
||||
0x800000,
|
||||
0xc00000,
|
||||
|
||||
0x1000000,
|
||||
0x1800000,
|
||||
0x2000000,
|
||||
0x3000000,
|
||||
0x4000000,
|
||||
0x6000000
|
||||
};
|
||||
|
||||
|
||||
private static int GetDictionarySizeFromUncompressedSize(ulong unCompressedSize)
|
||||
{
|
||||
foreach (int v in DictionarySizes)
|
||||
{
|
||||
if ((ulong)v >= unCompressedSize)
|
||||
return v;
|
||||
}
|
||||
|
||||
return DictionarySizes[DictionarySizes.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
293
SabreTools.Library/External/Compress/SevenZip/SevenZipWriteClose.cs
vendored
Normal file
293
SabreTools.Library/External/Compress/SevenZip/SevenZipWriteClose.cs
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using Zstandard.Net;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private void Create7ZStructure()
|
||||
{
|
||||
int fileCount = _localFiles.Count;
|
||||
|
||||
//FileInfo
|
||||
_header.FileInfo = new Structure.FileInfo
|
||||
{
|
||||
Names = new string[fileCount]
|
||||
};
|
||||
|
||||
ulong emptyStreamCount = 0;
|
||||
ulong emptyFileCount = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
_header.FileInfo.Names[i] = _localFiles[i].FileName;
|
||||
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_localFiles[i].IsDirectory)
|
||||
{
|
||||
emptyFileCount += 1;
|
||||
}
|
||||
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags = null;
|
||||
_header.FileInfo.EmptyFileFlags = null;
|
||||
_header.FileInfo.Attributes = null;
|
||||
|
||||
if (emptyStreamCount > 0)
|
||||
{
|
||||
if (emptyStreamCount != emptyFileCount) //then we found directories and need to set the attributes
|
||||
{
|
||||
_header.FileInfo.Attributes = new uint[fileCount];
|
||||
}
|
||||
|
||||
if (emptyFileCount > 0)
|
||||
{
|
||||
_header.FileInfo.EmptyFileFlags = new bool[emptyStreamCount];
|
||||
}
|
||||
|
||||
emptyStreamCount = 0;
|
||||
_header.FileInfo.EmptyStreamFlags = new bool[fileCount];
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_localFiles[i].IsDirectory)
|
||||
{
|
||||
if (_header.FileInfo.Attributes != null)
|
||||
_header.FileInfo.Attributes[i] = 0x10; // set attributes to directory
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_header.FileInfo.EmptyFileFlags != null)
|
||||
_header.FileInfo.EmptyFileFlags[emptyStreamCount] = true; // set empty file flag
|
||||
}
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags[i] = true;
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//StreamsInfo
|
||||
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
||||
|
||||
//StreamsInfo.PackedStreamsInfo
|
||||
if (_compressed)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
||||
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
||||
}
|
||||
}
|
||||
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
||||
|
||||
if (_compressed)
|
||||
{
|
||||
//StreamsInfo.Folders
|
||||
_header.StreamsInfo.Folders = new Folder[1];
|
||||
|
||||
//StreamsInfo.Folders.Coder
|
||||
// flags 0x23
|
||||
|
||||
Folder folder = new Folder
|
||||
{
|
||||
BindPairs = null,
|
||||
Coders = new[] {
|
||||
new Coder {
|
||||
Method = new byte[] { 3, 1, 1 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = _codeMSbytes
|
||||
}
|
||||
},
|
||||
PackedStreamIndices = new[] { (ulong)0 },
|
||||
UnpackedStreamSizes = new[] { _unpackedStreamSize },
|
||||
UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount],
|
||||
UnpackCRC = null
|
||||
};
|
||||
|
||||
switch (_lzmaStream)
|
||||
{
|
||||
case LzmaStream _:
|
||||
folder.Coders[0].Method = new byte[] { 3, 1, 1 };
|
||||
break;
|
||||
case ZstandardStream _:
|
||||
folder.Coders[0].Method = new byte[] { 4, 247, 17, 1 };
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
||||
{
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
};
|
||||
folder.UnpackedStreamInfo[fileIndex++] = unpackedStreamInfo;
|
||||
}
|
||||
_header.StreamsInfo.Folders[0] = folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.Folders = new Folder[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Folder folder = new Folder
|
||||
{
|
||||
BindPairs = null,
|
||||
Coders = new[] {
|
||||
new Coder {
|
||||
Method = new byte[] {0},
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = null
|
||||
}
|
||||
},
|
||||
PackedStreamIndices = new[] { (ulong)i },
|
||||
UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize },
|
||||
UnpackCRC = null,
|
||||
|
||||
UnpackedStreamInfo = new[] {
|
||||
new UnpackedStreamInfo {
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_header.StreamsInfo.Folders[fileIndex++] = folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void CloseWriting7Zip()
|
||||
{
|
||||
if (_compressed)
|
||||
{
|
||||
_lzmaStream.Close();
|
||||
}
|
||||
|
||||
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
|
||||
|
||||
Create7ZStructure();
|
||||
|
||||
byte[] newHeaderByte;
|
||||
using (Stream headerMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
||||
{
|
||||
_header.WriteHeader(headerBw);
|
||||
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
}
|
||||
}
|
||||
|
||||
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
|
||||
#region Header Compression
|
||||
long packedHeaderPos = _zipFs.Position;
|
||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
|
||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
||||
byte[] lzmaStreamProperties = lzs.Properties;
|
||||
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
||||
lzs.Close();
|
||||
|
||||
StreamsInfo streamsInfo = new StreamsInfo
|
||||
{
|
||||
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
|
||||
Folders = new[] {
|
||||
new Folder {
|
||||
BindPairs = new BindPair[0],
|
||||
Coders = new [] {
|
||||
new Coder {
|
||||
Method = new byte[] { 3, 1, 1 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = lzmaStreamProperties
|
||||
}
|
||||
},
|
||||
UnpackedStreamSizes = new[] {(ulong) newHeaderByte.Length},
|
||||
UnpackCRC = mainHeaderCRC
|
||||
}
|
||||
},
|
||||
PackedStreams = new[] {
|
||||
new PackedStreamInfo
|
||||
{
|
||||
PackedSize = (ulong)(_zipFs.Position - packedHeaderPos),
|
||||
StreamPosition = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using (Stream headerMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter bw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
||||
streamsInfo.WriteHeader(bw);
|
||||
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
|
||||
}
|
||||
}
|
||||
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
#endregion
|
||||
|
||||
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
ulong headerPosition = (ulong)_zipFs.Position + 32; //tzip header is 32 bytes
|
||||
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
|
||||
_zipFs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
||||
_signatureHeader.WriteFinal(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
}
|
||||
_zipFs.Flush();
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,8 @@ namespace Compress.SevenZip.Structure
|
||||
BCJ2,
|
||||
PPMd,
|
||||
BZip2,
|
||||
LZMA2
|
||||
LZMA2,
|
||||
ZSTD
|
||||
}
|
||||
|
||||
|
||||
@@ -73,40 +74,42 @@ namespace Compress.SevenZip.Structure
|
||||
throw new NotSupportedException("External flag");
|
||||
}
|
||||
|
||||
if ((Method.Length == 1) && (Method[0] == 0))
|
||||
if (Method.Length == 1 && Method[0] == 0)
|
||||
{
|
||||
DecoderType = DecompressType.Stored;
|
||||
}
|
||||
else if ((Method.Length == 1) && (Method[0] == 3))
|
||||
else if (Method.Length == 1 && Method[0] == 3)
|
||||
{
|
||||
DecoderType = DecompressType.Delta;
|
||||
}
|
||||
else if ((Method.Length == 3) && (Method[0] == 3) && (Method[1] == 1) && (Method[2] == 1))
|
||||
else if (Method.Length == 3 && Method[0] == 3 && Method[1] == 1 && Method[2] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.LZMA;
|
||||
}
|
||||
else if ((Method.Length == 4) && (Method[0] == 3) && (Method[1] == 3) && (Method[2] == 1) &&
|
||||
(Method[3] == 3))
|
||||
else if (Method.Length == 4 && Method[0] == 3 && Method[1] == 3 && Method[2] == 1 && Method[3] == 3)
|
||||
{
|
||||
DecoderType = DecompressType.BCJ;
|
||||
}
|
||||
else if ((Method.Length == 4) && (Method[0] == 3) && (Method[1] == 3) && (Method[2] == 1) &&
|
||||
(Method[3] == 27))
|
||||
else if (Method.Length == 4 && Method[0] == 3 && Method[1] == 3 && Method[2] == 1 && Method[3] == 27)
|
||||
{
|
||||
DecoderType = DecompressType.BCJ2;
|
||||
}
|
||||
else if ((Method.Length == 3) && (Method[0] == 3) && (Method[1] == 4) && (Method[2] == 1))
|
||||
else if (Method.Length == 3 && Method[0] == 3 && Method[1] == 4 && Method[2] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.PPMd;
|
||||
}
|
||||
else if ((Method.Length == 3) && (Method[0] == 4) && (Method[1] == 2) && (Method[2] == 2))
|
||||
else if (Method.Length == 3 && Method[0] == 4 && Method[1] == 2 && Method[2] == 2)
|
||||
{
|
||||
DecoderType = DecompressType.BZip2;
|
||||
}
|
||||
else if ((Method.Length == 1) && (Method[0] == 33))
|
||||
else if (Method.Length == 1 && Method[0] == 33)
|
||||
{
|
||||
DecoderType = DecompressType.LZMA2;
|
||||
}
|
||||
else if (SevenZ.supportZstd && Method.Length == 4 && Method[0] == 4 && Method[1] == 247 && Method[2] == 17 && Method[3] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.ZSTD;
|
||||
}
|
||||
|
||||
InputStreamsSourceInfo = new InStreamSourceInfo[NumInStreams];
|
||||
for (uint i = 0; i < NumInStreams; i++)
|
||||
|
||||
@@ -338,10 +338,18 @@ namespace Compress.SevenZip.Structure
|
||||
Folders[i].WriteUnpackedStreamSize(bw);
|
||||
}
|
||||
|
||||
if (Folders[0].UnpackCRC != null)
|
||||
bool hasCRC = false;
|
||||
uint?[] CRCs = new uint?[numFolders];
|
||||
for (ulong i = 0; i < numFolders; i++)
|
||||
{
|
||||
CRCs[i] = Folders[i].UnpackCRC;
|
||||
hasCRC |= (CRCs[i] != null);
|
||||
}
|
||||
|
||||
if (hasCRC)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kCRC);
|
||||
throw new NotImplementedException();
|
||||
Util.WritePackedCRCs(bw, CRCs);
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Compress.SevenZip.Structure
|
||||
}
|
||||
|
||||
|
||||
private void Write(BinaryWriter bw)
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kHeader);
|
||||
StreamsInfo.Write(bw);
|
||||
@@ -46,11 +46,6 @@ namespace Compress.SevenZip.Structure
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
Write(bw);
|
||||
}
|
||||
|
||||
public static ZipReturn ReadHeaderOrPackedHeader(Stream stream, long baseOffset, out Header header)
|
||||
{
|
||||
header = null;
|
||||
|
||||
@@ -49,6 +49,13 @@ namespace Compress.SevenZip.Structure
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
PackedStreamInfo.Write(bw, PackPosition, PackedStreams);
|
||||
Folder.WriteUnPackInfo(bw, Folders);
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
|
||||
@@ -183,6 +183,23 @@ namespace Compress.SevenZip
|
||||
}
|
||||
}
|
||||
|
||||
public static void WritePackedCRCs(BinaryWriter bw, uint?[] digests)
|
||||
{
|
||||
bool[] digestsDefined = new bool[digests.Length];
|
||||
for (int i = 0; i < digests.Length; i++)
|
||||
{
|
||||
digestsDefined[i] = digests[i] != null;
|
||||
}
|
||||
WriteBoolFlagsDefaultTrue(bw, digestsDefined);
|
||||
for (int i = 0; i < digests.Length; i++)
|
||||
{
|
||||
if (digestsDefined[i])
|
||||
{
|
||||
bw.Write((uint)digests[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool[] ReadBoolFlagsDefaultTrue(BinaryReader br, ulong numItems)
|
||||
{
|
||||
byte allAreDefined = br.ReadByte();
|
||||
@@ -198,6 +215,22 @@ namespace Compress.SevenZip
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static void WriteBoolFlagsDefaultTrue(BinaryWriter bw, bool[] bArray)
|
||||
{
|
||||
bool allTrue = true;
|
||||
foreach (bool b in bArray)
|
||||
{
|
||||
allTrue &= b;
|
||||
}
|
||||
|
||||
if (allTrue)
|
||||
{
|
||||
bw.Write((byte)1);
|
||||
return;
|
||||
}
|
||||
WriteBoolFlags(bw, bArray);
|
||||
}
|
||||
|
||||
public static bool[] ReadBoolFlags(BinaryReader br, ulong numItems)
|
||||
{
|
||||
byte b = 0;
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Compress
|
||||
ZipErrorTimeStamp,
|
||||
ZipErrorRollBackFile,
|
||||
ZipTryingToAccessADirectory,
|
||||
ZipErrorWritingToOutputStream,
|
||||
ZipUntested
|
||||
|
||||
}
|
||||
|
||||
@@ -382,7 +382,8 @@ namespace Compress.ZipFile.ZLib
|
||||
// The distribution counts are first used to generate the code values
|
||||
// without bit reversal.
|
||||
for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
unchecked {
|
||||
unchecked
|
||||
{
|
||||
next_code[bits] = code = (short)((code + bl_count[bits - 1]) << 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,4 +123,3 @@ namespace Compress.ZipFile.ZLib
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -138,10 +138,6 @@ namespace Compress.ZipFile
|
||||
bool lTrrntzip = true;
|
||||
|
||||
_centerDirStart = (ulong)_zipFs.Position;
|
||||
if (_centerDirStart >= 0xffffffff)
|
||||
{
|
||||
_zip64 = true;
|
||||
}
|
||||
|
||||
using (CrcCalculatorStream crcCs = new CrcCalculatorStream(_zipFs, true))
|
||||
{
|
||||
@@ -160,6 +156,9 @@ namespace Compress.ZipFile
|
||||
_fileComment = lTrrntzip ? GetBytes("TORRENTZIPPED-" + crcCs.Crc.ToString("X8")) : new byte[0];
|
||||
ZipStatus = lTrrntzip ? ZipStatus.TrrntZip : ZipStatus.None;
|
||||
}
|
||||
_zip64 |= _centerDirStart >= 0xffffffff;
|
||||
_zip64 |= _centerDirSize >= 0xffffffff;
|
||||
_zip64 |= _localFiles.Count >= 0xffff;
|
||||
|
||||
if (_zip64)
|
||||
{
|
||||
@@ -218,7 +217,6 @@ namespace Compress.ZipFile
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
// TODO: Figure out how to re-add the file time functionality to this
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream)
|
||||
{
|
||||
stream = null;
|
||||
@@ -271,9 +269,9 @@ namespace Compress.ZipFile
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public void ZipFileAddDirectory()
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
LocalFile.LocalFileAddDirectory(_zipFs);
|
||||
LocalFile.LocalFileAddZeroLengthFile(_zipFs);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -528,7 +526,7 @@ namespace Compress.ZipFile
|
||||
|
||||
|
||||
|
||||
// TODO: Figure out the timestamp instead of using ticks like we were before
|
||||
|
||||
public ZipReturn ZipFileOpen(string newFilename, long timestamp, bool readHeaders)
|
||||
{
|
||||
ZipFileClose();
|
||||
@@ -1799,9 +1797,13 @@ namespace Compress.ZipFile
|
||||
|
||||
if (_compressedSize == 0 && UncompressedSize == 0)
|
||||
{
|
||||
LocalFileAddDirectory(zipFs);
|
||||
LocalFileAddZeroLengthFile(zipFs);
|
||||
_compressedSize = (ulong)zipFs.Position - _dataLocation;
|
||||
}
|
||||
else if (_compressedSize == 0 && UncompressedSize != 0)
|
||||
{
|
||||
return ZipReturn.ZipErrorWritingToOutputStream;
|
||||
}
|
||||
|
||||
CRC = crc32;
|
||||
WriteCompressedSize(zipFs);
|
||||
@@ -1892,7 +1894,7 @@ namespace Compress.ZipFile
|
||||
zipFs.Seek(posNow, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public static void LocalFileAddDirectory(Stream zipFs)
|
||||
public static void LocalFileAddZeroLengthFile(Stream zipFs)
|
||||
{
|
||||
zipFs.WriteByte(03);
|
||||
zipFs.WriteByte(00);
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace Compress.gZip
|
||||
|
||||
public long TimeStamp => _zipFileInfo?.LastWriteTime ?? 0;
|
||||
|
||||
public void ZipFileAddDirectory()
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
2
SabreTools.Library/External/RVIO/RVIO.cs
vendored
2
SabreTools.Library/External/RVIO/RVIO.cs
vendored
@@ -443,6 +443,8 @@ namespace RVIO
|
||||
{
|
||||
case 5: return "ERROR_ACCESS_DENIED: Access is denied.";
|
||||
case 32: return "ERROR_FILE_IN_USE: The file is in use by another process.";
|
||||
case 39: return "ERROR_HANDLE_DISK_FULL: The disk is full.";
|
||||
case 112: return "ERROR_DISK_FULL: There is not enough space on the disk.";
|
||||
case 123: return "ERROR_INVALID_NAME: The filename, directory name, or volume label syntax is incorrect.";
|
||||
case 183: return "ERROR_ALREADY_EXISTS: Cannot create a file when that file already exists.";
|
||||
}
|
||||
|
||||
@@ -18,18 +18,16 @@ using MemoryStream = System.IO.MemoryStream;
|
||||
using SeekOrigin = System.IO.SeekOrigin;
|
||||
using Stream = System.IO.Stream;
|
||||
#endif
|
||||
using Compress;
|
||||
using Compress.SevenZip;
|
||||
using Compress.ZipFile;
|
||||
using SevenZip; // TODO: Remove this when 7zip write is implemented in SharpCompress
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.SevenZip;
|
||||
using SharpCompress.Readers;
|
||||
using NaturalSort;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Torrent7zip archive for reading and writing
|
||||
/// </summary>
|
||||
/// TODO: Torrent 7-zip: https://sourceforge.net/p/t7z/code/HEAD/tree/
|
||||
public class SevenZipArchive : BaseArchive
|
||||
{
|
||||
#region Constructors
|
||||
@@ -74,13 +72,62 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
// Extract all files to the temp directory
|
||||
SharpCompress.Archives.SevenZip.SevenZipArchive sza = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(Utilities.TryOpenRead(this.Filename));
|
||||
foreach (SevenZipArchiveEntry entry in sza.Entries)
|
||||
SevenZ zf = new SevenZ();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
entry.WriteToDirectory(outDir, new SharpCompress.Common.ExtractionOptions { PreserveFileTime = true, ExtractFullPath = true, Overwrite = true });
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
|
||||
{
|
||||
// Open the read stream
|
||||
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
|
||||
|
||||
// Create the rest of the path, if needed
|
||||
if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName(zf.Filename(i))))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(outDir, Path.GetDirectoryName(zf.Filename(i))));
|
||||
}
|
||||
|
||||
// If the entry ends with a directory separator, continue to the next item, if any
|
||||
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
||||
{
|
||||
zf.ZipFileCloseReadStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
FileStream writeStream = Utilities.TryCreate(Path.Combine(outDir, zf.Filename(i)));
|
||||
|
||||
// If the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||
if (streamsize < _bufferSize)
|
||||
{
|
||||
byte[] ibuffer = new byte[streamsize];
|
||||
int ilen = readStream.Read(ibuffer, 0, (int)streamsize);
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
// Otherwise, we do the normal loop
|
||||
else
|
||||
{
|
||||
int realBufferSize = (streamsize < _bufferSize ? (int)streamsize : _bufferSize);
|
||||
byte[] ibuffer = new byte[realBufferSize];
|
||||
int ilen;
|
||||
while ((ilen = readStream.Read(ibuffer, 0, realBufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
zr = zf.ZipFileCloseReadStream();
|
||||
writeStream.Dispose();
|
||||
}
|
||||
|
||||
zf.ZipFileClose();
|
||||
encounteredErrors = false;
|
||||
sza.Dispose();
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
@@ -158,18 +205,52 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
SharpCompress.Archives.SevenZip.SevenZipArchive sza = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false, });
|
||||
foreach (SevenZipArchiveEntry entry in sza.Entries)
|
||||
SevenZ zf = new SevenZ();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
|
||||
{
|
||||
// Write the file out
|
||||
realEntry = entry.Key;
|
||||
entry.WriteTo(ms);
|
||||
break;
|
||||
if (zf.Filename(i).Contains(entryName))
|
||||
{
|
||||
// Open the read stream
|
||||
realEntry = zf.Filename(i);
|
||||
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
|
||||
|
||||
// If the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||
if (streamsize < _bufferSize)
|
||||
{
|
||||
byte[] ibuffer = new byte[streamsize];
|
||||
int ilen = readStream.Read(ibuffer, 0, (int)streamsize);
|
||||
ms.Write(ibuffer, 0, ilen);
|
||||
ms.Flush();
|
||||
}
|
||||
// Otherwise, we do the normal loop
|
||||
else
|
||||
{
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while (streamsize > _bufferSize)
|
||||
{
|
||||
ilen = readStream.Read(ibuffer, 0, _bufferSize);
|
||||
ms.Write(ibuffer, 0, ilen);
|
||||
ms.Flush();
|
||||
streamsize -= _bufferSize;
|
||||
}
|
||||
|
||||
ilen = readStream.Read(ibuffer, 0, (int)streamsize);
|
||||
ms.Write(ibuffer, 0, ilen);
|
||||
ms.Flush();
|
||||
}
|
||||
|
||||
zr = zf.ZipFileCloseReadStream();
|
||||
}
|
||||
}
|
||||
sza.Dispose();
|
||||
|
||||
zf.ZipFileClose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -199,18 +280,47 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
SharpCompress.Archives.SevenZip.SevenZipArchive sza = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(Utilities.TryOpenRead(this.Filename));
|
||||
foreach (SevenZipArchiveEntry entry in sza.Entries.Where(e => e != null && !e.IsDirectory))
|
||||
SevenZ zf = new SevenZ();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
||||
{
|
||||
// If the entry is a directory (or looks like a directory), we don't want to open it
|
||||
if (zf.IsDirectory(i)
|
||||
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Open the read stream
|
||||
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
|
||||
|
||||
// If we get a read error, log it and continue
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Globals.Logger.Warning("An error occurred while reading archive {0}: Zip Error - {1}", this.Filename, zr);
|
||||
zr = zf.ZipFileCloseReadStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
// If secure hashes are disabled, do a quickscan
|
||||
if (omitFromScan == Hash.SecureHashes)
|
||||
{
|
||||
string newname = zf.Filename(i);
|
||||
long newsize = (long)zf.UncompressedSize(i);
|
||||
byte[] newcrc = zf.CRC32(i);
|
||||
|
||||
found.Add(new BaseFile
|
||||
{
|
||||
Filename = entry.Key,
|
||||
Size = entry.Size,
|
||||
CRC = BitConverter.GetBytes(entry.Crc),
|
||||
Date = (date && entry.LastModifiedTime != null ? entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss") : null),
|
||||
Filename = newname,
|
||||
Size = newsize,
|
||||
CRC = newcrc,
|
||||
|
||||
Parent = gamename,
|
||||
});
|
||||
@@ -218,18 +328,16 @@ namespace SabreTools.Library.FileTypes
|
||||
// Otherwise, use the stream directly
|
||||
else
|
||||
{
|
||||
Stream entryStream = entry.OpenEntryStream();
|
||||
BaseFile sevenZipEntryRom = Utilities.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan);
|
||||
sevenZipEntryRom.Filename = entry.Key;
|
||||
sevenZipEntryRom.Parent = gamename;
|
||||
sevenZipEntryRom.Date = (date && entry.LastModifiedTime != null ? entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss") : null);
|
||||
found.Add(sevenZipEntryRom);
|
||||
entryStream.Dispose();
|
||||
BaseFile zipEntryRom = Utilities.GetStreamInfo(readStream, (long)zf.UncompressedSize(i), omitFromScan: omitFromScan, keepReadOpen: true);
|
||||
zipEntryRom.Filename = zf.Filename(i);
|
||||
zipEntryRom.Parent = gamename;
|
||||
found.Add(zipEntryRom);
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose of the archive
|
||||
sza.Dispose();
|
||||
zr = zf.ZipFileCloseReadStream();
|
||||
zf.ZipFileClose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -251,24 +359,36 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
SharpCompress.Archives.SevenZip.SevenZipArchive sza = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false });
|
||||
List<SevenZipArchiveEntry> sevenZipEntries = sza.Entries.OrderBy(e => e.Key, new NaturalSort.NaturalReversedComparer()).ToList();
|
||||
string lastSevenZipEntry = null;
|
||||
foreach (SevenZipArchiveEntry entry in sevenZipEntries)
|
||||
SevenZ zf = new SevenZ();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
if (entry != null)
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
List<(string, bool)> zipEntries = new List<(string, bool)>();
|
||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
||||
{
|
||||
zipEntries.Add((zf.Filename(i), zf.IsDirectory(i)));
|
||||
}
|
||||
|
||||
zipEntries = zipEntries.OrderBy(p => p.Item1, new NaturalReversedComparer()).ToList();
|
||||
string lastZipEntry = null;
|
||||
foreach ((string, bool) entry in zipEntries)
|
||||
{
|
||||
// If the current is a superset of last, we skip it
|
||||
if (lastSevenZipEntry != null && lastSevenZipEntry.StartsWith(entry.Key))
|
||||
if (lastZipEntry != null && lastZipEntry.StartsWith(entry.Item1))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
// If the entry is a directory, we add it
|
||||
else if (entry.IsDirectory)
|
||||
else
|
||||
{
|
||||
empties.Add(entry.Key);
|
||||
lastSevenZipEntry = entry.Key;
|
||||
if (entry.Item2)
|
||||
{
|
||||
empties.Add(entry.Item1);
|
||||
}
|
||||
lastZipEntry = entry.Item1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,43 +403,16 @@ namespace SabreTools.Library.FileTypes
|
||||
/// <summary>
|
||||
/// Check whether the input file is a standardized format
|
||||
/// </summary>
|
||||
/// TODO: Finish reading T7z information
|
||||
public override bool IsTorrent()
|
||||
{
|
||||
bool ist7z = false;
|
||||
|
||||
if (File.Exists(this.Filename))
|
||||
SevenZ zf = new SevenZ();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream fread = Utilities.TryOpenRead(this.Filename);
|
||||
uint ar, offs = 0;
|
||||
fread.Seek(0, SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[128];
|
||||
ar = (uint)fread.Read(buffer, 0, 4 + Constants.Torrent7ZipSignature.Length + 4);
|
||||
if (ar < (4 + Constants.Torrent7ZipSignature.Length + 4))
|
||||
{
|
||||
if (ar >= Constants.Torrent7ZipSignature.Length + 4)
|
||||
{
|
||||
ar -= (uint)(Constants.Torrent7ZipSignature.Length + 4);
|
||||
}
|
||||
if (ar <= Constants.Torrent7ZipHeader.Length)
|
||||
{
|
||||
ar = (uint)Constants.Torrent7ZipHeader.Length;
|
||||
}
|
||||
// memset(buffer+offs+ar,0,crcsz-ar)
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
fread.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Globals.Logger.Warning("File '{0}' could not be opened", this.Filename);
|
||||
ist7z = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ist7z;
|
||||
return zf.ZipStatus == ZipStatus.Trrnt7Zip;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -371,79 +464,89 @@ namespace SabreTools.Library.FileTypes
|
||||
inputStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Get the output archive name from the first rebuild rom
|
||||
string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName) + (rom.MachineName.EndsWith(".7z") ? "" : ".7z"));
|
||||
string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName) + (rom.MachineName.EndsWith(".zip") ? "" : ".zip"));
|
||||
|
||||
// Set internal variables
|
||||
SevenZipBase.SetLibraryPath("7za.dll");
|
||||
SevenZipExtractor oldZipFile = null;
|
||||
SevenZipCompressor zipFile;
|
||||
Stream writeStream = null;
|
||||
SevenZ oldZipFile = new SevenZ();
|
||||
SevenZ zipFile = new SevenZ();
|
||||
ZipReturn zipReturn = ZipReturn.ZipGood;
|
||||
|
||||
try
|
||||
{
|
||||
// If the full output path doesn't exist, create it
|
||||
if (!Directory.Exists(Path.GetDirectoryName(tempFile)))
|
||||
if (!Directory.Exists(Path.GetDirectoryName(archiveFileName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(archiveFileName));
|
||||
}
|
||||
|
||||
// If the archive doesn't exist, create it and put the single file
|
||||
if (!File.Exists(archiveFileName))
|
||||
{
|
||||
zipFile = new SevenZipCompressor()
|
||||
{
|
||||
ArchiveFormat = OutArchiveFormat.SevenZip,
|
||||
CompressionLevel = CompressionLevel.Normal,
|
||||
};
|
||||
inputStream.Seek(0, SeekOrigin.Begin);
|
||||
zipReturn = zipFile.ZipFileCreate(tempFile);
|
||||
|
||||
// Create the temp directory
|
||||
string tempPath = Path.Combine(outDir, Guid.NewGuid().ToString());
|
||||
if (!Directory.Exists(tempPath))
|
||||
// Open the input file for reading
|
||||
ulong istreamSize = (ulong)(inputStream.Length);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
if (date && !String.IsNullOrWhiteSpace(rom.Date) && DateTime.TryParse(rom.Date.Replace('\\', '/'), out dt))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt);
|
||||
zipFile.ZipFileOpenWriteStream(false, false, rom.Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipFile.ZipFileOpenWriteStream(false, true, rom.Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
|
||||
// Create a stream dictionary
|
||||
Dictionary<string, Stream> dict = new Dictionary<string, Stream>();
|
||||
dict.Add(rom.Name, inputStream);
|
||||
|
||||
// Now add the stream
|
||||
zipFile.CompressStreamDictionary(dict, tempFile);
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = inputStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
inputStream.Dispose();
|
||||
zipFile.ZipFileCloseWriteStream(Utilities.StringToByteArray(rom.CRC));
|
||||
}
|
||||
|
||||
// Otherwise, sort the input files and write out in the correct order
|
||||
else
|
||||
{
|
||||
// Open the old archive for reading
|
||||
using (oldZipFile = new SevenZipExtractor(archiveFileName))
|
||||
{
|
||||
oldZipFile.ZipFileOpen(archiveFileName, -1, true);
|
||||
|
||||
// Map all inputs to index
|
||||
Dictionary<string, int> inputIndexMap = new Dictionary<string, int>();
|
||||
var oldZipFileContents = new List<string>();
|
||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
||||
{
|
||||
oldZipFileContents.Add(oldZipFile.Filename(i));
|
||||
}
|
||||
|
||||
// If the old one doesn't contain the new file, then add it
|
||||
if (!oldZipFile.ArchiveFileNames.Contains(rom.Name.Replace('\\', '/')))
|
||||
if (!oldZipFileContents.Contains(rom.Name.Replace('\\', '/')))
|
||||
{
|
||||
inputIndexMap.Add(rom.Name.Replace('\\', '/'), -1);
|
||||
}
|
||||
|
||||
// Then add all of the old entries to it too
|
||||
for (int i = 0; i < oldZipFile.FilesCount; i++)
|
||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
||||
{
|
||||
inputIndexMap.Add(oldZipFile.ArchiveFileNames[i], i);
|
||||
inputIndexMap.Add(oldZipFile.Filename(i), i);
|
||||
}
|
||||
|
||||
// If the number of entries is the same as the old archive, skip out
|
||||
if (inputIndexMap.Keys.Count <= oldZipFile.FilesCount)
|
||||
if (inputIndexMap.Keys.Count <= oldZipFile.LocalFilesCount())
|
||||
{
|
||||
success = true;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Otherwise, process the old zipfile
|
||||
zipFile = new SevenZipCompressor()
|
||||
{
|
||||
ArchiveFormat = OutArchiveFormat.SevenZip,
|
||||
CompressionLevel = CompressionLevel.Normal,
|
||||
};
|
||||
zipFile.ZipFileCreate(tempFile);
|
||||
|
||||
// Get the order for the entries with the new file
|
||||
List<string> keys = inputIndexMap.Keys.ToList();
|
||||
@@ -458,36 +561,59 @@ namespace SabreTools.Library.FileTypes
|
||||
// If we have the input file, add it now
|
||||
if (index < 0)
|
||||
{
|
||||
// Create a stream dictionary
|
||||
Dictionary<string, Stream> dict = new Dictionary<string, Stream>();
|
||||
dict.Add(rom.Name, inputStream);
|
||||
// Open the input file for reading
|
||||
ulong istreamSize = (ulong)(inputStream.Length);
|
||||
|
||||
// Now add the stream
|
||||
zipFile.CompressStreamDictionary(dict, tempFile);
|
||||
DateTime dt = DateTime.Now;
|
||||
if (date && !String.IsNullOrWhiteSpace(rom.Date) && DateTime.TryParse(rom.Date.Replace('\\', '/'), out dt))
|
||||
{
|
||||
uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt);
|
||||
zipFile.ZipFileOpenWriteStream(false, false, rom.Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipFile.ZipFileOpenWriteStream(false, true, rom.Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = inputStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
|
||||
inputStream.Dispose();
|
||||
zipFile.ZipFileCloseWriteStream(Utilities.StringToByteArray(rom.CRC));
|
||||
}
|
||||
|
||||
// Otherwise, copy the file from the old archive
|
||||
else
|
||||
{
|
||||
Stream oldZipFileEntryStream = new MemoryStream();
|
||||
oldZipFile.ExtractFile(index, oldZipFileEntryStream);
|
||||
oldZipFileEntryStream.Seek(0, SeekOrigin.Begin);
|
||||
// Instantiate the streams
|
||||
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
|
||||
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, 0, out writeStream);
|
||||
|
||||
// Create a stream dictionary
|
||||
Dictionary<string, Stream> dict = new Dictionary<string, Stream>();
|
||||
dict.Add(oldZipFile.ArchiveFileNames[index], oldZipFileEntryStream);
|
||||
|
||||
// Now add the stream
|
||||
zipFile.CompressStreamDictionary(dict, tempFile);
|
||||
oldZipFileEntryStream.Dispose();
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = zreadStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
|
||||
// After the first file, make sure we're in append mode
|
||||
zipFile.CompressionMode = CompressionMode.Append;
|
||||
oldZipFile.ZipFileCloseReadStream();
|
||||
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the output zip file
|
||||
zipFile.ZipFileClose();
|
||||
oldZipFile.ZipFileClose();
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -507,33 +633,6 @@ namespace SabreTools.Library.FileTypes
|
||||
}
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
// Now make the file T7Z
|
||||
// TODO: Add ACTUAL T7Z compatible code
|
||||
|
||||
BinaryWriter bw = new BinaryWriter(Utilities.TryOpenReadWrite(archiveFileName));
|
||||
bw.Seek(0, SeekOrigin.Begin);
|
||||
bw.Write(Constants.Torrent7ZipHeader);
|
||||
bw.Seek(0, SeekOrigin.End);
|
||||
|
||||
using (oldZipFile = new SevenZipExtractor(Utilities.TryOpenReadWrite(archiveFileName)))
|
||||
{
|
||||
|
||||
// Get the correct signature to use (Default 0, Unicode 1, SingleFile 2, StripFileNames 4)
|
||||
byte[] tempsig = Constants.Torrent7ZipSignature;
|
||||
if (oldZipFile.FilesCount > 1)
|
||||
{
|
||||
tempsig[16] = 0x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsig[16] = 0;
|
||||
}
|
||||
|
||||
bw.Write(tempsig);
|
||||
bw.Flush();
|
||||
bw.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -573,12 +672,13 @@ namespace SabreTools.Library.FileTypes
|
||||
}
|
||||
|
||||
// Get the output archive name from the first rebuild rom
|
||||
string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(roms[0].MachineName) + (roms[0].MachineName.EndsWith(".7z") ? "" : ".7z"));
|
||||
string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(roms[0].MachineName) + (roms[0].MachineName.EndsWith(".zip") ? "" : ".zip"));
|
||||
|
||||
// Set internal variables
|
||||
SevenZipBase.SetLibraryPath("7za.dll");
|
||||
SevenZipExtractor oldZipFile;
|
||||
SevenZipCompressor zipFile;
|
||||
Stream writeStream = null;
|
||||
SevenZ oldZipFile = new SevenZ();
|
||||
SevenZ zipFile = new SevenZ();
|
||||
ZipReturn zipReturn = ZipReturn.ZipGood;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -591,11 +691,7 @@ namespace SabreTools.Library.FileTypes
|
||||
// If the archive doesn't exist, create it and put the single file
|
||||
if (!File.Exists(archiveFileName))
|
||||
{
|
||||
zipFile = new SevenZipCompressor()
|
||||
{
|
||||
ArchiveFormat = OutArchiveFormat.SevenZip,
|
||||
CompressionLevel = CompressionLevel.Normal,
|
||||
};
|
||||
zipReturn = zipFile.ZipFileCreate(tempFile);
|
||||
|
||||
// Map all inputs to index
|
||||
Dictionary<string, int> inputIndexMap = new Dictionary<string, int>();
|
||||
@@ -608,42 +704,59 @@ namespace SabreTools.Library.FileTypes
|
||||
List<string> keys = inputIndexMap.Keys.ToList();
|
||||
keys.Sort(ZipFile.TrrntZipStringCompare);
|
||||
|
||||
// Create the temp directory
|
||||
string tempPath = Path.Combine(outDir, Guid.NewGuid().ToString());
|
||||
if (!Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
}
|
||||
|
||||
// Now add all of the files in order
|
||||
foreach (string key in keys)
|
||||
{
|
||||
string newkey = Path.Combine(tempPath, key);
|
||||
// Get the index mapped to the key
|
||||
int index = inputIndexMap[key];
|
||||
|
||||
File.Move(inputFiles[inputIndexMap[key]], newkey);
|
||||
zipFile.CompressFiles(tempFile, newkey);
|
||||
File.Move(newkey, inputFiles[inputIndexMap[key]]);
|
||||
// Open the input file for reading
|
||||
Stream freadStream = Utilities.TryOpenRead(inputFiles[index]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[index]).Length);
|
||||
|
||||
// After the first file, make sure we're in append mode
|
||||
zipFile.CompressionMode = CompressionMode.Append;
|
||||
DateTime dt = DateTime.Now;
|
||||
if (date && !String.IsNullOrWhiteSpace(roms[index].Date) && DateTime.TryParse(roms[index].Date.Replace('\\', '/'), out dt))
|
||||
{
|
||||
uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt);
|
||||
zipFile.ZipFileOpenWriteStream(false, false, roms[index].Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipFile.ZipFileOpenWriteStream(false, true, roms[index].Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
|
||||
Utilities.CleanDirectory(tempPath);
|
||||
Utilities.TryDeleteDirectory(tempPath);
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = freadStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
|
||||
freadStream.Dispose();
|
||||
zipFile.ZipFileCloseWriteStream(Utilities.StringToByteArray(roms[index].CRC));
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, sort the input files and write out in the correct order
|
||||
else
|
||||
{
|
||||
// Open the old archive for reading
|
||||
using (oldZipFile = new SevenZipExtractor(archiveFileName))
|
||||
{
|
||||
oldZipFile.ZipFileOpen(archiveFileName, -1, true);
|
||||
|
||||
// Map all inputs to index
|
||||
Dictionary<string, int> inputIndexMap = new Dictionary<string, int>();
|
||||
for (int i = 0; i < inputFiles.Count; i++)
|
||||
{
|
||||
var oldZipFileContents = new List<string>();
|
||||
for (int j = 0; j < oldZipFile.LocalFilesCount(); j++)
|
||||
{
|
||||
oldZipFileContents.Add(oldZipFile.Filename(j));
|
||||
}
|
||||
|
||||
// If the old one contains the new file, then just skip out
|
||||
if (oldZipFile.ArchiveFileNames.Contains(roms[i].Name.Replace('\\', '/')))
|
||||
if (oldZipFileContents.Contains(roms[i].Name.Replace('\\', '/')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -652,24 +765,20 @@ namespace SabreTools.Library.FileTypes
|
||||
}
|
||||
|
||||
// Then add all of the old entries to it too
|
||||
for (int i = 0; i < oldZipFile.FilesCount; i++)
|
||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
||||
{
|
||||
inputIndexMap.Add(oldZipFile.ArchiveFileNames[i], i);
|
||||
inputIndexMap.Add(oldZipFile.Filename(i), i);
|
||||
}
|
||||
|
||||
// If the number of entries is the same as the old archive, skip out
|
||||
if (inputIndexMap.Keys.Count <= oldZipFile.FilesCount)
|
||||
if (inputIndexMap.Keys.Count <= oldZipFile.LocalFilesCount())
|
||||
{
|
||||
success = true;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Otherwise, process the old zipfile
|
||||
zipFile = new SevenZipCompressor()
|
||||
{
|
||||
ArchiveFormat = OutArchiveFormat.SevenZip,
|
||||
CompressionLevel = CompressionLevel.Normal,
|
||||
};
|
||||
zipFile.ZipFileCreate(tempFile);
|
||||
|
||||
// Get the order for the entries with the new file
|
||||
List<string> keys = inputIndexMap.Keys.ToList();
|
||||
@@ -684,38 +793,58 @@ namespace SabreTools.Library.FileTypes
|
||||
// If we have the input file, add it now
|
||||
if (index < 0)
|
||||
{
|
||||
FileStream inputStream = Utilities.TryOpenRead(inputFiles[-index - 1]);
|
||||
// Open the input file for reading
|
||||
Stream freadStream = Utilities.TryOpenRead(inputFiles[-index - 1]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[-index - 1]).Length);
|
||||
|
||||
// Create a stream dictionary
|
||||
Dictionary<string, Stream> dict = new Dictionary<string, Stream>();
|
||||
dict.Add(key, inputStream);
|
||||
DateTime dt = DateTime.Now;
|
||||
if (date && !String.IsNullOrWhiteSpace(roms[-index - 1].Date) && DateTime.TryParse(roms[-index - 1].Date.Replace('\\', '/'), out dt))
|
||||
{
|
||||
uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt);
|
||||
zipFile.ZipFileOpenWriteStream(false, false, roms[-index - 1].Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipFile.ZipFileOpenWriteStream(false, true, roms[-index - 1].Name.Replace('\\', '/'), istreamSize, 0, out writeStream);
|
||||
}
|
||||
|
||||
// Now add the stream
|
||||
zipFile.CompressStreamDictionary(dict, tempFile);
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = freadStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
freadStream.Dispose();
|
||||
zipFile.ZipFileCloseWriteStream(Utilities.StringToByteArray(roms[-index - 1].CRC));
|
||||
}
|
||||
|
||||
// Otherwise, copy the file from the old archive
|
||||
else
|
||||
{
|
||||
Stream oldZipFileEntryStream = new MemoryStream();
|
||||
oldZipFile.ExtractFile(index, oldZipFileEntryStream);
|
||||
oldZipFileEntryStream.Seek(0, SeekOrigin.Begin);
|
||||
// Instantiate the streams
|
||||
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
|
||||
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, 0, out writeStream);
|
||||
|
||||
// Create a stream dictionary
|
||||
Dictionary<string, Stream> dict = new Dictionary<string, Stream>();
|
||||
dict.Add(oldZipFile.ArchiveFileNames[index], oldZipFileEntryStream);
|
||||
|
||||
// Now add the stream
|
||||
zipFile.CompressStreamDictionary(dict, tempFile);
|
||||
oldZipFileEntryStream.Dispose();
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[_bufferSize];
|
||||
int ilen;
|
||||
while ((ilen = zreadStream.Read(ibuffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
writeStream.Flush();
|
||||
}
|
||||
|
||||
// After the first file, make sure we're in append mode
|
||||
zipFile.CompressionMode = CompressionMode.Append;
|
||||
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the output zip file
|
||||
zipFile.ZipFileClose();
|
||||
oldZipFile.ZipFileClose();
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -731,32 +860,6 @@ namespace SabreTools.Library.FileTypes
|
||||
}
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
// Now make the file T7Z
|
||||
// TODO: Add ACTUAL T7Z compatible code
|
||||
|
||||
BinaryWriter bw = new BinaryWriter(Utilities.TryOpenReadWrite(archiveFileName));
|
||||
bw.Seek(0, SeekOrigin.Begin);
|
||||
bw.Write(Constants.Torrent7ZipHeader);
|
||||
bw.Seek(0, SeekOrigin.End);
|
||||
|
||||
using (oldZipFile = new SevenZipExtractor(Utilities.TryOpenReadWrite(archiveFileName)))
|
||||
{
|
||||
// Get the correct signature to use (Default 0, Unicode 1, SingleFile 2, StripFileNames 4)
|
||||
byte[] tempsig = Constants.Torrent7ZipSignature;
|
||||
if (oldZipFile.FilesCount > 1)
|
||||
{
|
||||
tempsig[16] = 0x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsig[16] = 0;
|
||||
}
|
||||
|
||||
bw.Write(tempsig);
|
||||
bw.Flush();
|
||||
bw.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ using Stream = System.IO.Stream;
|
||||
#endif
|
||||
using Compress;
|
||||
using Compress.ZipFile;
|
||||
using SharpCompress.Readers;
|
||||
using NaturalSort;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
@@ -93,6 +93,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
||||
{
|
||||
zf.ZipFileCloseReadStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -286,6 +287,15 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
||||
{
|
||||
// If the entry is a directory (or looks like a directory), we don't want to open it
|
||||
if (zf.IsDirectory(i)
|
||||
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Open the read stream
|
||||
zr = zf.ZipFileOpenReadStream(i, false, out Stream readStream, out ulong streamsize, out ushort cm);
|
||||
|
||||
@@ -297,15 +307,6 @@ namespace SabreTools.Library.FileTypes
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the entry ends with a directory separator, continue to the next item, if any
|
||||
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
||||
{
|
||||
zr = zf.ZipFileCloseReadStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
// If secure hashes are disabled, do a quickscan
|
||||
if (omitFromScan == Hash.SecureHashes)
|
||||
{
|
||||
@@ -360,27 +361,36 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
SharpCompress.Archives.Zip.ZipArchive za = SharpCompress.Archives.Zip.ZipArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false });
|
||||
List<SharpCompress.Archives.Zip.ZipArchiveEntry> zipEntries = za.Entries.OrderBy(e => e.Key, new NaturalSort.NaturalReversedComparer()).ToList();
|
||||
string lastZipEntry = null;
|
||||
foreach (SharpCompress.Archives.Zip.ZipArchiveEntry entry in zipEntries)
|
||||
ZipFile zf = new ZipFile();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
if (entry != null)
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
List<(string, bool)> zipEntries = new List<(string, bool)>();
|
||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
||||
{
|
||||
zipEntries.Add((zf.Filename(i), zf.IsDirectory(i)));
|
||||
}
|
||||
|
||||
zipEntries = zipEntries.OrderBy(p => p.Item1, new NaturalReversedComparer()).ToList();
|
||||
string lastZipEntry = null;
|
||||
foreach ((string, bool) entry in zipEntries)
|
||||
{
|
||||
// If the current is a superset of last, we skip it
|
||||
if (lastZipEntry != null && lastZipEntry.StartsWith(entry.Key))
|
||||
if (lastZipEntry != null && lastZipEntry.StartsWith(entry.Item1))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
// If the entry is a directory, we add it
|
||||
else
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
if (entry.Item2)
|
||||
{
|
||||
empties.Add(entry.Key);
|
||||
}
|
||||
lastZipEntry = entry.Key;
|
||||
empties.Add(entry.Item1);
|
||||
}
|
||||
lastZipEntry = entry.Item1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,7 +407,14 @@ namespace SabreTools.Library.FileTypes
|
||||
/// </summary>
|
||||
public override bool IsTorrent()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
ZipFile zf = new ZipFile();
|
||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
throw new Exception(ZipFile.ZipErrorMessageText(zr));
|
||||
}
|
||||
|
||||
return zf.ZipStatus == ZipStatus.TrrntZip;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -501,7 +518,7 @@ namespace SabreTools.Library.FileTypes
|
||||
else
|
||||
{
|
||||
// Open the old archive for reading
|
||||
oldZipFile.ZipFileOpen(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, true);
|
||||
oldZipFile.ZipFileOpen(archiveFileName, -1, true);
|
||||
|
||||
// Map all inputs to index
|
||||
Dictionary<string, int> inputIndexMap = new Dictionary<string, int>();
|
||||
@@ -728,7 +745,7 @@ namespace SabreTools.Library.FileTypes
|
||||
else
|
||||
{
|
||||
// Open the old archive for reading
|
||||
oldZipFile.ZipFileOpen(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, true);
|
||||
oldZipFile.ZipFileOpen(archiveFileName, -1, true);
|
||||
|
||||
// Map all inputs to index
|
||||
Dictionary<string, int> inputIndexMap = new Dictionary<string, int>();
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="7za.dll" />
|
||||
<None Remove="Skippers\a7800.xml" />
|
||||
<None Remove="Skippers\fds.xml" />
|
||||
<None Remove="Skippers\lynx.xml" />
|
||||
@@ -61,9 +60,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="7za.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Skippers\a7800.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -100,7 +96,7 @@
|
||||
<PackageReference Include="AlphaFS" Version="2.2.6" />
|
||||
<PackageReference Include="Mono.Data.Sqlite.Portable" Version="1.0.3.5" />
|
||||
<PackageReference Include="SevenZipSharp.Net45" Version="1.0.19" />
|
||||
<PackageReference Include="SharpCompress" Version="0.23.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user