mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
7zip extraction improvements
This commit is contained in:
parent
865a592e09
commit
27f3571951
@ -1,4 +1,6 @@
|
||||
Morrowind BSA,00 01 00 00,TES3, null, null, 0, null
|
||||
TES 4-5 and FO 3 BSA,42 53 41 00,BSA
|
||||
FO4 BSA,42 54 44 58,BA2
|
||||
Relaxed RAR format,52 61 72 21,RAR
|
||||
Relaxed RAR format,52 61 72 21,RAR
|
||||
RAR5 or newer, 52 61 72 21 1A 07 01 00,RAR_NEW
|
||||
RAR4 or older, 52 61 72 21 1A 07 00,RAR_OLD
|
@ -307,6 +307,8 @@ namespace Wabbajack.Common.FileSignatures {
|
||||
RA,
|
||||
RAM,
|
||||
RAR,
|
||||
RAR_NEW,
|
||||
RAR_OLD,
|
||||
RBI,
|
||||
RDATA,
|
||||
REG,
|
||||
@ -443,6 +445,12 @@ namespace Wabbajack.Common.FileSignatures {
|
||||
// Relaxed RAR format
|
||||
(FileType.RAR, new byte[] {0x52, 0x61, 0x72, 0x21}),
|
||||
|
||||
// RAR5 or newer
|
||||
(FileType.RAR_NEW, new byte[] {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00}),
|
||||
|
||||
// RAR4 or older
|
||||
(FileType.RAR_OLD, new byte[] {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00}),
|
||||
|
||||
// JPEG2000 image files
|
||||
(FileType.JP2, new byte[] {0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20}),
|
||||
|
||||
|
@ -7,10 +7,12 @@
|
||||
|
||||
<#
|
||||
|
||||
byte[] StringToByteArray(string hex) {
|
||||
return Enumerable.Range(0, hex.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
||||
byte[] StringToByteArray(string hex)
|
||||
{
|
||||
return Enumerable.Range(0, hex.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var files = new string[] {"bsasigs.txt", "file_sigs_RAW.txt"};
|
||||
|
@ -54,7 +54,7 @@ namespace Wabbajack.Server.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, ex.ToJson());
|
||||
_logger.LogError(ex, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ namespace Wabbajack.VirtualFileSystem
|
||||
foreach (var group in grouped)
|
||||
{
|
||||
var only = group.Select(f => f.RelativeName);
|
||||
var extracted = await group.Key.StagedFile.ExtractAll(Queue, only);
|
||||
var extracted = await group.Key.StagedFile.ExtractAll(Queue, only, true);
|
||||
paths.Add(extracted);
|
||||
foreach (var file in group)
|
||||
file.StagedFile = extracted[file.RelativeName];
|
||||
|
@ -11,6 +11,7 @@ using Wabbajack.Common.StatusFeed;
|
||||
using Wabbajack.Common.StatusFeed.Errors;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.FileSignatures;
|
||||
using Wabbajack.VirtualFileSystem.SevenZipExtractor;
|
||||
using Utils = Wabbajack.Common.Utils;
|
||||
|
||||
|
||||
@ -29,6 +30,8 @@ namespace Wabbajack.VirtualFileSystem
|
||||
|
||||
public static async Task<ExtractedFiles> ExtractAll(WorkQueue queue, AbsolutePath source, IEnumerable<RelativePath> OnlyFiles = null, bool throwOnError = true)
|
||||
{
|
||||
OnlyFiles ??= new RelativePath[0];
|
||||
|
||||
try
|
||||
{
|
||||
var sig = await archiveSigs.MatchesAsync(source);
|
||||
@ -56,6 +59,7 @@ namespace Wabbajack.VirtualFileSystem
|
||||
if (!throwOnError)
|
||||
return new ExtractedFiles(await TempFolder.Create());
|
||||
|
||||
Utils.Log(ex.ToString());
|
||||
Utils.ErrorThrow(ex, $"Error while extracting {source}");
|
||||
throw new Exception();
|
||||
}
|
||||
@ -150,66 +154,23 @@ namespace Wabbajack.VirtualFileSystem
|
||||
|
||||
private static async Task<ExtractedFiles> ExtractAllWith7Zip(AbsolutePath source, IEnumerable<RelativePath> onlyFiles)
|
||||
{
|
||||
TempFile tmpFile = null;
|
||||
var dest = await TempFolder.Create();
|
||||
Utils.Log(new GenericInfo($"Extracting {(string)source.FileName}", $"The contents of {(string)source.FileName} are being extracted to {(string)source.FileName} using 7zip.exe"));
|
||||
|
||||
var process = new ProcessHelper
|
||||
{
|
||||
Path = @"Extractors\7z.exe".RelativeTo(AbsolutePath.EntryPoint),
|
||||
|
||||
};
|
||||
var files = onlyFiles.ToHashSet();
|
||||
|
||||
if (onlyFiles != null)
|
||||
using var archive = await ArchiveFile.Open(source);
|
||||
if (files.Count > 0)
|
||||
{
|
||||
//It's stupid that we have to do this, but 7zip's file pattern matching isn't very fuzzy
|
||||
IEnumerable<string> AllVariants(string input)
|
||||
await archive.Extract(path =>
|
||||
{
|
||||
yield return $"\"{input}\"";
|
||||
yield return $"\"\\{input}\"";
|
||||
}
|
||||
|
||||
tmpFile = new TempFile();
|
||||
await tmpFile.Path.WriteAllLinesAsync(onlyFiles.SelectMany(f => AllVariants((string)f)).ToArray());
|
||||
process.Arguments = new object[]
|
||||
{
|
||||
"x", "-bsp1", "-y", $"-o\"{dest.Dir}\"", source, $"@\"{tmpFile.Path}\"", "-mmt=off"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
process.Arguments = new object[] {"x", "-bsp1", "-y", $"-o\"{dest.Dir}\"", source, "-mmt=off"};
|
||||
}
|
||||
|
||||
|
||||
var result = process.Output.Where(d => d.Type == ProcessHelper.StreamType.Output)
|
||||
.ForEachAsync(p =>
|
||||
{
|
||||
var (_, line) = p;
|
||||
if (line == null)
|
||||
return;
|
||||
|
||||
if (line.Length <= 4 || line[3] != '%') return;
|
||||
|
||||
int.TryParse(line.Substring(0, 3), out var percentInt);
|
||||
Utils.Status($"Extracting {(string)source.FileName} - {line.Trim()}", Percent.FactoryPutInRange(percentInt / 100d));
|
||||
Utils.Log($"Extract file {path} {files.Contains(path)} {dest.Dir.Combine(path)}");
|
||||
return files.Contains(path) ? dest.Dir.Combine(path) : default;
|
||||
});
|
||||
|
||||
var exitCode = await process.Start();
|
||||
|
||||
|
||||
if (exitCode != 0)
|
||||
{
|
||||
Utils.ErrorThrow(new _7zipReturnError(exitCode, source, dest.Dir, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.Status($"Extracting {source.FileName} - done", Percent.One, alsoLog: true);
|
||||
}
|
||||
|
||||
if (tmpFile != null)
|
||||
{
|
||||
await tmpFile.DisposeAsync();
|
||||
await archive.Extract(path => dest.Dir.Combine(path));
|
||||
}
|
||||
|
||||
return new ExtractedFiles(dest);
|
||||
|
257
Wabbajack.VirtualFileSystem/SevenZipExtractor/ArchiveFile.cs
Normal file
257
Wabbajack.VirtualFileSystem/SevenZipExtractor/ArchiveFile.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.FileSignatures;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
public class ArchiveFile : IDisposable
|
||||
{
|
||||
private SevenZipHandle _sevenZipHandle;
|
||||
private IInArchive _archive;
|
||||
private InStreamWrapper _archiveStream;
|
||||
private IList<Entry> _entries;
|
||||
|
||||
private static readonly AbsolutePath LibraryFilePath = @"Extractors\7z.dll".RelativeTo(AbsolutePath.EntryPoint);
|
||||
private static SignatureChecker _checker = new SignatureChecker(Formats.FileTypeGuidMapping.Keys.ToArray());
|
||||
|
||||
public static async Task<ArchiveFile> Open(AbsolutePath archiveFilePath)
|
||||
{
|
||||
var self = new ArchiveFile();
|
||||
|
||||
self.InitializeAndValidateLibrary();
|
||||
|
||||
if (!archiveFilePath.IsFile)
|
||||
{
|
||||
throw new SevenZipException("Archive file not found");
|
||||
}
|
||||
|
||||
var format = await _checker.MatchesAsync(archiveFilePath);
|
||||
|
||||
if (format == null)
|
||||
{
|
||||
throw new SevenZipException($"Unknown format for {archiveFilePath}");
|
||||
}
|
||||
|
||||
self._archive = self._sevenZipHandle.CreateInArchive(Formats.FileTypeGuidMapping[format.Value]);
|
||||
self._archiveStream = new InStreamWrapper(await archiveFilePath.OpenRead());
|
||||
return self;
|
||||
}
|
||||
|
||||
public static async Task<ArchiveFile> Open(Stream archiveStream, SevenZipFormat? format = null, string libraryFilePath = null)
|
||||
{
|
||||
var self = new ArchiveFile();
|
||||
self.InitializeAndValidateLibrary();
|
||||
self._archive = self._sevenZipHandle.CreateInArchive(Formats.FormatGuidMapping[SevenZipFormat.SevenZip]);
|
||||
self._archiveStream = new InStreamWrapper(archiveStream);
|
||||
return self;
|
||||
}
|
||||
|
||||
public async Task Extract(AbsolutePath outputFolder, bool overwrite = false)
|
||||
{
|
||||
await this.Extract(entry =>
|
||||
{
|
||||
var fileName = outputFolder.Combine(entry.FileName);
|
||||
|
||||
if (!fileName.Exists || overwrite)
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
return default;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task Extract(Func<RelativePath, AbsolutePath> getOutputPath)
|
||||
{
|
||||
IList<Stream> fileStreams = new List<Stream>();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (Entry entry in Entries)
|
||||
{
|
||||
|
||||
AbsolutePath outputPath = entry.IsFolder ? default : getOutputPath((RelativePath)entry.FileName);
|
||||
|
||||
if (outputPath == default) // getOutputPath = null means SKIP
|
||||
{
|
||||
fileStreams.Add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.IsFolder)
|
||||
{
|
||||
outputPath.CreateDirectory();
|
||||
fileStreams.Add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
var directoryName = outputPath.Parent;
|
||||
directoryName.CreateDirectory();
|
||||
|
||||
fileStreams.Add(await outputPath.Create());
|
||||
}
|
||||
|
||||
this._archive.Extract(null, 0xFFFFFFFF, 0, new ArchiveStreamsCallback(fileStreams));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Stream stream in fileStreams)
|
||||
{
|
||||
if (stream == null) continue;
|
||||
var tsk = stream?.DisposeAsync();
|
||||
await tsk.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IList<Entry> Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._entries != null)
|
||||
{
|
||||
return this._entries;
|
||||
}
|
||||
|
||||
ulong checkPos = 32 * 1024;
|
||||
int open = this._archive.Open(this._archiveStream, ref checkPos, null);
|
||||
|
||||
if (open != 0)
|
||||
{
|
||||
throw new SevenZipException("Unable to open archive");
|
||||
}
|
||||
|
||||
uint itemsCount = this._archive.GetNumberOfItems();
|
||||
|
||||
this._entries = new List<Entry>();
|
||||
|
||||
for (uint fileIndex = 0; fileIndex < itemsCount; fileIndex++)
|
||||
{
|
||||
string fileName = this.GetProperty<string>(fileIndex, ItemPropId.kpidPath);
|
||||
bool isFolder = this.GetProperty<bool>(fileIndex, ItemPropId.kpidIsFolder);
|
||||
bool isEncrypted = this.GetProperty<bool>(fileIndex, ItemPropId.kpidEncrypted);
|
||||
ulong size = this.GetProperty<ulong>(fileIndex, ItemPropId.kpidSize);
|
||||
ulong packedSize = this.GetProperty<ulong>(fileIndex, ItemPropId.kpidPackedSize);
|
||||
DateTime creationTime = this.GetPropertySafe<DateTime>(fileIndex, ItemPropId.kpidCreationTime);
|
||||
DateTime lastWriteTime = this.GetPropertySafe<DateTime>(fileIndex, ItemPropId.kpidLastWriteTime);
|
||||
DateTime lastAccessTime = this.GetPropertySafe<DateTime>(fileIndex, ItemPropId.kpidLastAccessTime);
|
||||
uint crc = this.GetPropertySafe<uint>(fileIndex, ItemPropId.kpidCRC);
|
||||
uint attributes = this.GetPropertySafe<uint>(fileIndex, ItemPropId.kpidAttributes);
|
||||
string comment = this.GetPropertySafe<string>(fileIndex, ItemPropId.kpidComment);
|
||||
string hostOS = this.GetPropertySafe<string>(fileIndex, ItemPropId.kpidHostOS);
|
||||
string method = this.GetPropertySafe<string>(fileIndex, ItemPropId.kpidMethod);
|
||||
|
||||
bool isSplitBefore = this.GetPropertySafe<bool>(fileIndex, ItemPropId.kpidSplitBefore);
|
||||
bool isSplitAfter = this.GetPropertySafe<bool>(fileIndex, ItemPropId.kpidSplitAfter);
|
||||
|
||||
this._entries.Add(new Entry(this._archive, fileIndex)
|
||||
{
|
||||
FileName = fileName,
|
||||
IsFolder = isFolder,
|
||||
IsEncrypted = isEncrypted,
|
||||
Size = size,
|
||||
PackedSize = packedSize,
|
||||
CreationTime = creationTime,
|
||||
LastWriteTime = lastWriteTime,
|
||||
LastAccessTime = lastAccessTime,
|
||||
CRC = crc,
|
||||
Attributes = attributes,
|
||||
Comment = comment,
|
||||
HostOS = hostOS,
|
||||
Method = method,
|
||||
IsSplitBefore = isSplitBefore,
|
||||
IsSplitAfter = isSplitAfter
|
||||
});
|
||||
}
|
||||
|
||||
return this._entries;
|
||||
}
|
||||
}
|
||||
|
||||
private T GetPropertySafe<T>(uint fileIndex, ItemPropId name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.GetProperty<T>(fileIndex, name);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
private T GetProperty<T>(uint fileIndex, ItemPropId name)
|
||||
{
|
||||
PropVariant propVariant = new PropVariant();
|
||||
this._archive.GetProperty(fileIndex, name, ref propVariant);
|
||||
object value = propVariant.GetObject();
|
||||
|
||||
if (propVariant.VarType == VarEnum.VT_EMPTY)
|
||||
{
|
||||
propVariant.Clear();
|
||||
return default(T);
|
||||
}
|
||||
|
||||
propVariant.Clear();
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
Type type = typeof(T);
|
||||
bool isNullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
Type underlyingType = isNullable ? Nullable.GetUnderlyingType(type) : type;
|
||||
|
||||
T result = (T)Convert.ChangeType(value.ToString(), underlyingType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InitializeAndValidateLibrary()
|
||||
{
|
||||
try
|
||||
{
|
||||
this._sevenZipHandle = new SevenZipHandle((string)LibraryFilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SevenZipException("Unable to initialize SevenZipHandle", e);
|
||||
}
|
||||
}
|
||||
|
||||
~ArchiveFile()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (this._archiveStream != null)
|
||||
{
|
||||
this._archiveStream.Dispose();
|
||||
}
|
||||
|
||||
if (this._archive != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(this._archive);
|
||||
}
|
||||
|
||||
if (this._sevenZipHandle != null)
|
||||
{
|
||||
this._sevenZipHandle.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal class ArchiveFileCallback : IArchiveExtractCallback
|
||||
{
|
||||
private readonly string fileName;
|
||||
private readonly uint fileNumber;
|
||||
private OutStreamWrapper fileStream; // to be removed
|
||||
|
||||
public ArchiveFileCallback(uint fileNumber, string fileName)
|
||||
{
|
||||
this.fileNumber = fileNumber;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public void SetTotal(ulong total)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCompleted(ref ulong completeValue)
|
||||
{
|
||||
}
|
||||
|
||||
public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode)
|
||||
{
|
||||
if ((index != this.fileNumber) || (askExtractMode != AskMode.kExtract))
|
||||
{
|
||||
outStream = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
string fileDir = Path.GetDirectoryName(this.fileName);
|
||||
|
||||
if (!string.IsNullOrEmpty(fileDir))
|
||||
{
|
||||
Directory.CreateDirectory(fileDir);
|
||||
}
|
||||
|
||||
this.fileStream = new OutStreamWrapper(File.Create(this.fileName));
|
||||
|
||||
outStream = this.fileStream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrepareOperation(AskMode askExtractMode)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetOperationResult(OperationResult resultEOperationResult)
|
||||
{
|
||||
this.fileStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal class ArchiveStreamCallback : IArchiveExtractCallback
|
||||
{
|
||||
private readonly uint fileNumber;
|
||||
private readonly Stream stream;
|
||||
|
||||
public ArchiveStreamCallback(uint fileNumber, Stream stream)
|
||||
{
|
||||
this.fileNumber = fileNumber;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public void SetTotal(ulong total)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCompleted(ref ulong completeValue)
|
||||
{
|
||||
}
|
||||
|
||||
public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode)
|
||||
{
|
||||
if ((index != this.fileNumber) || (askExtractMode != AskMode.kExtract))
|
||||
{
|
||||
outStream = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outStream = new OutStreamWrapper(this.stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrepareOperation(AskMode askExtractMode)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetOperationResult(OperationResult resultEOperationResult)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal class ArchiveStreamsCallback : IArchiveExtractCallback
|
||||
{
|
||||
private readonly IList<Stream> streams;
|
||||
|
||||
public ArchiveStreamsCallback(IList<Stream> streams)
|
||||
{
|
||||
this.streams = streams;
|
||||
}
|
||||
|
||||
public void SetTotal(ulong total)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCompleted(ref ulong completeValue)
|
||||
{
|
||||
}
|
||||
|
||||
public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode)
|
||||
{
|
||||
if (askExtractMode != AskMode.kExtract)
|
||||
{
|
||||
outStream = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this.streams == null)
|
||||
{
|
||||
outStream = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Stream stream = this.streams[(int) index];
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
outStream = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outStream = new OutStreamWrapper(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrepareOperation(AskMode askExtractMode)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetOperationResult(OperationResult resultEOperationResult)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
119
Wabbajack.VirtualFileSystem/SevenZipExtractor/Entry.cs
Normal file
119
Wabbajack.VirtualFileSystem/SevenZipExtractor/Entry.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
public class Entry
|
||||
{
|
||||
private readonly IInArchive archive;
|
||||
private readonly uint index;
|
||||
|
||||
internal Entry(IInArchive archive, uint index)
|
||||
{
|
||||
this.archive = archive;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the file with its relative path within the archive
|
||||
/// </summary>
|
||||
public string FileName { get; internal set; }
|
||||
/// <summary>
|
||||
/// True if entry is a folder, false if it is a file
|
||||
/// </summary>
|
||||
public bool IsFolder { get; internal set; }
|
||||
/// <summary>
|
||||
/// Original entry size
|
||||
/// </summary>
|
||||
public ulong Size { get; internal set; }
|
||||
/// <summary>
|
||||
/// Entry size in a archived state
|
||||
/// </summary>
|
||||
public ulong PackedSize { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date and time of the file (entry) creation
|
||||
/// </summary>
|
||||
public DateTime CreationTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date and time of the last change of the file (entry)
|
||||
/// </summary>
|
||||
public DateTime LastWriteTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date and time of the last access of the file (entry)
|
||||
/// </summary>
|
||||
public DateTime LastAccessTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// CRC hash of the entry
|
||||
/// </summary>
|
||||
public UInt32 CRC { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attributes of the entry
|
||||
/// </summary>
|
||||
public UInt32 Attributes { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if entry is encrypted, otherwise false
|
||||
/// </summary>
|
||||
public bool IsEncrypted { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comment of the entry
|
||||
/// </summary>
|
||||
public string Comment { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compression method of the entry
|
||||
/// </summary>
|
||||
public string Method { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Host operating system of the entry
|
||||
/// </summary>
|
||||
public string HostOS { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if there are parts of this file in previous split archive parts
|
||||
/// </summary>
|
||||
public bool IsSplitBefore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if there are parts of this file in next split archive parts
|
||||
/// </summary>
|
||||
public bool IsSplitAfter { get; set; }
|
||||
|
||||
public void Extract(string fileName, bool preserveTimestamp = true)
|
||||
{
|
||||
if (this.IsFolder)
|
||||
{
|
||||
Directory.CreateDirectory(fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
string directoryName = Path.GetDirectoryName(fileName);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
}
|
||||
|
||||
using (FileStream fileStream = File.Create(fileName))
|
||||
{
|
||||
this.Extract(fileStream);
|
||||
}
|
||||
|
||||
if (preserveTimestamp)
|
||||
{
|
||||
File.SetLastWriteTime(fileName, this.LastWriteTime);
|
||||
}
|
||||
}
|
||||
public void Extract(Stream stream)
|
||||
{
|
||||
this.archive.Extract(new[] { this.index }, 1, 0, new ArchiveStreamCallback(this.index, stream));
|
||||
}
|
||||
}
|
||||
}
|
122
Wabbajack.VirtualFileSystem/SevenZipExtractor/Formats.cs
Normal file
122
Wabbajack.VirtualFileSystem/SevenZipExtractor/Formats.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Wabbajack.Common.FileSignatures;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
public class Formats
|
||||
{
|
||||
internal static readonly Dictionary<string, SevenZipFormat> ExtensionFormatMapping = new Dictionary<string, SevenZipFormat>
|
||||
{
|
||||
{"7z", SevenZipFormat.SevenZip},
|
||||
{"gz", SevenZipFormat.GZip},
|
||||
{"tar", SevenZipFormat.Tar},
|
||||
{"rar", SevenZipFormat.Rar},
|
||||
{"zip", SevenZipFormat.Zip},
|
||||
{"lzma", SevenZipFormat.Lzma},
|
||||
{"lzh", SevenZipFormat.Lzh},
|
||||
{"arj", SevenZipFormat.Arj},
|
||||
{"bz2", SevenZipFormat.BZip2},
|
||||
{"cab", SevenZipFormat.Cab},
|
||||
{"chm", SevenZipFormat.Chm},
|
||||
{"deb", SevenZipFormat.Deb},
|
||||
{"iso", SevenZipFormat.Iso},
|
||||
{"rpm", SevenZipFormat.Rpm},
|
||||
{"wim", SevenZipFormat.Wim},
|
||||
{"udf", SevenZipFormat.Udf},
|
||||
{"mub", SevenZipFormat.Mub},
|
||||
{"xar", SevenZipFormat.Xar},
|
||||
{"hfs", SevenZipFormat.Hfs},
|
||||
{"dmg", SevenZipFormat.Dmg},
|
||||
{"z", SevenZipFormat.Lzw},
|
||||
{"xz", SevenZipFormat.XZ},
|
||||
{"flv", SevenZipFormat.Flv},
|
||||
{"swf", SevenZipFormat.Swf},
|
||||
{"exe", SevenZipFormat.PE},
|
||||
{"dll", SevenZipFormat.PE},
|
||||
{"vhd", SevenZipFormat.Vhd}
|
||||
};
|
||||
|
||||
internal static Dictionary<SevenZipFormat, Guid> FormatGuidMapping = new Dictionary<SevenZipFormat, Guid>
|
||||
{
|
||||
{SevenZipFormat.SevenZip, new Guid("23170f69-40c1-278a-1000-000110070000")},
|
||||
{SevenZipFormat.Arj, new Guid("23170f69-40c1-278a-1000-000110040000")},
|
||||
{SevenZipFormat.BZip2, new Guid("23170f69-40c1-278a-1000-000110020000")},
|
||||
{SevenZipFormat.Cab, new Guid("23170f69-40c1-278a-1000-000110080000")},
|
||||
{SevenZipFormat.Chm, new Guid("23170f69-40c1-278a-1000-000110e90000")},
|
||||
{SevenZipFormat.Compound, new Guid("23170f69-40c1-278a-1000-000110e50000")},
|
||||
{SevenZipFormat.Cpio, new Guid("23170f69-40c1-278a-1000-000110ed0000")},
|
||||
{SevenZipFormat.Deb, new Guid("23170f69-40c1-278a-1000-000110ec0000")},
|
||||
{SevenZipFormat.GZip, new Guid("23170f69-40c1-278a-1000-000110ef0000")},
|
||||
{SevenZipFormat.Iso, new Guid("23170f69-40c1-278a-1000-000110e70000")},
|
||||
{SevenZipFormat.Lzh, new Guid("23170f69-40c1-278a-1000-000110060000")},
|
||||
{SevenZipFormat.Lzma, new Guid("23170f69-40c1-278a-1000-0001100a0000")},
|
||||
{SevenZipFormat.Nsis, new Guid("23170f69-40c1-278a-1000-000110090000")},
|
||||
{SevenZipFormat.Rar, new Guid("23170f69-40c1-278a-1000-000110030000")},
|
||||
{SevenZipFormat.Rar5, new Guid("23170f69-40c1-278a-1000-000110CC0000")},
|
||||
{SevenZipFormat.Rpm, new Guid("23170f69-40c1-278a-1000-000110eb0000")},
|
||||
{SevenZipFormat.Split, new Guid("23170f69-40c1-278a-1000-000110ea0000")},
|
||||
{SevenZipFormat.Tar, new Guid("23170f69-40c1-278a-1000-000110ee0000")},
|
||||
{SevenZipFormat.Wim, new Guid("23170f69-40c1-278a-1000-000110e60000")},
|
||||
{SevenZipFormat.Lzw, new Guid("23170f69-40c1-278a-1000-000110050000")},
|
||||
{SevenZipFormat.Zip, new Guid("23170f69-40c1-278a-1000-000110010000")},
|
||||
{SevenZipFormat.Udf, new Guid("23170f69-40c1-278a-1000-000110E00000")},
|
||||
{SevenZipFormat.Xar, new Guid("23170f69-40c1-278a-1000-000110E10000")},
|
||||
{SevenZipFormat.Mub, new Guid("23170f69-40c1-278a-1000-000110E20000")},
|
||||
{SevenZipFormat.Hfs, new Guid("23170f69-40c1-278a-1000-000110E30000")},
|
||||
{SevenZipFormat.Dmg, new Guid("23170f69-40c1-278a-1000-000110E40000")},
|
||||
{SevenZipFormat.XZ, new Guid("23170f69-40c1-278a-1000-0001100C0000")},
|
||||
{SevenZipFormat.Mslz, new Guid("23170f69-40c1-278a-1000-000110D50000")},
|
||||
{SevenZipFormat.PE, new Guid("23170f69-40c1-278a-1000-000110DD0000")},
|
||||
{SevenZipFormat.Elf, new Guid("23170f69-40c1-278a-1000-000110DE0000")},
|
||||
{SevenZipFormat.Swf, new Guid("23170f69-40c1-278a-1000-000110D70000")},
|
||||
{SevenZipFormat.Vhd, new Guid("23170f69-40c1-278a-1000-000110DC0000")},
|
||||
{SevenZipFormat.Flv, new Guid("23170f69-40c1-278a-1000-000110D60000")},
|
||||
{SevenZipFormat.SquashFS, new Guid("23170f69-40c1-278a-1000-000110D20000")},
|
||||
{SevenZipFormat.Lzma86, new Guid("23170f69-40c1-278a-1000-0001100B0000")},
|
||||
{SevenZipFormat.Ppmd, new Guid("23170f69-40c1-278a-1000-0001100D0000")},
|
||||
{SevenZipFormat.TE, new Guid("23170f69-40c1-278a-1000-000110CF0000")},
|
||||
{SevenZipFormat.UEFIc, new Guid("23170f69-40c1-278a-1000-000110D00000")},
|
||||
{SevenZipFormat.UEFIs, new Guid("23170f69-40c1-278a-1000-000110D10000")},
|
||||
{SevenZipFormat.CramFS, new Guid("23170f69-40c1-278a-1000-000110D30000")},
|
||||
{SevenZipFormat.APM, new Guid("23170f69-40c1-278a-1000-000110D40000")},
|
||||
{SevenZipFormat.Swfc, new Guid("23170f69-40c1-278a-1000-000110D80000")},
|
||||
{SevenZipFormat.Ntfs, new Guid("23170f69-40c1-278a-1000-000110D90000")},
|
||||
{SevenZipFormat.Fat, new Guid("23170f69-40c1-278a-1000-000110DA0000")},
|
||||
{SevenZipFormat.Mbr, new Guid("23170f69-40c1-278a-1000-000110DB0000")},
|
||||
{SevenZipFormat.MachO, new Guid("23170f69-40c1-278a-1000-000110DF0000")}
|
||||
};
|
||||
|
||||
internal static Dictionary<Definitions.FileType, Guid> FileTypeGuidMapping = new Dictionary<Definitions.FileType, Guid>
|
||||
{
|
||||
{Definitions.FileType._7Z, new Guid("23170f69-40c1-278a-1000-000110070000")},
|
||||
{Definitions.FileType.BZ2, new Guid("23170f69-40c1-278a-1000-000110020000")},
|
||||
{Definitions.FileType.RAR_NEW, new Guid("23170f69-40c1-278a-1000-000110030000")},
|
||||
{Definitions.FileType.RAR_OLD, new Guid("23170f69-40c1-278a-1000-000110CC0000")},
|
||||
{Definitions.FileType.ZIP, new Guid("23170f69-40c1-278a-1000-000110010000")},
|
||||
};
|
||||
|
||||
internal static Dictionary<SevenZipFormat, byte[]> FileSignatures = new Dictionary<SevenZipFormat, byte[]>
|
||||
{
|
||||
{SevenZipFormat.Rar5, new byte[] {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00}},
|
||||
{SevenZipFormat.Rar, new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 }},
|
||||
{SevenZipFormat.Vhd, new byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 }},
|
||||
{SevenZipFormat.Deb, new byte[] { 0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E }},
|
||||
{SevenZipFormat.Dmg, new byte[] { 0x78, 0x01, 0x73, 0x0D, 0x62, 0x62, 0x60 }},
|
||||
{SevenZipFormat.SevenZip, new byte[] { 0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C }},
|
||||
{SevenZipFormat.Tar, new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72 }},
|
||||
{SevenZipFormat.Iso, new byte[] { 0x43, 0x44, 0x30, 0x30, 0x31 }},
|
||||
{SevenZipFormat.Cab, new byte[] { 0x4D, 0x53, 0x43, 0x46 }},
|
||||
{SevenZipFormat.Rpm, new byte[] { 0xed, 0xab, 0xee, 0xdb }},
|
||||
{SevenZipFormat.Xar, new byte[] { 0x78, 0x61, 0x72, 0x21 }},
|
||||
{SevenZipFormat.Chm, new byte[] { 0x49, 0x54, 0x53, 0x46 }},
|
||||
{SevenZipFormat.BZip2, new byte[] { 0x42, 0x5A, 0x68 }},
|
||||
{SevenZipFormat.Flv, new byte[] { 0x46, 0x4C, 0x56 }},
|
||||
{SevenZipFormat.Swf, new byte[] { 0x46, 0x57, 0x53 }},
|
||||
{SevenZipFormat.GZip, new byte[] { 0x1f, 0x0b }},
|
||||
{SevenZipFormat.Zip, new byte[] { 0x50, 0x4b }},
|
||||
{SevenZipFormat.Arj, new byte[] { 0x60, 0xEA }},
|
||||
{SevenZipFormat.Lzh, new byte[] { 0x2D, 0x6C, 0x68 }}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000600200000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IArchiveExtractCallback //: IProgress
|
||||
{
|
||||
void SetTotal(ulong total);
|
||||
void SetCompleted([In] ref ulong completeValue);
|
||||
|
||||
[PreserveSig]
|
||||
int GetStream(
|
||||
uint index,
|
||||
[MarshalAs(UnmanagedType.Interface)] out ISequentialOutStream outStream,
|
||||
AskMode askExtractMode);
|
||||
// GetStream OUT: S_OK - OK, S_FALSE - skeep this file
|
||||
|
||||
void PrepareOperation(AskMode askExtractMode);
|
||||
void SetOperationResult(OperationResult resultEOperationResult);
|
||||
}
|
||||
}
|
20
Wabbajack.VirtualFileSystem/SevenZipExtractor/Kernel32Dll.cs
Normal file
20
Wabbajack.VirtualFileSystem/SevenZipExtractor/Kernel32Dll.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal static class Kernel32Dll
|
||||
{
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern SafeLibraryHandle LoadLibrary([MarshalAs(UnmanagedType.LPTStr)] string lpFileName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern IntPtr GetProcAddress(SafeLibraryHandle hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool FreeLibrary(IntPtr hModule);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
public SafeLibraryHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Release library handle</summary>
|
||||
/// <returns>true if the handle was released</returns>
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return Kernel32Dll.FreeLibrary(this.handle);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
public class SevenZipException : Exception
|
||||
{
|
||||
public SevenZipException()
|
||||
{
|
||||
}
|
||||
|
||||
public SevenZipException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SevenZipException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected SevenZipException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
285
Wabbajack.VirtualFileSystem/SevenZipExtractor/SevenZipFormat.cs
Normal file
285
Wabbajack.VirtualFileSystem/SevenZipExtractor/SevenZipFormat.cs
Normal file
@ -0,0 +1,285 @@
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum SevenZipFormat
|
||||
{
|
||||
// Default invalid format value
|
||||
Undefined = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Open 7-zip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/7-zip">Wikipedia information</a></remarks>
|
||||
SevenZip,
|
||||
|
||||
/// <summary>
|
||||
/// Proprietary Arj archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/ARJ">Wikipedia information</a></remarks>
|
||||
Arj,
|
||||
|
||||
/// <summary>
|
||||
/// Open Bzip2 archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Bzip2">Wikipedia information</a></remarks>
|
||||
BZip2,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft cabinet archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Cabinet_(file_format)">Wikipedia information</a></remarks>
|
||||
Cab,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft Compiled HTML Help file format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Microsoft_Compiled_HTML_Help">Wikipedia information</a></remarks>
|
||||
Chm,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft Compound file format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Compound_File_Binary_Format">Wikipedia information</a></remarks>
|
||||
Compound,
|
||||
|
||||
/// <summary>
|
||||
/// Open Cpio archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Cpio">Wikipedia information</a></remarks>
|
||||
Cpio,
|
||||
|
||||
/// <summary>
|
||||
/// Open Debian software package format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Deb_(file_format)">Wikipedia information</a></remarks>
|
||||
Deb,
|
||||
|
||||
/// <summary>
|
||||
/// Open Gzip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Gzip">Wikipedia information</a></remarks>
|
||||
GZip,
|
||||
|
||||
/// <summary>
|
||||
/// Open ISO disk image format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/ISO_image">Wikipedia information</a></remarks>
|
||||
Iso,
|
||||
|
||||
/// <summary>
|
||||
/// Open Lzh archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Lzh">Wikipedia information</a></remarks>
|
||||
Lzh,
|
||||
|
||||
/// <summary>
|
||||
/// Open core 7-zip Lzma raw archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Lzma">Wikipedia information</a></remarks>
|
||||
Lzma,
|
||||
|
||||
/// <summary>
|
||||
/// Nullsoft installation package format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/NSIS">Wikipedia information</a></remarks>
|
||||
Nsis,
|
||||
|
||||
/// <summary>
|
||||
/// RarLab Rar archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/RAR_(file_format)">Wikipedia information</a></remarks>
|
||||
Rar,
|
||||
|
||||
/// <summary>
|
||||
/// RarLab Rar archive format, version 5.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/RAR_(file_format)">Wikipedia information</a></remarks>
|
||||
Rar5,
|
||||
|
||||
/// <summary>
|
||||
/// Open Rpm software package format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/RPM_Package_Manager">Wikipedia information</a></remarks>
|
||||
Rpm,
|
||||
|
||||
/// <summary>
|
||||
/// Open split file format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="?">Wikipedia information</a></remarks>
|
||||
Split,
|
||||
|
||||
/// <summary>
|
||||
/// Open Tar archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Tar_(file_format)">Wikipedia information</a></remarks>
|
||||
Tar,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft Windows Imaging disk image format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Windows_Imaging_Format">Wikipedia information</a></remarks>
|
||||
Wim,
|
||||
|
||||
/// <summary>
|
||||
/// Open LZW archive format; implemented in "compress" program; also known as "Z" archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Compress">Wikipedia information</a></remarks>
|
||||
Lzw,
|
||||
|
||||
/// <summary>
|
||||
/// Open Zip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/ZIP_(file_format)">Wikipedia information</a></remarks>
|
||||
Zip,
|
||||
|
||||
/// <summary>
|
||||
/// Open Udf disk image format.
|
||||
/// </summary>
|
||||
Udf,
|
||||
|
||||
/// <summary>
|
||||
/// Xar open source archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Xar_(archiver)">Wikipedia information</a></remarks>
|
||||
Xar,
|
||||
|
||||
/// <summary>
|
||||
/// Mub
|
||||
/// </summary>
|
||||
Mub,
|
||||
|
||||
/// <summary>
|
||||
/// Macintosh Disk Image on CD.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/HFS_Plus">Wikipedia information</a></remarks>
|
||||
Hfs,
|
||||
|
||||
/// <summary>
|
||||
/// Apple Mac OS X Disk Copy Disk Image format.
|
||||
/// </summary>
|
||||
Dmg,
|
||||
|
||||
/// <summary>
|
||||
/// Open Xz archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Xz">Wikipedia information</a></remarks>
|
||||
XZ,
|
||||
|
||||
/// <summary>
|
||||
/// MSLZ archive format.
|
||||
/// </summary>
|
||||
Mslz,
|
||||
|
||||
/// <summary>
|
||||
/// Flash video format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Flv">Wikipedia information</a></remarks>
|
||||
Flv,
|
||||
|
||||
/// <summary>
|
||||
/// Shockwave Flash format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Swf">Wikipedia information</a></remarks>
|
||||
Swf,
|
||||
|
||||
/// <summary>
|
||||
/// Windows PE executable format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Portable_Executable">Wikipedia information</a></remarks>
|
||||
PE,
|
||||
|
||||
/// <summary>
|
||||
/// Linux executable Elf format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Executable_and_Linkable_Format">Wikipedia information</a></remarks>
|
||||
Elf,
|
||||
|
||||
/// <summary>
|
||||
/// Windows Installer Database.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Windows_Installer">Wikipedia information</a></remarks>
|
||||
Msi,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft virtual hard disk file format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/VHD_%28file_format%29">Wikipedia information</a></remarks>
|
||||
Vhd,
|
||||
|
||||
/// <summary>
|
||||
/// SquashFS file system format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/SquashFS">Wikipedia information</a></remarks>
|
||||
SquashFS,
|
||||
|
||||
/// <summary>
|
||||
/// Lzma86 file format.
|
||||
/// </summary>
|
||||
Lzma86,
|
||||
|
||||
/// <summary>
|
||||
/// Prediction by Partial Matching by Dmitry algorithm.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Prediction_by_partial_matching">Wikipedia information</a></remarks>
|
||||
Ppmd,
|
||||
|
||||
/// <summary>
|
||||
/// TE format.
|
||||
/// </summary>
|
||||
TE,
|
||||
|
||||
/// <summary>
|
||||
/// UEFIc format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface">Wikipedia information</a></remarks>
|
||||
UEFIc,
|
||||
|
||||
/// <summary>
|
||||
/// UEFIs format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface">Wikipedia information</a></remarks>
|
||||
UEFIs,
|
||||
|
||||
/// <summary>
|
||||
/// Compressed ROM file system format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Cramfs">Wikipedia information</a></remarks>
|
||||
CramFS,
|
||||
|
||||
/// <summary>
|
||||
/// APM format.
|
||||
/// </summary>
|
||||
APM,
|
||||
|
||||
/// <summary>
|
||||
/// Swfc format.
|
||||
/// </summary>
|
||||
Swfc,
|
||||
|
||||
/// <summary>
|
||||
/// NTFS file system format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/NTFS">Wikipedia information</a></remarks>
|
||||
Ntfs,
|
||||
|
||||
/// <summary>
|
||||
/// FAT file system format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/File_Allocation_Table">Wikipedia information</a></remarks>
|
||||
Fat,
|
||||
|
||||
/// <summary>
|
||||
/// MBR format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Master_boot_record">Wikipedia information</a></remarks>
|
||||
Mbr,
|
||||
|
||||
/// <summary>
|
||||
/// Mach-O file format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="https://en.wikipedia.org/wiki/Mach-O">Wikipedia information</a></remarks>
|
||||
MachO
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
internal class SevenZipHandle : IDisposable
|
||||
{
|
||||
private SafeLibraryHandle sevenZipSafeHandle;
|
||||
|
||||
public SevenZipHandle(string sevenZipLibPath)
|
||||
{
|
||||
this.sevenZipSafeHandle = Kernel32Dll.LoadLibrary(sevenZipLibPath);
|
||||
|
||||
if (this.sevenZipSafeHandle.IsInvalid)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
IntPtr functionPtr = Kernel32Dll.GetProcAddress(this.sevenZipSafeHandle, "GetHandlerProperty");
|
||||
|
||||
// Not valid dll
|
||||
if (functionPtr == IntPtr.Zero)
|
||||
{
|
||||
this.sevenZipSafeHandle.Close();
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
~SevenZipHandle()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if ((this.sevenZipSafeHandle != null) && !this.sevenZipSafeHandle.IsClosed)
|
||||
{
|
||||
this.sevenZipSafeHandle.Close();
|
||||
}
|
||||
|
||||
this.sevenZipSafeHandle = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public IInArchive CreateInArchive(Guid classId)
|
||||
{
|
||||
if (this.sevenZipSafeHandle == null)
|
||||
{
|
||||
throw new ObjectDisposedException("SevenZipHandle");
|
||||
}
|
||||
|
||||
IntPtr procAddress = Kernel32Dll.GetProcAddress(this.sevenZipSafeHandle, "CreateObject");
|
||||
CreateObjectDelegate createObject = (CreateObjectDelegate) Marshal.GetDelegateForFunctionPointer(procAddress, typeof (CreateObjectDelegate));
|
||||
|
||||
object result;
|
||||
Guid interfaceId = typeof (IInArchive).GUID;
|
||||
createObject(ref classId, ref interfaceId, out result);
|
||||
|
||||
return result as IInArchive;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,459 @@
|
||||
// Version 1.5
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Wabbajack.VirtualFileSystem.SevenZipExtractor
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct PropArray
|
||||
{
|
||||
uint length;
|
||||
IntPtr pointerValues;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct PropVariant
|
||||
{
|
||||
[DllImport("ole32.dll")]
|
||||
private static extern int PropVariantClear(ref PropVariant pvar);
|
||||
|
||||
[FieldOffset(0)] public ushort vt;
|
||||
[FieldOffset(8)] public IntPtr pointerValue;
|
||||
[FieldOffset(8)] public byte byteValue;
|
||||
[FieldOffset(8)] public long longValue;
|
||||
[FieldOffset(8)] public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
|
||||
[FieldOffset(8)] public PropArray propArray;
|
||||
|
||||
public VarEnum VarType
|
||||
{
|
||||
get
|
||||
{
|
||||
return (VarEnum) this.vt;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
switch (this.VarType)
|
||||
{
|
||||
case VarEnum.VT_EMPTY:
|
||||
break;
|
||||
|
||||
case VarEnum.VT_NULL:
|
||||
case VarEnum.VT_I2:
|
||||
case VarEnum.VT_I4:
|
||||
case VarEnum.VT_R4:
|
||||
case VarEnum.VT_R8:
|
||||
case VarEnum.VT_CY:
|
||||
case VarEnum.VT_DATE:
|
||||
case VarEnum.VT_ERROR:
|
||||
case VarEnum.VT_BOOL:
|
||||
//case VarEnum.VT_DECIMAL:
|
||||
case VarEnum.VT_I1:
|
||||
case VarEnum.VT_UI1:
|
||||
case VarEnum.VT_UI2:
|
||||
case VarEnum.VT_UI4:
|
||||
case VarEnum.VT_I8:
|
||||
case VarEnum.VT_UI8:
|
||||
case VarEnum.VT_INT:
|
||||
case VarEnum.VT_UINT:
|
||||
case VarEnum.VT_HRESULT:
|
||||
case VarEnum.VT_FILETIME:
|
||||
this.vt = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
PropVariantClear(ref this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
switch (this.VarType)
|
||||
{
|
||||
case VarEnum.VT_EMPTY:
|
||||
return null;
|
||||
|
||||
case VarEnum.VT_FILETIME:
|
||||
return DateTime.FromFileTime(this.longValue);
|
||||
|
||||
default:
|
||||
GCHandle PropHandle = GCHandle.Alloc(this, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
return Marshal.GetObjectForNativeVariant(PropHandle.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
PropHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000000050000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IProgress
|
||||
{
|
||||
void SetTotal(ulong total);
|
||||
void SetCompleted([In] ref ulong completeValue);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000600100000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IArchiveOpenCallback
|
||||
{
|
||||
// ref ulong replaced with IntPtr because handlers ofter pass null value
|
||||
// read actual value with Marshal.ReadInt64
|
||||
void SetTotal(
|
||||
IntPtr files, // [In] ref ulong files, can use 'ulong* files' but it is unsafe
|
||||
IntPtr bytes); // [In] ref ulong bytes
|
||||
|
||||
void SetCompleted(
|
||||
IntPtr files, // [In] ref ulong files
|
||||
IntPtr bytes); // [In] ref ulong bytes
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000500100000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface ICryptoGetTextPassword
|
||||
{
|
||||
[PreserveSig]
|
||||
int CryptoGetTextPassword(
|
||||
[MarshalAs(UnmanagedType.BStr)] out string password);
|
||||
|
||||
//[return : MarshalAs(UnmanagedType.BStr)]
|
||||
//string CryptoGetTextPassword();
|
||||
}
|
||||
|
||||
internal enum AskMode : int
|
||||
{
|
||||
kExtract = 0,
|
||||
kTest,
|
||||
kSkip
|
||||
}
|
||||
|
||||
internal enum OperationResult : int
|
||||
{
|
||||
kOK = 0,
|
||||
kUnSupportedMethod,
|
||||
kDataError,
|
||||
kCRCError
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000600300000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IArchiveOpenVolumeCallback
|
||||
{
|
||||
void GetProperty(
|
||||
ItemPropId propID, // PROPID
|
||||
IntPtr value); // PROPVARIANT
|
||||
|
||||
[PreserveSig]
|
||||
int GetStream(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string name,
|
||||
[MarshalAs(UnmanagedType.Interface)] out IInStream inStream);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000600400000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IInArchiveGetStream
|
||||
{
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
ISequentialInStream GetStream(uint index);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000300010000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface ISequentialInStream
|
||||
{
|
||||
//[PreserveSig]
|
||||
//int Read(
|
||||
// [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
// uint size,
|
||||
// IntPtr processedSize); // ref uint processedSize
|
||||
|
||||
uint Read(
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
uint size);
|
||||
|
||||
/*
|
||||
Out: if size != 0, return_value = S_OK and (*processedSize == 0),
|
||||
then there are no more bytes in stream.
|
||||
if (size > 0) && there are bytes in stream,
|
||||
this function must read at least 1 byte.
|
||||
This function is allowed to read less than number of remaining bytes in stream.
|
||||
You must call Read function in loop, if you need exact amount of data
|
||||
*/
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000300020000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface ISequentialOutStream
|
||||
{
|
||||
[PreserveSig]
|
||||
int Write(
|
||||
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
uint size,
|
||||
IntPtr processedSize); // ref uint processedSize
|
||||
/*
|
||||
if (size > 0) this function must write at least 1 byte.
|
||||
This function is allowed to write less than "size".
|
||||
You must call Write function in loop, if you need to write exact amount of data
|
||||
*/
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000300030000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IInStream //: ISequentialInStream
|
||||
{
|
||||
//[PreserveSig]
|
||||
//int Read(
|
||||
// [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
// uint size,
|
||||
// IntPtr processedSize); // ref uint processedSize
|
||||
|
||||
uint Read(
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
uint size);
|
||||
|
||||
//[PreserveSig]
|
||||
void Seek(
|
||||
long offset,
|
||||
uint seekOrigin,
|
||||
IntPtr newPosition); // ref long newPosition
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000300040000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IOutStream //: ISequentialOutStream
|
||||
{
|
||||
[PreserveSig]
|
||||
int Write(
|
||||
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data,
|
||||
uint size,
|
||||
IntPtr processedSize); // ref uint processedSize
|
||||
|
||||
//[PreserveSig]
|
||||
void Seek(
|
||||
long offset,
|
||||
uint seekOrigin,
|
||||
IntPtr newPosition); // ref long newPosition
|
||||
|
||||
[PreserveSig]
|
||||
int SetSize(long newSize);
|
||||
}
|
||||
|
||||
internal enum ItemPropId : uint
|
||||
{
|
||||
kpidNoProperty = 0,
|
||||
|
||||
kpidHandlerItemIndex = 2,
|
||||
kpidPath,
|
||||
kpidName,
|
||||
kpidExtension,
|
||||
kpidIsFolder,
|
||||
kpidSize,
|
||||
kpidPackedSize,
|
||||
kpidAttributes,
|
||||
kpidCreationTime,
|
||||
kpidLastAccessTime,
|
||||
kpidLastWriteTime,
|
||||
kpidSolid,
|
||||
kpidCommented,
|
||||
kpidEncrypted,
|
||||
kpidSplitBefore,
|
||||
kpidSplitAfter,
|
||||
kpidDictionarySize,
|
||||
kpidCRC,
|
||||
kpidType,
|
||||
kpidIsAnti,
|
||||
kpidMethod,
|
||||
kpidHostOS,
|
||||
kpidFileSystem,
|
||||
kpidUser,
|
||||
kpidGroup,
|
||||
kpidBlock,
|
||||
kpidComment,
|
||||
kpidPosition,
|
||||
kpidPrefix,
|
||||
|
||||
kpidTotalSize = 0x1100,
|
||||
kpidFreeSpace,
|
||||
kpidClusterSize,
|
||||
kpidVolumeName,
|
||||
|
||||
kpidLocalName = 0x1200,
|
||||
kpidProvider,
|
||||
|
||||
kpidUserDefined = 0x10000
|
||||
}
|
||||
|
||||
|
||||
[ComImport]
|
||||
[Guid("23170F69-40C1-278A-0000-000600600000")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
//[AutomationProxy(true)]
|
||||
internal interface IInArchive
|
||||
{
|
||||
[PreserveSig]
|
||||
int Open(
|
||||
IInStream stream,
|
||||
/*[MarshalAs(UnmanagedType.U8)]*/ [In] ref ulong maxCheckStartPosition,
|
||||
[MarshalAs(UnmanagedType.Interface)] IArchiveOpenCallback openArchiveCallback);
|
||||
|
||||
void Close();
|
||||
//void GetNumberOfItems([In] ref uint numItem);
|
||||
uint GetNumberOfItems();
|
||||
|
||||
void GetProperty(
|
||||
uint index,
|
||||
ItemPropId propID, // PROPID
|
||||
ref PropVariant value); // PROPVARIANT
|
||||
|
||||
[PreserveSig]
|
||||
int Extract(
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] indices, //[In] ref uint indices,
|
||||
uint numItems,
|
||||
int testMode,
|
||||
[MarshalAs(UnmanagedType.Interface)] IArchiveExtractCallback extractCallback);
|
||||
|
||||
// indices must be sorted
|
||||
// numItems = 0xFFFFFFFF means all files
|
||||
// testMode != 0 means "test files operation"
|
||||
|
||||
void GetArchiveProperty(
|
||||
uint propID, // PROPID
|
||||
ref PropVariant value); // PROPVARIANT
|
||||
|
||||
//void GetNumberOfProperties([In] ref uint numProperties);
|
||||
uint GetNumberOfProperties();
|
||||
|
||||
void GetPropertyInfo(
|
||||
uint index,
|
||||
[MarshalAs(UnmanagedType.BStr)] out string name,
|
||||
out ItemPropId propID, // PROPID
|
||||
out ushort varType); //VARTYPE
|
||||
|
||||
//void GetNumberOfArchiveProperties([In] ref uint numProperties);
|
||||
uint GetNumberOfArchiveProperties();
|
||||
|
||||
void GetArchivePropertyInfo(
|
||||
uint index,
|
||||
[MarshalAs(UnmanagedType.BStr)] string name,
|
||||
ref uint propID, // PROPID
|
||||
ref ushort varType); //VARTYPE
|
||||
}
|
||||
|
||||
internal enum ArchivePropId : uint
|
||||
{
|
||||
kName = 0,
|
||||
kClassID,
|
||||
kExtension,
|
||||
kAddExtension,
|
||||
kUpdate,
|
||||
kKeepName,
|
||||
kStartSignature,
|
||||
kFinishSignature,
|
||||
kAssociate
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
internal delegate int CreateObjectDelegate(
|
||||
[In] ref Guid classID,
|
||||
[In] ref Guid interfaceID,
|
||||
//out IntPtr outObject);
|
||||
[MarshalAs(UnmanagedType.Interface)] out object outObject);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
internal delegate int GetHandlerPropertyDelegate(
|
||||
ArchivePropId propID,
|
||||
ref PropVariant value); // PROPVARIANT
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
internal delegate int GetNumberOfFormatsDelegate(out uint numFormats);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
internal delegate int GetHandlerProperty2Delegate(
|
||||
uint formatIndex,
|
||||
ArchivePropId propID,
|
||||
ref PropVariant value); // PROPVARIANT
|
||||
|
||||
internal class StreamWrapper : IDisposable
|
||||
{
|
||||
protected Stream BaseStream;
|
||||
|
||||
protected StreamWrapper(Stream baseStream)
|
||||
{
|
||||
this.BaseStream = baseStream;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.BaseStream.Close();
|
||||
}
|
||||
|
||||
public virtual void Seek(long offset, uint seekOrigin, IntPtr newPosition)
|
||||
{
|
||||
long Position = (uint) this.BaseStream.Seek(offset, (SeekOrigin) seekOrigin);
|
||||
|
||||
if (newPosition != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt64(newPosition, Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class InStreamWrapper : StreamWrapper, ISequentialInStream, IInStream
|
||||
{
|
||||
public InStreamWrapper(Stream baseStream) : base(baseStream)
|
||||
{
|
||||
}
|
||||
|
||||
public uint Read(byte[] data, uint size)
|
||||
{
|
||||
return (uint) this.BaseStream.Read(data, 0, (int) size);
|
||||
}
|
||||
}
|
||||
|
||||
internal class OutStreamWrapper : StreamWrapper, ISequentialOutStream, IOutStream
|
||||
{
|
||||
public OutStreamWrapper(Stream baseStream) : base(baseStream)
|
||||
{
|
||||
}
|
||||
|
||||
public int SetSize(long newSize)
|
||||
{
|
||||
this.BaseStream.SetLength(newSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int Write(byte[] data, uint size, IntPtr processedSize)
|
||||
{
|
||||
this.BaseStream.Write(data, 0, (int) size);
|
||||
|
||||
if (processedSize != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt32(processedSize, (int) size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user