etc
This commit is contained in:
parent
1a2b2c3dc5
commit
6616a75cfb
BizHawk.Client.Common
7z
ArchiveEmulationStreamProxy.csArchiveExtractCallback.csArchiveOpenCallback.csArchiveUpdateCallback.csCOM.csCommon.csEventArgs.csExceptions.csFileSignatureChecker.csFormats.csLibraryFeature.csLibraryManager.csLzmaDecodeStream.csLzmaEncodeStream.csLzmaProgressCallback.csNativeMethods.csSevenZipCompressor.csSevenZipCompressorAsynchronous.csSevenZipExtractor.csSevenZipExtractorAsynchronous.csSevenZipSfx.csStreamWrappers.cs
BizHawk.Client.Common.csprojCoreFileProvider.csFirmwareManager.csGlobal.csHawkFile.csKeyTurbo.csarch
Test.bzip2.7zTest.lzma.7zTest.lzma2.7zTest.ppmd.7zTest.rarTest.tarTest.txtTest.txt.bz2Test.txt.gzTest.txt.xzTest.zip
sdk
Properties
RecentFiles.csRomGame.csconfig
helpers
movie
InputAdapters.csMovie.csMovieHeader.csMovieLog.csMovieMnemonics.csMovieSession.csMultitrackRecording.csSubtitle.csSubtitleList.cs
tools
|
@ -0,0 +1,101 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The Stream extension class to emulate the archive part of a stream.
|
||||
/// </summary>
|
||||
internal class ArchiveEmulationStreamProxy : Stream, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the file offset.
|
||||
/// </summary>
|
||||
public int Offset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source wrapped stream.
|
||||
/// </summary>
|
||||
public Stream Source { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveEmulationStream class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to wrap.</param>
|
||||
/// <param name="offset">The stream offset.</param>
|
||||
public ArchiveEmulationStreamProxy(Stream stream, int offset)
|
||||
{
|
||||
Source = stream;
|
||||
Offset = offset;
|
||||
Source.Position = offset;
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return Source.CanRead; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return Source.CanSeek; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return Source.CanWrite; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
Source.Flush();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return Source.Length - Offset; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return Source.Position - Offset;
|
||||
}
|
||||
set
|
||||
{
|
||||
Source.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return Source.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return Source.Seek(origin == SeekOrigin.Begin ? offset + Offset : offset,
|
||||
origin) - Offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
Source.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Source.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
Source.Dispose();
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Source.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// Archive extraction callback to handle the process of unpacking files
|
||||
/// </summary>
|
||||
internal sealed class ArchiveExtractCallback : CallbackBase, IArchiveExtractCallback, ICryptoGetTextPassword,
|
||||
IDisposable
|
||||
{
|
||||
private List<uint> _actualIndexes;
|
||||
private IInArchive _archive;
|
||||
|
||||
/// <summary>
|
||||
/// For Compressing event.
|
||||
/// </summary>
|
||||
private long _bytesCount;
|
||||
|
||||
private long _bytesWritten;
|
||||
private long _bytesWrittenOld;
|
||||
private string _directory;
|
||||
|
||||
/// <summary>
|
||||
/// Rate of the done work from [0, 1].
|
||||
/// </summary>
|
||||
private float _doneRate;
|
||||
|
||||
private SevenZipExtractor _extractor;
|
||||
private FakeOutStreamWrapper _fakeStream;
|
||||
private uint? _fileIndex;
|
||||
private int _filesCount;
|
||||
private OutStreamWrapper _fileStream;
|
||||
private bool _directoryStructure;
|
||||
private int _currentIndex;
|
||||
#if !WINCE
|
||||
const int MEMORY_PRESSURE = 64 * 1024 * 1024; //64mb seems to be the maximum value
|
||||
#endif
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveExtractCallback class
|
||||
/// </summary>
|
||||
/// <param name="archive">IInArchive interface for the archive</param>
|
||||
/// <param name="directory">Directory where files are to be unpacked to</param>
|
||||
/// <param name="filesCount">The archive files count</param>'
|
||||
/// <param name="extractor">The owner of the callback</param>
|
||||
/// <param name="actualIndexes">The list of actual indexes (solid archives support)</param>
|
||||
/// <param name="directoryStructure">The value indicating whether to preserve directory structure of extracted files.</param>
|
||||
public ArchiveExtractCallback(IInArchive archive, string directory, int filesCount, bool directoryStructure,
|
||||
List<uint> actualIndexes, SevenZipExtractor extractor)
|
||||
{
|
||||
Init(archive, directory, filesCount, directoryStructure, actualIndexes, extractor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveExtractCallback class
|
||||
/// </summary>
|
||||
/// <param name="archive">IInArchive interface for the archive</param>
|
||||
/// <param name="directory">Directory where files are to be unpacked to</param>
|
||||
/// <param name="filesCount">The archive files count</param>
|
||||
/// <param name="password">Password for the archive</param>
|
||||
/// <param name="extractor">The owner of the callback</param>
|
||||
/// <param name="actualIndexes">The list of actual indexes (solid archives support)</param>
|
||||
/// <param name="directoryStructure">The value indicating whether to preserve directory structure of extracted files.</param>
|
||||
public ArchiveExtractCallback(IInArchive archive, string directory, int filesCount, bool directoryStructure,
|
||||
List<uint> actualIndexes, string password, SevenZipExtractor extractor)
|
||||
: base(password)
|
||||
{
|
||||
Init(archive, directory, filesCount, directoryStructure, actualIndexes, extractor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveExtractCallback class
|
||||
/// </summary>
|
||||
/// <param name="archive">IInArchive interface for the archive</param>
|
||||
/// <param name="stream">The stream where files are to be unpacked to</param>
|
||||
/// <param name="filesCount">The archive files count</param>
|
||||
/// <param name="fileIndex">The file index for the stream</param>
|
||||
/// <param name="extractor">The owner of the callback</param>
|
||||
public ArchiveExtractCallback(IInArchive archive, Stream stream, int filesCount, uint fileIndex,
|
||||
SevenZipExtractor extractor)
|
||||
{
|
||||
Init(archive, stream, filesCount, fileIndex, extractor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveExtractCallback class
|
||||
/// </summary>
|
||||
/// <param name="archive">IInArchive interface for the archive</param>
|
||||
/// <param name="stream">The stream where files are to be unpacked to</param>
|
||||
/// <param name="filesCount">The archive files count</param>
|
||||
/// <param name="fileIndex">The file index for the stream</param>
|
||||
/// <param name="password">Password for the archive</param>
|
||||
/// <param name="extractor">The owner of the callback</param>
|
||||
public ArchiveExtractCallback(IInArchive archive, Stream stream, int filesCount, uint fileIndex, string password,
|
||||
SevenZipExtractor extractor)
|
||||
: base(password)
|
||||
{
|
||||
Init(archive, stream, filesCount, fileIndex, extractor);
|
||||
}
|
||||
|
||||
private void Init(IInArchive archive, string directory, int filesCount, bool directoryStructure,
|
||||
List<uint> actualIndexes, SevenZipExtractor extractor)
|
||||
{
|
||||
CommonInit(archive, filesCount, extractor);
|
||||
_directory = directory;
|
||||
_actualIndexes = actualIndexes;
|
||||
_directoryStructure = directoryStructure;
|
||||
if (!directory.EndsWith("" + Path.DirectorySeparatorChar, StringComparison.CurrentCulture))
|
||||
{
|
||||
_directory += Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
private void Init(IInArchive archive, Stream stream, int filesCount, uint fileIndex, SevenZipExtractor extractor)
|
||||
{
|
||||
CommonInit(archive, filesCount, extractor);
|
||||
_fileStream = new OutStreamWrapper(stream, false);
|
||||
_fileStream.BytesWritten += IntEventArgsHandler;
|
||||
_fileIndex = fileIndex;
|
||||
}
|
||||
|
||||
private void CommonInit(IInArchive archive, int filesCount, SevenZipExtractor extractor)
|
||||
{
|
||||
_archive = archive;
|
||||
_filesCount = filesCount;
|
||||
_fakeStream = new FakeOutStreamWrapper();
|
||||
_fakeStream.BytesWritten += IntEventArgsHandler;
|
||||
_extractor = extractor;
|
||||
#if !WINCE
|
||||
GC.AddMemoryPressure(MEMORY_PRESSURE);
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a new file is going to be unpacked
|
||||
/// </summary>
|
||||
/// <remarks>Occurs when 7-zip engine requests for an output stream for a new file to unpack in</remarks>
|
||||
public event EventHandler<FileInfoEventArgs> FileExtractionStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a file has been successfully unpacked
|
||||
/// </summary>
|
||||
public event EventHandler<FileInfoEventArgs> FileExtractionFinished;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the archive is opened and 7-zip sends the size of unpacked data
|
||||
/// </summary>
|
||||
public event EventHandler<OpenEventArgs> Open;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the extraction is performed
|
||||
/// </summary>
|
||||
public event EventHandler<ProgressEventArgs> Extracting;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs during the extraction when a file already exists
|
||||
/// </summary>
|
||||
public event EventHandler<FileOverwriteEventArgs> FileExists;
|
||||
|
||||
private void OnFileExists(FileOverwriteEventArgs e)
|
||||
{
|
||||
if (FileExists != null)
|
||||
{
|
||||
FileExists(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOpen(OpenEventArgs e)
|
||||
{
|
||||
if (Open != null)
|
||||
{
|
||||
Open(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFileExtractionStarted(FileInfoEventArgs e)
|
||||
{
|
||||
if (FileExtractionStarted != null)
|
||||
{
|
||||
FileExtractionStarted(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFileExtractionFinished(FileInfoEventArgs e)
|
||||
{
|
||||
if (FileExtractionFinished != null)
|
||||
{
|
||||
FileExtractionFinished(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExtracting(ProgressEventArgs e)
|
||||
{
|
||||
if (Extracting != null)
|
||||
{
|
||||
Extracting(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void IntEventArgsHandler(object sender, IntEventArgs e)
|
||||
{
|
||||
var pold = (int)((_bytesWrittenOld * 100) / _bytesCount);
|
||||
_bytesWritten += e.Value;
|
||||
var pnow = (int)((_bytesWritten * 100) / _bytesCount);
|
||||
if (pnow > pold)
|
||||
{
|
||||
if (pnow > 100)
|
||||
{
|
||||
pold = pnow = 0;
|
||||
}
|
||||
_bytesWrittenOld = _bytesWritten;
|
||||
OnExtracting(new ProgressEventArgs((byte)pnow, (byte)(pnow - pold)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IArchiveExtractCallback Members
|
||||
|
||||
/// <summary>
|
||||
/// Gives the size of the unpacked archive files
|
||||
/// </summary>
|
||||
/// <param name="total">Size of the unpacked archive files (in bytes)</param>
|
||||
public void SetTotal(ulong total)
|
||||
{
|
||||
_bytesCount = (long)total;
|
||||
OnOpen(new OpenEventArgs(total));
|
||||
}
|
||||
|
||||
public void SetCompleted(ref ulong completeValue) { }
|
||||
|
||||
/// <summary>
|
||||
/// Sets output stream for writing unpacked data
|
||||
/// </summary>
|
||||
/// <param name="index">Current file index</param>
|
||||
/// <param name="outStream">Output stream pointer</param>
|
||||
/// <param name="askExtractMode">Extraction mode</param>
|
||||
/// <returns>0 if OK</returns>
|
||||
public int GetStream(uint index, out
|
||||
#if !MONO
|
||||
ISequentialOutStream
|
||||
#else
|
||||
HandleRef
|
||||
#endif
|
||||
outStream, AskMode askExtractMode)
|
||||
{
|
||||
#if !MONO
|
||||
outStream = null;
|
||||
#else
|
||||
outStream = new System.Runtime.InteropServices.HandleRef(null, IntPtr.Zero);
|
||||
#endif
|
||||
if (Canceled)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
_currentIndex = (int)index;
|
||||
if (askExtractMode == AskMode.Extract)
|
||||
{
|
||||
var fileName = _directory;
|
||||
if (!_fileIndex.HasValue)
|
||||
{
|
||||
#region Extraction to a file
|
||||
|
||||
if (_actualIndexes == null || _actualIndexes.Contains(index))
|
||||
{
|
||||
var data = new PropVariant();
|
||||
_archive.GetProperty(index, ItemPropId.Path, ref data);
|
||||
string entryName = NativeMethods.SafeCast(data, "");
|
||||
|
||||
#region Get entryName
|
||||
|
||||
if (String.IsNullOrEmpty(entryName))
|
||||
{
|
||||
if (_filesCount == 1)
|
||||
{
|
||||
var archName = Path.GetFileName(_extractor.FileName);
|
||||
archName = archName.Substring(0, archName.LastIndexOf('.'));
|
||||
if (!archName.EndsWith(".tar", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
archName += ".tar";
|
||||
}
|
||||
entryName = archName;
|
||||
}
|
||||
else
|
||||
{
|
||||
entryName = "[no name] " + index.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
fileName = Path.Combine(_directory, _directoryStructure? entryName : Path.GetFileName(entryName));
|
||||
_archive.GetProperty(index, ItemPropId.IsDirectory, ref data);
|
||||
try
|
||||
{
|
||||
fileName = ValidateFileName(fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AddException(e);
|
||||
goto FileExtractionStartedLabel;
|
||||
}
|
||||
if (!NativeMethods.SafeCast(data, false))
|
||||
{
|
||||
#region Branch
|
||||
|
||||
_archive.GetProperty(index, ItemPropId.LastWriteTime, ref data);
|
||||
var time = NativeMethods.SafeCast(data, DateTime.MinValue);
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
var fnea = new FileOverwriteEventArgs(fileName);
|
||||
OnFileExists(fnea);
|
||||
if (fnea.Cancel)
|
||||
{
|
||||
Canceled = true;
|
||||
return -1;
|
||||
}
|
||||
if (String.IsNullOrEmpty(fnea.FileName))
|
||||
{
|
||||
#if !MONO
|
||||
outStream = _fakeStream;
|
||||
#else
|
||||
outStream = _fakeStream.Handle;
|
||||
#endif
|
||||
goto FileExtractionStartedLabel;
|
||||
}
|
||||
fileName = fnea.FileName;
|
||||
}
|
||||
try
|
||||
{
|
||||
_fileStream = new OutStreamWrapper(File.Create(fileName), fileName, time, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is FileNotFoundException)
|
||||
{
|
||||
AddException(
|
||||
new IOException("The file \"" + fileName +
|
||||
"\" was not extracted due to the File.Create fail."));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddException(e);
|
||||
}
|
||||
outStream = _fakeStream;
|
||||
goto FileExtractionStartedLabel;
|
||||
}
|
||||
_fileStream.BytesWritten += IntEventArgsHandler;
|
||||
outStream = _fileStream;
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Branch
|
||||
|
||||
if (!Directory.Exists(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AddException(e);
|
||||
}
|
||||
outStream = _fakeStream;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outStream = _fakeStream;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Extraction to a stream
|
||||
|
||||
if (index == _fileIndex)
|
||||
{
|
||||
outStream = _fileStream;
|
||||
_fileIndex = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
outStream = _fakeStream;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
FileExtractionStartedLabel:
|
||||
_doneRate += 1.0f / _filesCount;
|
||||
var iea = new FileInfoEventArgs(
|
||||
_extractor.ArchiveFileData[(int)index], PercentDoneEventArgs.ProducePercentDone(_doneRate));
|
||||
OnFileExtractionStarted(iea);
|
||||
if (iea.Cancel)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AddException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Canceled = true;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrepareOperation(AskMode askExtractMode) { }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the archive was extracted
|
||||
/// </summary>
|
||||
/// <param name="operationResult"></param>
|
||||
public void SetOperationResult(OperationResult operationResult)
|
||||
{
|
||||
if (operationResult != OperationResult.Ok && ReportErrors)
|
||||
{
|
||||
switch (operationResult)
|
||||
{
|
||||
case OperationResult.CrcError:
|
||||
AddException(new ExtractionFailedException("File is corrupted. Crc check has failed."));
|
||||
break;
|
||||
case OperationResult.DataError:
|
||||
AddException(new ExtractionFailedException("File is corrupted. Data error has occured."));
|
||||
break;
|
||||
case OperationResult.UnsupportedMethod:
|
||||
AddException(new ExtractionFailedException("Unsupported method error has occured."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_fileStream != null && !_fileIndex.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileStream.BytesWritten -= IntEventArgsHandler;
|
||||
_fileStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
_fileStream = null;
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
}
|
||||
var iea = new FileInfoEventArgs(
|
||||
_extractor.ArchiveFileData[_currentIndex], PercentDoneEventArgs.ProducePercentDone(_doneRate));
|
||||
OnFileExtractionFinished(iea);
|
||||
if (iea.Cancel)
|
||||
{
|
||||
Canceled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICryptoGetTextPassword Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets password for the archive
|
||||
/// </summary>
|
||||
/// <param name="password">Password for the archive</param>
|
||||
/// <returns>Zero if everything is OK</returns>
|
||||
public int CryptoGetTextPassword(out string password)
|
||||
{
|
||||
password = Password;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
#if !WINCE
|
||||
GC.RemoveMemoryPressure(MEMORY_PRESSURE);
|
||||
#endif
|
||||
if (_fileStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
_fileStream = null;
|
||||
}
|
||||
if (_fakeStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fakeStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
_fakeStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Validates the file name and ensures that the directory to the file name is valid and creates intermediate directories if necessary
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name</param>
|
||||
/// <returns>The valid file name</returns>
|
||||
private static string ValidateFileName(string fileName)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new SevenZipArchiveException("some archive name is null or empty.");
|
||||
}
|
||||
var splittedFileName = new List<string>(fileName.Split(Path.DirectorySeparatorChar));
|
||||
#if !WINCE
|
||||
foreach (char chr in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
for (int i = 0; i < splittedFileName.Count; i++)
|
||||
{
|
||||
if (chr == ':' && i == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (String.IsNullOrEmpty(splittedFileName[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
while (splittedFileName[i].IndexOf(chr) > -1)
|
||||
{
|
||||
splittedFileName[i] = splittedFileName[i].Replace(chr, '_');
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (fileName.StartsWith(new string(Path.DirectorySeparatorChar, 2),
|
||||
StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
splittedFileName.RemoveAt(0);
|
||||
splittedFileName.RemoveAt(0);
|
||||
splittedFileName[0] = new string(Path.DirectorySeparatorChar, 2) + splittedFileName[0];
|
||||
}
|
||||
if (splittedFileName.Count > 2)
|
||||
{
|
||||
string tfn = splittedFileName[0];
|
||||
for (int i = 1; i < splittedFileName.Count - 1; i++)
|
||||
{
|
||||
tfn += Path.DirectorySeparatorChar + splittedFileName[i];
|
||||
if (!Directory.Exists(tfn))
|
||||
{
|
||||
Directory.CreateDirectory(tfn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return String.Join(new string(Path.DirectorySeparatorChar, 1), splittedFileName.ToArray());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if MONO
|
||||
using SevenZip.Mono;
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// Callback to handle the archive opening
|
||||
/// </summary>
|
||||
internal sealed class ArchiveOpenCallback : CallbackBase, IArchiveOpenCallback, IArchiveOpenVolumeCallback,
|
||||
ICryptoGetTextPassword, IDisposable
|
||||
{
|
||||
private FileInfo _fileInfo;
|
||||
private Dictionary<string, InStreamWrapper> _wrappers =
|
||||
new Dictionary<string, InStreamWrapper>();
|
||||
public readonly List<string> VolumeFileNames = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Performs the common initialization.
|
||||
/// </summary>
|
||||
/// <param name="fileName">Volume file name.</param>
|
||||
private void Init(string fileName)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
_fileInfo = new FileInfo(fileName);
|
||||
VolumeFileNames.Add(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveOpenCallback class.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The archive file name.</param>
|
||||
public ArchiveOpenCallback(string fileName)
|
||||
{
|
||||
Init(fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveOpenCallback class.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The archive file name.</param>
|
||||
/// <param name="password">Password for the archive.</param>
|
||||
public ArchiveOpenCallback(string fileName, string password) : base(password)
|
||||
{
|
||||
Init(fileName);
|
||||
}
|
||||
|
||||
#region IArchiveOpenCallback Members
|
||||
|
||||
public void SetTotal(IntPtr files, IntPtr bytes) {}
|
||||
|
||||
public void SetCompleted(IntPtr files, IntPtr bytes) {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IArchiveOpenVolumeCallback Members
|
||||
|
||||
public int GetProperty(ItemPropId propId, ref PropVariant value)
|
||||
{
|
||||
switch (propId)
|
||||
{
|
||||
case ItemPropId.Name:
|
||||
value.VarType = VarEnum.VT_BSTR;
|
||||
value.Value = Marshal.StringToBSTR(_fileInfo.FullName);
|
||||
break;
|
||||
case ItemPropId.IsDirectory:
|
||||
value.VarType = VarEnum.VT_BOOL;
|
||||
value.UInt64Value = (byte) (_fileInfo.Attributes & FileAttributes.Directory);
|
||||
break;
|
||||
case ItemPropId.Size:
|
||||
value.VarType = VarEnum.VT_UI8;
|
||||
value.UInt64Value = (UInt64) _fileInfo.Length;
|
||||
break;
|
||||
case ItemPropId.Attributes:
|
||||
value.VarType = VarEnum.VT_UI4;
|
||||
value.UInt32Value = (uint) _fileInfo.Attributes;
|
||||
break;
|
||||
case ItemPropId.CreationTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
value.Int64Value = _fileInfo.CreationTime.ToFileTime();
|
||||
break;
|
||||
case ItemPropId.LastAccessTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
value.Int64Value = _fileInfo.LastAccessTime.ToFileTime();
|
||||
break;
|
||||
case ItemPropId.LastWriteTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
value.Int64Value = _fileInfo.LastWriteTime.ToFileTime();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetStream(string name, out IInStream inStream)
|
||||
{
|
||||
if (!File.Exists(name))
|
||||
{
|
||||
name = Path.Combine(Path.GetDirectoryName(_fileInfo.FullName), name);
|
||||
if (!File.Exists(name))
|
||||
{
|
||||
inStream = null;
|
||||
AddException(new FileNotFoundException("The volume \"" + name + "\" was not found. Extraction can be impossible."));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
VolumeFileNames.Add(name);
|
||||
if (_wrappers.ContainsKey(name))
|
||||
{
|
||||
inStream = _wrappers[name];
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var wrapper = new InStreamWrapper(
|
||||
new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), true);
|
||||
_wrappers.Add(name, wrapper);
|
||||
inStream = wrapper;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
AddException(new FileNotFoundException("Failed to open the volume \"" + name + "\". Extraction is impossible."));
|
||||
inStream = null;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICryptoGetTextPassword Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets password for the archive
|
||||
/// </summary>
|
||||
/// <param name="password">Password for the archive</param>
|
||||
/// <returns>Zero if everything is OK</returns>
|
||||
public int CryptoGetTextPassword(out string password)
|
||||
{
|
||||
password = Password;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_wrappers != null)
|
||||
{
|
||||
foreach (InStreamWrapper wrap in _wrappers.Values)
|
||||
{
|
||||
wrap.Dispose();
|
||||
}
|
||||
_wrappers = null;
|
||||
}
|
||||
#if MONO
|
||||
libp7zInvokerRaw.FreeObject(Handle);
|
||||
#endif
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,806 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// Archive update callback to handle the process of packing files
|
||||
/// </summary>
|
||||
internal sealed class ArchiveUpdateCallback : CallbackBase, IArchiveUpdateCallback, ICryptoGetTextPassword2,
|
||||
IDisposable
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// _files.Count if do not count directories
|
||||
/// </summary>
|
||||
private int _actualFilesCount;
|
||||
|
||||
/// <summary>
|
||||
/// For Compressing event.
|
||||
/// </summary>
|
||||
private long _bytesCount;
|
||||
|
||||
private long _bytesWritten;
|
||||
private long _bytesWrittenOld;
|
||||
private SevenZipCompressor _compressor;
|
||||
|
||||
/// <summary>
|
||||
/// No directories.
|
||||
/// </summary>
|
||||
private bool _directoryStructure;
|
||||
|
||||
/// <summary>
|
||||
/// Rate of the done work from [0, 1]
|
||||
/// </summary>
|
||||
private float _doneRate;
|
||||
|
||||
/// <summary>
|
||||
/// The names of the archive entries
|
||||
/// </summary>
|
||||
private string[] _entries;
|
||||
|
||||
/// <summary>
|
||||
/// Array of files to pack
|
||||
/// </summary>
|
||||
private FileInfo[] _files;
|
||||
|
||||
private InStreamWrapper _fileStream;
|
||||
|
||||
private uint _indexInArchive;
|
||||
private uint _indexOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Common root of file names length.
|
||||
/// </summary>
|
||||
private int _rootLength;
|
||||
|
||||
/// <summary>
|
||||
/// Input streams to be compressed.
|
||||
/// </summary>
|
||||
private Stream[] _streams;
|
||||
|
||||
private UpdateData _updateData;
|
||||
private List<InStreamWrapper> _wrappersToDispose;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default item name used in MemoryStream compression.
|
||||
/// </summary>
|
||||
public string DefaultItemName { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value indicating whether to compress as fast as possible, without calling events.
|
||||
/// </summary>
|
||||
public bool FastCompression { private get; set; }
|
||||
#if !WINCE
|
||||
private int _memoryPressure;
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="files">Array of files to pack</param>
|
||||
/// <param name="rootLength">Common file names root length</param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
FileInfo[] files, int rootLength,
|
||||
SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
Init(files, rootLength, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="files">Array of files to pack</param>
|
||||
/// <param name="rootLength">Common file names root length</param>
|
||||
/// <param name="password">The archive password</param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
FileInfo[] files, int rootLength, string password,
|
||||
SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
: base(password)
|
||||
{
|
||||
Init(files, rootLength, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="stream">The input stream</param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
Stream stream, SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
Init(stream, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="stream">The input stream</param>
|
||||
/// <param name="password">The archive password</param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
Stream stream, string password, SevenZipCompressor compressor, UpdateData updateData,
|
||||
bool directoryStructure)
|
||||
: base(password)
|
||||
{
|
||||
Init(stream, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="streamDict">Dictionary<file stream, name of the archive entry></param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
Dictionary<string, Stream> streamDict,
|
||||
SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
Init(streamDict, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ArchiveUpdateCallback class
|
||||
/// </summary>
|
||||
/// <param name="streamDict">Dictionary<file stream, name of the archive entry></param>
|
||||
/// <param name="password">The archive password</param>
|
||||
/// <param name="compressor">The owner of the callback</param>
|
||||
/// <param name="updateData">The compression parameters.</param>
|
||||
/// <param name="directoryStructure">Preserve directory structure.</param>
|
||||
public ArchiveUpdateCallback(
|
||||
Dictionary<string, Stream> streamDict, string password,
|
||||
SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
: base(password)
|
||||
{
|
||||
Init(streamDict, compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
private void CommonInit(SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
_compressor = compressor;
|
||||
_indexInArchive = updateData.FilesCount;
|
||||
_indexOffset = updateData.Mode != InternalCompressionMode.Append ? 0 : _indexInArchive;
|
||||
if (_compressor.ArchiveFormat == OutArchiveFormat.Zip)
|
||||
{
|
||||
_wrappersToDispose = new List<InStreamWrapper>();
|
||||
}
|
||||
_updateData = updateData;
|
||||
_directoryStructure = directoryStructure;
|
||||
DefaultItemName = "default";
|
||||
}
|
||||
|
||||
private void Init(
|
||||
FileInfo[] files, int rootLength, SevenZipCompressor compressor,
|
||||
UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
_files = files;
|
||||
_rootLength = rootLength;
|
||||
if (files != null)
|
||||
{
|
||||
foreach (var fi in files)
|
||||
{
|
||||
if (fi.Exists)
|
||||
{
|
||||
_bytesCount += fi.Length;
|
||||
if ((fi.Attributes & FileAttributes.Directory) == 0)
|
||||
{
|
||||
_actualFilesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CommonInit(compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
private void Init(
|
||||
Stream stream, SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
_fileStream = new InStreamWrapper(stream, false);
|
||||
_fileStream.BytesRead += IntEventArgsHandler;
|
||||
_actualFilesCount = 1;
|
||||
try
|
||||
{
|
||||
_bytesCount = stream.Length;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_bytesCount = -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_bytesCount = -1;
|
||||
}
|
||||
CommonInit(compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
private void Init(
|
||||
Dictionary<string, Stream> streamDict,
|
||||
SevenZipCompressor compressor, UpdateData updateData, bool directoryStructure)
|
||||
{
|
||||
_streams = new Stream[streamDict.Count];
|
||||
streamDict.Values.CopyTo(_streams, 0);
|
||||
_entries = new string[streamDict.Count];
|
||||
streamDict.Keys.CopyTo(_entries, 0);
|
||||
_actualFilesCount = streamDict.Count;
|
||||
foreach (Stream str in _streams)
|
||||
{
|
||||
if (str != null)
|
||||
{
|
||||
_bytesCount += str.Length;
|
||||
}
|
||||
}
|
||||
CommonInit(compressor, updateData, directoryStructure);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the dictionary size.
|
||||
/// </summary>
|
||||
public float DictionarySize
|
||||
{
|
||||
set
|
||||
{
|
||||
#if !WINCE
|
||||
_memoryPressure = (int)(value * 1024 * 1024);
|
||||
GC.AddMemoryPressure(_memoryPressure);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises events for the GetStream method.
|
||||
/// </summary>
|
||||
/// <param name="index">The current item index.</param>
|
||||
/// <returns>True if not cancelled; otherwise, false.</returns>
|
||||
private bool EventsForGetStream(uint index)
|
||||
{
|
||||
if (!FastCompression)
|
||||
{
|
||||
if (_fileStream != null)
|
||||
{
|
||||
_fileStream.BytesRead += IntEventArgsHandler;
|
||||
}
|
||||
_doneRate += 1.0f / _actualFilesCount;
|
||||
var fiea = new FileNameEventArgs(_files != null? _files[index].Name : _entries[index],
|
||||
PercentDoneEventArgs.ProducePercentDone(_doneRate));
|
||||
OnFileCompression(fiea);
|
||||
if (fiea.Cancel)
|
||||
{
|
||||
Canceled = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the next file is going to be packed.
|
||||
/// </summary>
|
||||
/// <remarks>Occurs when 7-zip engine requests for an input stream for the next file to pack it</remarks>
|
||||
public event EventHandler<FileNameEventArgs> FileCompressionStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when data are being compressed.
|
||||
/// </summary>
|
||||
public event EventHandler<ProgressEventArgs> Compressing;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the current file was compressed.
|
||||
/// </summary>
|
||||
public event EventHandler FileCompressionFinished;
|
||||
|
||||
private void OnFileCompression(FileNameEventArgs e)
|
||||
{
|
||||
if (FileCompressionStarted != null)
|
||||
{
|
||||
FileCompressionStarted(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCompressing(ProgressEventArgs e)
|
||||
{
|
||||
if (Compressing != null)
|
||||
{
|
||||
Compressing(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFileCompressionFinished(EventArgs e)
|
||||
{
|
||||
if (FileCompressionFinished != null)
|
||||
{
|
||||
FileCompressionFinished(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IArchiveUpdateCallback Members
|
||||
|
||||
public void SetTotal(ulong total) {}
|
||||
|
||||
public void SetCompleted(ref ulong completeValue) {}
|
||||
|
||||
public int GetUpdateItemInfo(uint index, ref int newData, ref int newProperties, ref uint indexInArchive)
|
||||
{
|
||||
switch (_updateData.Mode)
|
||||
{
|
||||
case InternalCompressionMode.Create:
|
||||
newData = 1;
|
||||
newProperties = 1;
|
||||
indexInArchive = UInt32.MaxValue;
|
||||
break;
|
||||
case InternalCompressionMode.Append:
|
||||
if (index < _indexInArchive)
|
||||
{
|
||||
newData = 0;
|
||||
newProperties = 0;
|
||||
indexInArchive = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
newData = 1;
|
||||
newProperties = 1;
|
||||
indexInArchive = UInt32.MaxValue;
|
||||
}
|
||||
break;
|
||||
case InternalCompressionMode.Modify:
|
||||
newData = 0;
|
||||
newProperties = Convert.ToInt32(_updateData.FileNamesToModify.ContainsKey((int)index)
|
||||
&& _updateData.FileNamesToModify[(int)index] != null);
|
||||
if (_updateData.FileNamesToModify.ContainsKey((int)index)
|
||||
&& _updateData.FileNamesToModify[(int)index] == null)
|
||||
{
|
||||
indexInArchive = (UInt32)_updateData.ArchiveFileData.Count;
|
||||
foreach (KeyValuePair<Int32, string> pairModification in _updateData.FileNamesToModify)
|
||||
if ((pairModification.Key <= index) && (pairModification.Value == null))
|
||||
{
|
||||
do
|
||||
{
|
||||
indexInArchive--;
|
||||
}
|
||||
while ((indexInArchive > 0) && _updateData.FileNamesToModify.ContainsKey((Int32)indexInArchive)
|
||||
&& (_updateData.FileNamesToModify[(Int32)indexInArchive] == null));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indexInArchive = index;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetProperty(uint index, ItemPropId propID, ref PropVariant value)
|
||||
{
|
||||
index -= _indexOffset;
|
||||
try
|
||||
{
|
||||
switch (propID)
|
||||
{
|
||||
case ItemPropId.IsAnti:
|
||||
value.VarType = VarEnum.VT_BOOL;
|
||||
value.UInt64Value = 0;
|
||||
break;
|
||||
case ItemPropId.Path:
|
||||
#region Path
|
||||
|
||||
value.VarType = VarEnum.VT_BSTR;
|
||||
string val = DefaultItemName;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
if (_files == null)
|
||||
{
|
||||
if (_entries != null)
|
||||
{
|
||||
val = _entries[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_directoryStructure)
|
||||
{
|
||||
if (_rootLength > 0)
|
||||
{
|
||||
val = _files[index].FullName.Substring(_rootLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = _files[index].FullName[0] + _files[index].FullName.Substring(2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = _files[index].Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = _updateData.FileNamesToModify[(int) index];
|
||||
}
|
||||
value.Value = Marshal.StringToBSTR(val);
|
||||
#endregion
|
||||
break;
|
||||
case ItemPropId.IsDirectory:
|
||||
value.VarType = VarEnum.VT_BOOL;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
if (_files == null)
|
||||
{
|
||||
if (_streams == null)
|
||||
{
|
||||
value.UInt64Value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt64Value = (ulong)(_streams[index] == null ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt64Value = (byte)(_files[index].Attributes & FileAttributes.Directory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt64Value = Convert.ToUInt64(_updateData.ArchiveFileData[(int) index].IsDirectory);
|
||||
}
|
||||
break;
|
||||
case ItemPropId.Size:
|
||||
#region Size
|
||||
|
||||
value.VarType = VarEnum.VT_UI8;
|
||||
UInt64 size;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
if (_files == null)
|
||||
{
|
||||
if (_streams == null)
|
||||
{
|
||||
size = _bytesCount > 0 ? (ulong) _bytesCount : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (ulong) (_streams[index] == null? 0 : _streams[index].Length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (_files[index].Attributes & FileAttributes.Directory) == 0
|
||||
? (ulong) _files[index].Length
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = _updateData.ArchiveFileData[(int) index].Size;
|
||||
}
|
||||
value.UInt64Value = size;
|
||||
|
||||
#endregion
|
||||
break;
|
||||
case ItemPropId.Attributes:
|
||||
value.VarType = VarEnum.VT_UI4;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
if (_files == null)
|
||||
{
|
||||
if (_streams == null)
|
||||
{
|
||||
value.UInt32Value = (uint)FileAttributes.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt32Value = (uint)(_streams[index] == null ? FileAttributes.Directory : FileAttributes.Normal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt32Value = (uint) _files[index].Attributes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.UInt32Value = _updateData.ArchiveFileData[(int) index].Attributes;
|
||||
}
|
||||
break;
|
||||
#region Times
|
||||
case ItemPropId.CreationTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
value.Int64Value = _files == null
|
||||
? DateTime.Now.ToFileTime()
|
||||
: _files[index].CreationTime.ToFileTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.Int64Value = _updateData.ArchiveFileData[(int) index].CreationTime.ToFileTime();
|
||||
}
|
||||
break;
|
||||
case ItemPropId.LastAccessTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
value.Int64Value = _files == null
|
||||
? DateTime.Now.ToFileTime()
|
||||
: _files[index].LastAccessTime.ToFileTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.Int64Value = _updateData.ArchiveFileData[(int) index].LastAccessTime.ToFileTime();
|
||||
}
|
||||
break;
|
||||
case ItemPropId.LastWriteTime:
|
||||
value.VarType = VarEnum.VT_FILETIME;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
value.Int64Value = _files == null
|
||||
? DateTime.Now.ToFileTime()
|
||||
: _files[index].LastWriteTime.ToFileTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.Int64Value = _updateData.ArchiveFileData[(int) index].LastWriteTime.ToFileTime();
|
||||
}
|
||||
break;
|
||||
#endregion
|
||||
case ItemPropId.Extension:
|
||||
#region Extension
|
||||
|
||||
value.VarType = VarEnum.VT_BSTR;
|
||||
if (_updateData.Mode != InternalCompressionMode.Modify)
|
||||
{
|
||||
try
|
||||
{
|
||||
val = _files != null
|
||||
? _files[index].Extension.Substring(1)
|
||||
: _entries == null
|
||||
? ""
|
||||
: Path.GetExtension(_entries[index]);
|
||||
value.Value = Marshal.StringToBSTR(val);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
value.Value = Marshal.StringToBSTR("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = Path.GetExtension(_updateData.ArchiveFileData[(int) index].FileName);
|
||||
value.Value = Marshal.StringToBSTR(val);
|
||||
}
|
||||
|
||||
#endregion
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AddException(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream for 7-zip library.
|
||||
/// </summary>
|
||||
/// <param name="index">File index</param>
|
||||
/// <param name="inStream">Input file stream</param>
|
||||
/// <returns>Zero if Ok</returns>
|
||||
public int GetStream(uint index, out
|
||||
#if !MONO
|
||||
ISequentialInStream
|
||||
#else
|
||||
HandleRef
|
||||
#endif
|
||||
inStream)
|
||||
{
|
||||
index -= _indexOffset;
|
||||
if (_files != null)
|
||||
{
|
||||
_fileStream = null;
|
||||
try
|
||||
{
|
||||
if (File.Exists(_files[index].FullName))
|
||||
{
|
||||
_fileStream = new InStreamWrapper(
|
||||
new FileStream(_files[index].FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite),
|
||||
true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AddException(e);
|
||||
inStream = null;
|
||||
return -1;
|
||||
}
|
||||
inStream = _fileStream;
|
||||
if (!EventsForGetStream(index))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_streams == null)
|
||||
{
|
||||
inStream = _fileStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileStream = new InStreamWrapper(_streams[index], true);
|
||||
inStream = _fileStream;
|
||||
if (!EventsForGetStream(index))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long EnumProperties(IntPtr enumerator)
|
||||
{
|
||||
//Not implemented HRESULT
|
||||
return 0x80004001L;
|
||||
}
|
||||
|
||||
public void SetOperationResult(OperationResult operationResult)
|
||||
{
|
||||
if (operationResult != OperationResult.Ok && ReportErrors)
|
||||
{
|
||||
switch (operationResult)
|
||||
{
|
||||
case OperationResult.CrcError:
|
||||
AddException(new ExtractionFailedException("File is corrupted. Crc check has failed."));
|
||||
break;
|
||||
case OperationResult.DataError:
|
||||
AddException(new ExtractionFailedException("File is corrupted. Data error has occured."));
|
||||
break;
|
||||
case OperationResult.UnsupportedMethod:
|
||||
AddException(new ExtractionFailedException("Unsupported method error has occured."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_fileStream != null)
|
||||
{
|
||||
|
||||
_fileStream.BytesRead -= IntEventArgsHandler;
|
||||
//Specific Zip implementation - can not Dispose files for Zip.
|
||||
if (_compressor.ArchiveFormat != OutArchiveFormat.Zip)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
_wrappersToDispose.Add(_fileStream);
|
||||
}
|
||||
_fileStream = null;
|
||||
GC.Collect();
|
||||
// Issue #6987
|
||||
//GC.WaitForPendingFinalizers();
|
||||
}
|
||||
OnFileCompressionFinished(EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICryptoGetTextPassword2 Members
|
||||
|
||||
public int CryptoGetTextPassword2(ref int passwordIsDefined, out string password)
|
||||
{
|
||||
passwordIsDefined = String.IsNullOrEmpty(Password) ? 0 : 1;
|
||||
password = Password;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
#if !WINCE
|
||||
GC.RemoveMemoryPressure(_memoryPressure);
|
||||
#endif
|
||||
if (_fileStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) {}
|
||||
}
|
||||
if (_wrappersToDispose != null)
|
||||
{
|
||||
foreach (var wrapper in _wrappersToDispose)
|
||||
{
|
||||
try
|
||||
{
|
||||
wrapper.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) {}
|
||||
}
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void IntEventArgsHandler(object sender, IntEventArgs e)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
var pold = (byte) ((_bytesWrittenOld*100)/_bytesCount);
|
||||
_bytesWritten += e.Value;
|
||||
byte pnow;
|
||||
if (_bytesCount < _bytesWritten) //Holy shit, this check for ZIP is golden
|
||||
{
|
||||
pnow = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
pnow = (byte)((_bytesWritten * 100) / _bytesCount);
|
||||
}
|
||||
if (pnow > pold)
|
||||
{
|
||||
_bytesWrittenOld = _bytesWritten;
|
||||
OnCompressing(new ProgressEventArgs(pnow, (byte) (pnow - pold)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,833 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
#if !WINCE
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
#endif
|
||||
#if DOTNET20
|
||||
using System.Threading;
|
||||
#else
|
||||
using System.Windows.Threading;
|
||||
#endif
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
|
||||
/// <summary>
|
||||
/// The way of the event synchronization.
|
||||
/// </summary>
|
||||
public enum EventSynchronizationStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Events are called synchronously if user can do some action; that is, cancel the execution process for example.
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// Always call events asynchronously.
|
||||
/// </summary>
|
||||
AlwaysAsynchronous,
|
||||
/// <summary>
|
||||
/// Always call events synchronously.
|
||||
/// </summary>
|
||||
AlwaysSynchronous
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SevenZip Extractor/Compressor base class. Implements Password string, ReportErrors flag.
|
||||
/// </summary>
|
||||
public class SevenZipBase : MarshalByRefObject
|
||||
{
|
||||
private readonly string _password;
|
||||
private readonly bool _reportErrors;
|
||||
private readonly int _uniqueID;
|
||||
private static readonly List<int> Identificators = new List<int>();
|
||||
#if !WINCE
|
||||
internal static readonly AsyncCallback AsyncCallbackImplementation = AsyncCallbackMethod;
|
||||
|
||||
/// <summary>
|
||||
/// True if the instance of the class needs to be recreated in new thread context; otherwise, false.
|
||||
/// </summary>
|
||||
protected internal bool NeedsToBeRecreated;
|
||||
|
||||
/// <summary>
|
||||
/// AsyncCallback implementation used in asynchronous invocations.
|
||||
/// </summary>
|
||||
/// <param name="ar">IAsyncResult instance.</param>
|
||||
internal static void AsyncCallbackMethod(IAsyncResult ar)
|
||||
{
|
||||
var result = (AsyncResult) ar;
|
||||
result.AsyncDelegate.GetType().GetMethod("EndInvoke").Invoke(result.AsyncDelegate, new[] { ar });
|
||||
((SevenZipBase)ar.AsyncState).ReleaseContext();
|
||||
}
|
||||
|
||||
virtual internal void SaveContext(
|
||||
#if !DOTNET20
|
||||
DispatcherPriority priority = DispatcherPriority.Normal
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if !DOTNET20
|
||||
Dispatcher = Dispatcher.CurrentDispatcher;
|
||||
Priority = priority;
|
||||
#else
|
||||
Context = SynchronizationContext.Current;
|
||||
#endif
|
||||
NeedsToBeRecreated = true;
|
||||
}
|
||||
|
||||
internal void ReleaseContext()
|
||||
{
|
||||
#if !DOTNET20
|
||||
Dispatcher = null;
|
||||
#else
|
||||
Context = null;
|
||||
#endif
|
||||
NeedsToBeRecreated = true;
|
||||
}
|
||||
|
||||
private delegate void EventHandlerDelegate<T>(EventHandler<T> handler, T e) where T : EventArgs;
|
||||
|
||||
internal void OnEvent<T>(EventHandler<T> handler, T e, bool synchronous) where T: EventArgs
|
||||
{
|
||||
try
|
||||
{
|
||||
if (handler != null)
|
||||
{
|
||||
switch (EventSynchronization)
|
||||
{
|
||||
case EventSynchronizationStrategy.AlwaysAsynchronous:
|
||||
synchronous = false;
|
||||
break;
|
||||
case EventSynchronizationStrategy.AlwaysSynchronous:
|
||||
synchronous = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
#if !DOTNET20
|
||||
Dispatcher == null
|
||||
#else
|
||||
Context == null
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Usual synchronous call
|
||||
handler(this, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !DOTNET20
|
||||
var eventHandlerDelegate = new EventHandlerDelegate<T>((h, ee) => h(this, ee));
|
||||
if (synchronous)
|
||||
{
|
||||
// Could be just handler(this, e);
|
||||
Dispatcher.Invoke(eventHandlerDelegate, Priority, handler, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.BeginInvoke(eventHandlerDelegate, Priority, handler, e);
|
||||
}
|
||||
#else
|
||||
var callback = new SendOrPostCallback((obj) =>
|
||||
{
|
||||
var array = (object[])obj;
|
||||
((EventHandler<T>)array[0])(array[1], (T)array[2]);
|
||||
});
|
||||
if (synchronous)
|
||||
{
|
||||
// Could be just handler(this, e);
|
||||
this.Context.Send(callback, new object[] { handler, this, e });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Context.Post(callback, new object[] { handler, this, e });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Gets or sets the Dispatcher object for this instance.
|
||||
/// It will be used to fire events in the user context.
|
||||
/// </summary>
|
||||
internal Dispatcher Dispatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Dispatcher priority of calling user events.
|
||||
/// </summary>
|
||||
internal DispatcherPriority Priority { get; set; }
|
||||
#else
|
||||
internal SynchronizationContext Context { get; set; }
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Gets or sets the event synchronization strategy.
|
||||
/// </summary>
|
||||
public EventSynchronizationStrategy EventSynchronization { get; set; }
|
||||
#else // WINCE
|
||||
internal void OnEvent<T>(EventHandler<T> handler, T e, bool synchronous) where T : System.EventArgs
|
||||
{
|
||||
try
|
||||
{
|
||||
handler(this, e);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddException(ex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Gets the unique identificator of this SevenZipBase instance.
|
||||
/// </summary>
|
||||
public int UniqueID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _uniqueID;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User exceptions thrown during the requested operations, for example, in events.
|
||||
/// </summary>
|
||||
private readonly List<Exception> _exceptions = new List<Exception>();
|
||||
|
||||
private static int GetUniqueID()
|
||||
{
|
||||
int id;
|
||||
var rnd = new Random(DateTime.Now.Millisecond);
|
||||
do
|
||||
{
|
||||
id = rnd.Next(Int32.MaxValue);
|
||||
}
|
||||
while (Identificators.Contains(id));
|
||||
Identificators.Add(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipBase class.
|
||||
/// </summary>
|
||||
protected SevenZipBase()
|
||||
{
|
||||
_password = "";
|
||||
_reportErrors = true;
|
||||
_uniqueID = GetUniqueID();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipBase class
|
||||
/// </summary>
|
||||
/// <param name="password">The archive password.</param>
|
||||
protected SevenZipBase(string password)
|
||||
{
|
||||
if (String.IsNullOrEmpty(password))
|
||||
{
|
||||
throw new SevenZipException("Empty password was specified.");
|
||||
}
|
||||
_password = password;
|
||||
_reportErrors = true;
|
||||
_uniqueID = GetUniqueID();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Removes the UniqueID from the list.
|
||||
/// </summary>
|
||||
~SevenZipBase()
|
||||
{
|
||||
Identificators.Remove(_uniqueID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the archive password
|
||||
/// </summary>
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets throw exceptions on archive errors flag
|
||||
/// </summary>
|
||||
internal bool ReportErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _reportErrors;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user exceptions thrown during the requested operations, for example, in events.
|
||||
/// </summary>
|
||||
internal ReadOnlyCollection<Exception> Exceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ReadOnlyCollection<Exception>(_exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddException(Exception e)
|
||||
{
|
||||
_exceptions.Add(e);
|
||||
}
|
||||
|
||||
internal void ClearExceptions()
|
||||
{
|
||||
_exceptions.Clear();
|
||||
}
|
||||
|
||||
internal bool HasExceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return _exceptions.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws the specified exception when is able to.
|
||||
/// </summary>
|
||||
/// <param name="e">The exception to throw.</param>
|
||||
/// <param name="handler">The handler responsible for the exception.</param>
|
||||
internal bool ThrowException(CallbackBase handler, params Exception[] e)
|
||||
{
|
||||
if (_reportErrors && (handler == null || !handler.Canceled))
|
||||
{
|
||||
throw e[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void ThrowUserException()
|
||||
{
|
||||
if (HasExceptions)
|
||||
{
|
||||
throw new SevenZipException(SevenZipException.USER_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws exception if HRESULT != 0.
|
||||
/// </summary>
|
||||
/// <param name="hresult">Result code to check.</param>
|
||||
/// <param name="message">Exception message.</param>
|
||||
/// <param name="handler">The class responsible for the callback.</param>
|
||||
internal void CheckedExecute(int hresult, string message, CallbackBase handler)
|
||||
{
|
||||
if (hresult != (int) OperationResult.Ok || handler.HasExceptions)
|
||||
{
|
||||
if (!handler.HasExceptions)
|
||||
{
|
||||
if (hresult < -2000000000)
|
||||
{
|
||||
ThrowException(handler,
|
||||
new SevenZipException(
|
||||
"The execution has failed due to the bug in the SevenZipSharp.\n" +
|
||||
"Please report about it to http://sevenzipsharp.codeplex.com/WorkItem/List.aspx, post the release number and attach the archive."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowException(handler,
|
||||
new SevenZipException(message + hresult.ToString(CultureInfo.InvariantCulture) +
|
||||
'.'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowException(handler, handler.Exceptions[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !WINCE && !MONO
|
||||
/// <summary>
|
||||
/// Changes the path to the 7-zip native library.
|
||||
/// </summary>
|
||||
/// <param name="libraryPath">The path to the 7-zip native library.</param>
|
||||
public static void SetLibraryPath(string libraryPath)
|
||||
{
|
||||
SevenZipLibraryManager.SetLibraryPath(libraryPath);
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Gets the current library features.
|
||||
/// </summary>
|
||||
public static LibraryFeature CurrentLibraryFeatures
|
||||
{
|
||||
get
|
||||
{
|
||||
return SevenZipLibraryManager.CurrentLibraryFeatures;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified System.Object is equal to the current SevenZipBase.
|
||||
/// </summary>
|
||||
/// <param name="obj">The System.Object to compare with the current SevenZipBase.</param>
|
||||
/// <returns>true if the specified System.Object is equal to the current SevenZipBase; otherwise, false.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var inst = obj as SevenZipBase;
|
||||
if (inst == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _uniqueID == inst._uniqueID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns> A hash code for the current SevenZipBase.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _uniqueID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a System.String that represents the current SevenZipBase.
|
||||
/// </summary>
|
||||
/// <returns>A System.String that represents the current SevenZipBase.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var type = "SevenZipBase";
|
||||
if (this is SevenZipExtractor)
|
||||
{
|
||||
type = "SevenZipExtractor";
|
||||
}
|
||||
if (this is SevenZipCompressor)
|
||||
{
|
||||
type = "SevenZipCompressor";
|
||||
}
|
||||
return string.Format("{0} [{1}]", type, _uniqueID);
|
||||
}
|
||||
}
|
||||
|
||||
internal class CallbackBase : MarshalByRefObject
|
||||
{
|
||||
private readonly string _password;
|
||||
private readonly bool _reportErrors;
|
||||
/// <summary>
|
||||
/// User exceptions thrown during the requested operations, for example, in events.
|
||||
/// </summary>
|
||||
private readonly List<Exception> _exceptions = new List<Exception>();
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CallbackBase class.
|
||||
/// </summary>
|
||||
protected CallbackBase()
|
||||
{
|
||||
_password = "";
|
||||
_reportErrors = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CallbackBase class.
|
||||
/// </summary>
|
||||
/// <param name="password">The archive password.</param>
|
||||
protected CallbackBase(string password)
|
||||
{
|
||||
if (String.IsNullOrEmpty(password))
|
||||
{
|
||||
throw new SevenZipException("Empty password was specified.");
|
||||
}
|
||||
_password = password;
|
||||
_reportErrors = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the archive password
|
||||
/// </summary>
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value indicating whether the current procedure was cancelled.
|
||||
/// </summary>
|
||||
public bool Canceled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets throw exceptions on archive errors flag
|
||||
/// </summary>
|
||||
public bool ReportErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _reportErrors;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user exceptions thrown during the requested operations, for example, in events.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Exception> Exceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ReadOnlyCollection<Exception>(_exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddException(Exception e)
|
||||
{
|
||||
_exceptions.Add(e);
|
||||
}
|
||||
|
||||
public void ClearExceptions()
|
||||
{
|
||||
_exceptions.Clear();
|
||||
}
|
||||
|
||||
public bool HasExceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return _exceptions.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws the specified exception when is able to.
|
||||
/// </summary>
|
||||
/// <param name="e">The exception to throw.</param>
|
||||
/// <param name="handler">The handler responsible for the exception.</param>
|
||||
public bool ThrowException(CallbackBase handler, params Exception[] e)
|
||||
{
|
||||
if (_reportErrors && (handler == null || !handler.Canceled))
|
||||
{
|
||||
throw e[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws the first exception in the list if any exists.
|
||||
/// </summary>
|
||||
/// <returns>True means no exceptions.</returns>
|
||||
public bool ThrowException()
|
||||
{
|
||||
if (HasExceptions && _reportErrors)
|
||||
{
|
||||
throw _exceptions[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ThrowUserException()
|
||||
{
|
||||
if (HasExceptions)
|
||||
{
|
||||
throw new SevenZipException(SevenZipException.USER_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Struct for storing information about files in the 7-zip archive.
|
||||
/// </summary>
|
||||
public struct ArchiveFileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets index of the file in the archive file table.
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets file name
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file last write time.
|
||||
/// </summary>
|
||||
public DateTime LastWriteTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file creation time.
|
||||
/// </summary>
|
||||
public DateTime CreationTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file creation time.
|
||||
/// </summary>
|
||||
public DateTime LastAccessTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets size of the file (unpacked).
|
||||
/// </summary>
|
||||
public ulong Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets CRC checksum of the file.
|
||||
/// </summary>
|
||||
public uint Crc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets file attributes.
|
||||
/// </summary>
|
||||
public uint Attributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets being a directory.
|
||||
/// </summary>
|
||||
public bool IsDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets being encrypted.
|
||||
/// </summary>
|
||||
public bool Encrypted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets comment for the file.
|
||||
/// </summary>
|
||||
public string Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified System.Object is equal to the current ArchiveFileInfo.
|
||||
/// </summary>
|
||||
/// <param name="obj">The System.Object to compare with the current ArchiveFileInfo.</param>
|
||||
/// <returns>true if the specified System.Object is equal to the current ArchiveFileInfo; otherwise, false.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is ArchiveFileInfo) ? Equals((ArchiveFileInfo) obj) : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveFileInfo is equal to the current ArchiveFileInfo.
|
||||
/// </summary>
|
||||
/// <param name="afi">The ArchiveFileInfo to compare with the current ArchiveFileInfo.</param>
|
||||
/// <returns>true if the specified ArchiveFileInfo is equal to the current ArchiveFileInfo; otherwise, false.</returns>
|
||||
public bool Equals(ArchiveFileInfo afi)
|
||||
{
|
||||
return afi.Index == Index && afi.FileName == FileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns> A hash code for the current ArchiveFileInfo.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return FileName.GetHashCode() ^ Index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a System.String that represents the current ArchiveFileInfo.
|
||||
/// </summary>
|
||||
/// <returns>A System.String that represents the current ArchiveFileInfo.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "[" + Index.ToString(CultureInfo.CurrentCulture) + "] " + FileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveFileInfo instances are considered equal.
|
||||
/// </summary>
|
||||
/// <param name="afi1">The first ArchiveFileInfo to compare.</param>
|
||||
/// <param name="afi2">The second ArchiveFileInfo to compare.</param>
|
||||
/// <returns>true if the specified ArchiveFileInfo instances are considered equal; otherwise, false.</returns>
|
||||
public static bool operator ==(ArchiveFileInfo afi1, ArchiveFileInfo afi2)
|
||||
{
|
||||
return afi1.Equals(afi2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveFileInfo instances are not considered equal.
|
||||
/// </summary>
|
||||
/// <param name="afi1">The first ArchiveFileInfo to compare.</param>
|
||||
/// <param name="afi2">The second ArchiveFileInfo to compare.</param>
|
||||
/// <returns>true if the specified ArchiveFileInfo instances are not considered equal; otherwise, false.</returns>
|
||||
public static bool operator !=(ArchiveFileInfo afi1, ArchiveFileInfo afi2)
|
||||
{
|
||||
return !afi1.Equals(afi2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archive property struct.
|
||||
/// </summary>
|
||||
public struct ArchiveProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the archive property.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the archive property.
|
||||
/// </summary>
|
||||
public object Value { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified System.Object is equal to the current ArchiveProperty.
|
||||
/// </summary>
|
||||
/// <param name="obj">The System.Object to compare with the current ArchiveProperty.</param>
|
||||
/// <returns>true if the specified System.Object is equal to the current ArchiveProperty; otherwise, false.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is ArchiveProperty) ? Equals((ArchiveProperty) obj) : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveProperty is equal to the current ArchiveProperty.
|
||||
/// </summary>
|
||||
/// <param name="afi">The ArchiveProperty to compare with the current ArchiveProperty.</param>
|
||||
/// <returns>true if the specified ArchiveProperty is equal to the current ArchiveProperty; otherwise, false.</returns>
|
||||
public bool Equals(ArchiveProperty afi)
|
||||
{
|
||||
return afi.Name == Name && afi.Value == Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns> A hash code for the current ArchiveProperty.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Name.GetHashCode() ^ Value.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a System.String that represents the current ArchiveProperty.
|
||||
/// </summary>
|
||||
/// <returns>A System.String that represents the current ArchiveProperty.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return Name + " = " + Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveProperty instances are considered equal.
|
||||
/// </summary>
|
||||
/// <param name="afi1">The first ArchiveProperty to compare.</param>
|
||||
/// <param name="afi2">The second ArchiveProperty to compare.</param>
|
||||
/// <returns>true if the specified ArchiveProperty instances are considered equal; otherwise, false.</returns>
|
||||
public static bool operator ==(ArchiveProperty afi1, ArchiveProperty afi2)
|
||||
{
|
||||
return afi1.Equals(afi2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified ArchiveProperty instances are not considered equal.
|
||||
/// </summary>
|
||||
/// <param name="afi1">The first ArchiveProperty to compare.</param>
|
||||
/// <param name="afi2">The second ArchiveProperty to compare.</param>
|
||||
/// <returns>true if the specified ArchiveProperty instances are not considered equal; otherwise, false.</returns>
|
||||
public static bool operator !=(ArchiveProperty afi1, ArchiveProperty afi2)
|
||||
{
|
||||
return !afi1.Equals(afi2);
|
||||
}
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
|
||||
/// <summary>
|
||||
/// Archive compression mode.
|
||||
/// </summary>
|
||||
public enum CompressionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new archive; overwrite the existing one.
|
||||
/// </summary>
|
||||
Create,
|
||||
/// <summary>
|
||||
/// Add data to the archive.
|
||||
/// </summary>
|
||||
Append,
|
||||
}
|
||||
|
||||
internal enum InternalCompressionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new archive; overwrite the existing one.
|
||||
/// </summary>
|
||||
Create,
|
||||
/// <summary>
|
||||
/// Add data to the archive.
|
||||
/// </summary>
|
||||
Append,
|
||||
/// <summary>
|
||||
/// Modify archive data.
|
||||
/// </summary>
|
||||
Modify
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zip encryption method enum.
|
||||
/// </summary>
|
||||
public enum ZipEncryptionMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// ZipCrypto encryption method.
|
||||
/// </summary>
|
||||
ZipCrypto,
|
||||
/// <summary>
|
||||
/// AES 128 bit encryption method.
|
||||
/// </summary>
|
||||
Aes128,
|
||||
/// <summary>
|
||||
/// AES 192 bit encryption method.
|
||||
/// </summary>
|
||||
Aes192,
|
||||
/// <summary>
|
||||
/// AES 256 bit encryption method.
|
||||
/// </summary>
|
||||
Aes256
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archive update data for UpdateCallback.
|
||||
/// </summary>
|
||||
internal struct UpdateData
|
||||
{
|
||||
public uint FilesCount;
|
||||
public InternalCompressionMode Mode;
|
||||
|
||||
public Dictionary<int, string> FileNamesToModify { get; set; }
|
||||
|
||||
public List<ArchiveFileInfo> ArchiveFileData { get; set; }
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// EventArgs for storing PercentDone property.
|
||||
/// </summary>
|
||||
public class PercentDoneEventArgs : EventArgs
|
||||
{
|
||||
private readonly byte _percentDone;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PercentDoneEventArgs class.
|
||||
/// </summary>
|
||||
/// <param name="percentDone">The percent of finished work.</param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException"/>
|
||||
public PercentDoneEventArgs(byte percentDone)
|
||||
{
|
||||
if (percentDone > 100 || percentDone < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("percentDone",
|
||||
"The percent of finished work must be between 0 and 100.");
|
||||
}
|
||||
_percentDone = percentDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the percent of finished work.
|
||||
/// </summary>
|
||||
public byte PercentDone
|
||||
{
|
||||
get
|
||||
{
|
||||
return _percentDone;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to stop the current archive operation.
|
||||
/// </summary>
|
||||
public bool Cancel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts a [0, 1] rate to its percent equivalent.
|
||||
/// </summary>
|
||||
/// <param name="doneRate">The rate of the done work.</param>
|
||||
/// <returns>Percent integer equivalent.</returns>
|
||||
/// <exception cref="System.ArgumentException"/>
|
||||
internal static byte ProducePercentDone(float doneRate)
|
||||
{
|
||||
#if !WINCE
|
||||
return (byte) Math.Round(Math.Min(100*doneRate, 100), MidpointRounding.AwayFromZero);
|
||||
#else
|
||||
return (byte) Math.Round(Math.Min(100*doneRate, 100));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The EventArgs class for accurate progress handling.
|
||||
/// </summary>
|
||||
public sealed class ProgressEventArgs : PercentDoneEventArgs
|
||||
{
|
||||
private readonly byte _delta;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ProgressEventArgs class.
|
||||
/// </summary>
|
||||
/// <param name="percentDone">The percent of finished work.</param>
|
||||
/// <param name="percentDelta">The percent of work done after the previous event.</param>
|
||||
public ProgressEventArgs(byte percentDone, byte percentDelta)
|
||||
: base(percentDone)
|
||||
{
|
||||
_delta = percentDelta;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the change in done work percentage.
|
||||
/// </summary>
|
||||
public byte PercentDelta
|
||||
{
|
||||
get
|
||||
{
|
||||
return _delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// EventArgs used to report the file information which is going to be packed.
|
||||
/// </summary>
|
||||
public sealed class FileInfoEventArgs : PercentDoneEventArgs
|
||||
{
|
||||
private readonly ArchiveFileInfo _fileInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FileInfoEventArgs class.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The current ArchiveFileInfo.</param>
|
||||
/// <param name="percentDone">The percent of finished work.</param>
|
||||
public FileInfoEventArgs(ArchiveFileInfo fileInfo, byte percentDone)
|
||||
: base(percentDone)
|
||||
{
|
||||
_fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the corresponding FileInfo to the event.
|
||||
/// </summary>
|
||||
public ArchiveFileInfo FileInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs used to report the size of unpacked archive data
|
||||
/// </summary>
|
||||
public sealed class OpenEventArgs : EventArgs
|
||||
{
|
||||
private readonly ulong _totalSize;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the OpenEventArgs class
|
||||
/// </summary>
|
||||
/// <param name="totalSize">Size of unpacked archive data</param>
|
||||
public OpenEventArgs(ulong totalSize)
|
||||
{
|
||||
_totalSize = totalSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of unpacked archive data
|
||||
/// </summary>
|
||||
public ulong TotalSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _totalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an int number
|
||||
/// </summary>
|
||||
public sealed class IntEventArgs : EventArgs
|
||||
{
|
||||
private readonly int _value;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IntEventArgs class
|
||||
/// </summary>
|
||||
/// <param name="value">Useful data carried by the IntEventArgs class</param>
|
||||
public IntEventArgs(int value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the IntEventArgs class
|
||||
/// </summary>
|
||||
public int Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs class which stores the file name.
|
||||
/// </summary>
|
||||
public sealed class FileNameEventArgs : PercentDoneEventArgs
|
||||
{
|
||||
private readonly string _fileName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FileNameEventArgs class.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file name.</param>
|
||||
/// <param name="percentDone">The percent of finished work</param>
|
||||
public FileNameEventArgs(string fileName, byte percentDone) :
|
||||
base(percentDone)
|
||||
{
|
||||
_fileName = fileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file name.
|
||||
/// </summary>
|
||||
public string FileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs for FileExists event, stores the file name and asks whether to overwrite it in case it already exists.
|
||||
/// </summary>
|
||||
public sealed class FileOverwriteEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FileOverwriteEventArgs class
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file name.</param>
|
||||
public FileOverwriteEventArgs(string fileName)
|
||||
{
|
||||
FileName = fileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value indicating whether to cancel the extraction.
|
||||
/// </summary>
|
||||
public bool Cancel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file name to extract to. Null means skip.
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The reason for calling <see cref="ExtractFileCallback"/>.
|
||||
/// </summary>
|
||||
public enum ExtractFileCallbackReason
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ExtractFileCallback"/> is called the first time for a file.
|
||||
/// </summary>
|
||||
Start,
|
||||
|
||||
/// <summary>
|
||||
/// All data has been written to the target without any exceptions.
|
||||
/// </summary>
|
||||
Done,
|
||||
|
||||
/// <summary>
|
||||
/// An exception occured during extraction of the file.
|
||||
/// </summary>
|
||||
Failure
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The arguments passed to <see cref="ExtractFileCallback"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For each file, <see cref="ExtractFileCallback"/> is first called with <see cref="Reason"/>
|
||||
/// set to <see cref="ExtractFileCallbackReason.Start"/>. If the callback chooses to extract the
|
||||
/// file data by setting <see cref="ExtractToFile"/> or <see cref="ExtractToStream"/>, the callback
|
||||
/// will be called a second time with <see cref="Reason"/> set to
|
||||
/// <see cref="ExtractFileCallbackReason.Done"/> or <see cref="ExtractFileCallbackReason.Failure"/>
|
||||
/// to allow for any cleanup task like closing the stream.
|
||||
/// </remarks>
|
||||
public class ExtractFileCallbackArgs : EventArgs
|
||||
{
|
||||
private readonly ArchiveFileInfo _archiveFileInfo;
|
||||
private Stream _extractToStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExtractFileCallbackArgs"/> class.
|
||||
/// </summary>
|
||||
/// <param name="archiveFileInfo">The information about file in the archive.</param>
|
||||
public ExtractFileCallbackArgs(ArchiveFileInfo archiveFileInfo)
|
||||
{
|
||||
Reason = ExtractFileCallbackReason.Start;
|
||||
_archiveFileInfo = archiveFileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about file in the archive.
|
||||
/// </summary>
|
||||
/// <value>Information about file in the archive.</value>
|
||||
public ArchiveFileInfo ArchiveFileInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return _archiveFileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The reason for calling <see cref="ExtractFileCallback"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If neither <see cref="ExtractToFile"/> nor <see cref="ExtractToStream"/> is set,
|
||||
/// <see cref="ExtractFileCallback"/> will not be called after <see cref="ExtractFileCallbackReason.Start"/>.
|
||||
/// </remarks>
|
||||
/// <value>The reason.</value>
|
||||
public ExtractFileCallbackReason Reason { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The exception that occurred during extraction.
|
||||
/// </summary>
|
||||
/// <value>The _Exception.</value>
|
||||
/// <remarks>
|
||||
/// If the callback is called with <see cref="Reason"/> set to <see cref="ExtractFileCallbackReason.Failure"/>,
|
||||
/// this member contains the _Exception that occurred.
|
||||
/// The default behavior is to rethrow the _Exception after return of the callback.
|
||||
/// However the callback can set <see cref="Exception"/> to <c>null</c> to swallow the _Exception
|
||||
/// and continue extraction with the next file.
|
||||
/// </remarks>
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to cancel the extraction.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> to cancel the extraction; <c>false</c> to continue. The default is <c>false</c>.</value>
|
||||
public bool CancelExtraction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether and where to extract the file.
|
||||
/// </summary>
|
||||
/// <value>The path where to extract the file to.</value>
|
||||
/// <remarks>
|
||||
/// If <see cref="ExtractToStream"/> is set, this mmember will be ignored.
|
||||
/// </remarks>
|
||||
public string ExtractToFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether and where to extract the file.
|
||||
/// </summary>
|
||||
/// <value>The the extracted data is written to.</value>
|
||||
/// <remarks>
|
||||
/// If both this member and <see cref="ExtractToFile"/> are <c>null</c> (the defualt), the file
|
||||
/// will not be extracted and the callback will be be executed a second time with the <see cref="Reason"/>
|
||||
/// set to <see cref="ExtractFileCallbackReason.Done"/> or <see cref="ExtractFileCallbackReason.Failure"/>.
|
||||
/// </remarks>
|
||||
public Stream ExtractToStream
|
||||
{
|
||||
get
|
||||
{
|
||||
return _extractToStream;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_extractToStream != null && !_extractToStream.CanWrite)
|
||||
{
|
||||
throw new ExtractionFailedException("The specified stream is not writable!");
|
||||
}
|
||||
_extractToStream = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets any data that will be preserved between the <see cref="ExtractFileCallbackReason.Start"/> callback call
|
||||
/// and the <see cref="ExtractFileCallbackReason.Done"/> or <see cref="ExtractFileCallbackReason.Failure"/> calls.
|
||||
/// </summary>
|
||||
/// <value>The data.</value>
|
||||
public object ObjectData { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback delegate for <see cref="SevenZipExtractor.ExtractFiles(SevenZip.ExtractFileCallback)"/>.
|
||||
/// </summary>
|
||||
public delegate void ExtractFileCallback(ExtractFileCallbackArgs extractFileCallbackArgs);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
#if !WINCE
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// Base SevenZip exception class.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// The message for thrown user exceptions.
|
||||
/// </summary>
|
||||
internal const string USER_EXCEPTION_MESSAGE = "The extraction was successful but" +
|
||||
"some exceptions were thrown in your events. Check UserExceptions for details.";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
public SevenZipException() : base("SevenZip unknown exception.") {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
/// <param name="defaultMessage">Default exception message</param>
|
||||
public SevenZipException(string defaultMessage)
|
||||
: base(defaultMessage) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
/// <param name="defaultMessage">Default exception message</param>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipException(string defaultMessage, string message)
|
||||
: base(defaultMessage + " Message: " + message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
/// <param name="defaultMessage">Default exception message</param>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipException(string defaultMessage, string message, Exception inner)
|
||||
: base(
|
||||
defaultMessage + (defaultMessage.EndsWith(" ", StringComparison.CurrentCulture) ? "" : " Message: ") +
|
||||
message, inner) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
/// <param name="defaultMessage">Default exception message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipException(string defaultMessage, Exception inner)
|
||||
: base(defaultMessage, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNMANAGED
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for ArchiveExtractCallback.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ExtractionFailedException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "Could not extract files!";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ExtractionFailedException class
|
||||
/// </summary>
|
||||
public ExtractionFailedException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public ExtractionFailedException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public ExtractionFailedException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected ExtractionFailedException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for ArchiveUpdateCallback.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CompressionFailedException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "Could not pack files!";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CompressionFailedException class
|
||||
/// </summary>
|
||||
public CompressionFailedException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public CompressionFailedException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public CompressionFailedException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected CompressionFailedException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for LZMA operations.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class LzmaException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "Specified stream is not a valid LZMA compressed stream!";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaException class
|
||||
/// </summary>
|
||||
public LzmaException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public LzmaException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public LzmaException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected LzmaException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNMANAGED
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for 7-zip archive open or read operations.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipArchiveException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE =
|
||||
"Invalid archive: open/read error! Is it encrypted and a wrong password was provided?\n" +
|
||||
"If your archive is an exotic one, it is possible that SevenZipSharp has no signature for "+
|
||||
"its format and thus decided it is TAR by mistake.";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipArchiveException class
|
||||
/// </summary>
|
||||
public SevenZipArchiveException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipArchiveException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipArchiveException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipArchiveException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipArchiveException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipArchiveException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipArchiveException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for empty common root if file name array in SevenZipCompressor.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipInvalidFileNamesException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "Invalid file names have been specified: ";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipInvalidFileNamesException class
|
||||
/// </summary>
|
||||
public SevenZipInvalidFileNamesException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipInvalidFileNamesException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipInvalidFileNamesException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipInvalidFileNamesException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipInvalidFileNamesException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipInvalidFileNamesException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipInvalidFileNamesException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for fail to create an archive in SevenZipCompressor.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipCompressionFailedException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "The compression has failed for an unknown reason with code ";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipCompressionFailedException class
|
||||
/// </summary>
|
||||
public SevenZipCompressionFailedException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipCompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipCompressionFailedException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipCompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipCompressionFailedException(string message, Exception inner)
|
||||
: base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipCompressionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipCompressionFailedException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for fail to extract an archive in SevenZipExtractor.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipExtractionFailedException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "The extraction has failed for an unknown reason with code ";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipExtractionFailedException class
|
||||
/// </summary>
|
||||
public SevenZipExtractionFailedException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipExtractionFailedException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipExtractionFailedException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipExtractionFailedException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipExtractionFailedException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for 7-zip library operations.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipLibraryException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public const string DEFAULT_MESSAGE = "Can not load 7-zip library or internal COM error!";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipLibraryException class
|
||||
/// </summary>
|
||||
public SevenZipLibraryException() : base(DEFAULT_MESSAGE) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipLibraryException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipLibraryException(string message) : base(DEFAULT_MESSAGE, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipLibraryException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipLibraryException(string message, Exception inner) : base(DEFAULT_MESSAGE, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipLibraryException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipLibraryException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SFX
|
||||
|
||||
/// <summary>
|
||||
/// Exception class for 7-zip sfx settings validation.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SevenZipSfxValidationException : SevenZipException
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception dafault message which is displayed if no extra information is specified
|
||||
/// </summary>
|
||||
public static readonly string DefaultMessage = "Sfx settings validation failed.";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfxValidationException class
|
||||
/// </summary>
|
||||
public SevenZipSfxValidationException() : base(DefaultMessage) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfxValidationException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
public SevenZipSfxValidationException(string message) : base(DefaultMessage, message) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfxValidationException class
|
||||
/// </summary>
|
||||
/// <param name="message">Additional detailed message</param>
|
||||
/// <param name="inner">Inner exception occured</param>
|
||||
public SevenZipSfxValidationException(string message, Exception inner) : base(DefaultMessage, message, inner) {}
|
||||
#if !WINCE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfxValidationException class
|
||||
/// </summary>
|
||||
/// <param name="info">All data needed for serialization or deserialization</param>
|
||||
/// <param name="context">Serialized stream descriptor</param>
|
||||
protected SevenZipSfxValidationException(
|
||||
SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// The signature checker class. Original code by Siddharth Uppal, adapted by Markhor.
|
||||
/// </summary>
|
||||
/// <remarks>Based on the code at http://blog.somecreativity.com/2008/04/08/how-to-check-if-a-file-is-compressed-in-c/#</remarks>
|
||||
public static class FileChecker
|
||||
{
|
||||
public static bool ThrowExceptions = true;
|
||||
|
||||
private const int SIGNATURE_SIZE = 16;
|
||||
private const int SFX_SCAN_LENGTH = 256 * 1024;
|
||||
|
||||
private static bool SpecialDetect(Stream stream, int offset, InArchiveFormat expectedFormat)
|
||||
{
|
||||
if (stream.Length > offset + SIGNATURE_SIZE)
|
||||
{
|
||||
var signature = new byte[SIGNATURE_SIZE];
|
||||
int bytesRequired = SIGNATURE_SIZE;
|
||||
int index = 0;
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
while (bytesRequired > 0)
|
||||
{
|
||||
int bytesRead = stream.Read(signature, index, bytesRequired);
|
||||
bytesRequired -= bytesRead;
|
||||
index += bytesRead;
|
||||
}
|
||||
string actualSignature = BitConverter.ToString(signature);
|
||||
foreach (string expectedSignature in Formats.InSignatureFormats.Keys)
|
||||
{
|
||||
if (Formats.InSignatureFormats[expectedSignature] != expectedFormat)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (actualSignature.StartsWith(expectedSignature, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the InArchiveFormat for a specific extension.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to identify.</param>
|
||||
/// <param name="offset">The archive beginning offset.</param>
|
||||
/// <param name="isExecutable">True if the original format of the stream is PE; otherwise, false.</param>
|
||||
/// <returns>Corresponding InArchiveFormat.</returns>
|
||||
public static InArchiveFormat CheckSignature(Stream stream, out int offset, out bool isExecutable)
|
||||
{
|
||||
offset = 0;
|
||||
isExecutable = false;
|
||||
|
||||
if (!stream.CanRead)
|
||||
{
|
||||
if (ThrowExceptions)
|
||||
throw new ArgumentException("The stream must be readable.");
|
||||
else return InArchiveFormat.None;
|
||||
}
|
||||
if (stream.Length < SIGNATURE_SIZE)
|
||||
{
|
||||
if (ThrowExceptions)
|
||||
throw new ArgumentException("The stream is invalid.");
|
||||
else return InArchiveFormat.None;
|
||||
}
|
||||
|
||||
#region Get file signature
|
||||
|
||||
var signature = new byte[SIGNATURE_SIZE];
|
||||
int bytesRequired = SIGNATURE_SIZE;
|
||||
int index = 0;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
while (bytesRequired > 0)
|
||||
{
|
||||
int bytesRead = stream.Read(signature, index, bytesRequired);
|
||||
bytesRequired -= bytesRead;
|
||||
index += bytesRead;
|
||||
}
|
||||
string actualSignature = BitConverter.ToString(signature);
|
||||
|
||||
#endregion
|
||||
|
||||
InArchiveFormat suspectedFormat = InArchiveFormat.XZ; // any except PE and Cab
|
||||
isExecutable = false;
|
||||
|
||||
foreach (string expectedSignature in Formats.InSignatureFormats.Keys)
|
||||
{
|
||||
if (actualSignature.StartsWith(expectedSignature, StringComparison.OrdinalIgnoreCase) ||
|
||||
actualSignature.Substring(6).StartsWith(expectedSignature, StringComparison.OrdinalIgnoreCase) &&
|
||||
Formats.InSignatureFormats[expectedSignature] == InArchiveFormat.Lzh)
|
||||
{
|
||||
if (Formats.InSignatureFormats[expectedSignature] == InArchiveFormat.PE)
|
||||
{
|
||||
suspectedFormat = InArchiveFormat.PE;
|
||||
isExecutable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Formats.InSignatureFormats[expectedSignature];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Many Microsoft formats
|
||||
if (actualSignature.StartsWith("D0-CF-11-E0-A1-B1-1A-E1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
suspectedFormat = InArchiveFormat.Cab; // != InArchiveFormat.XZ
|
||||
}
|
||||
|
||||
#region SpecialDetect
|
||||
try
|
||||
{
|
||||
SpecialDetect(stream, 257, InArchiveFormat.Tar);
|
||||
}
|
||||
catch (ArgumentException) {}
|
||||
if (SpecialDetect(stream, 0x8001, InArchiveFormat.Iso))
|
||||
{
|
||||
return InArchiveFormat.Iso;
|
||||
}
|
||||
if (SpecialDetect(stream, 0x8801, InArchiveFormat.Iso))
|
||||
{
|
||||
return InArchiveFormat.Iso;
|
||||
}
|
||||
if (SpecialDetect(stream, 0x9001, InArchiveFormat.Iso))
|
||||
{
|
||||
return InArchiveFormat.Iso;
|
||||
}
|
||||
if (SpecialDetect(stream, 0x9001, InArchiveFormat.Iso))
|
||||
{
|
||||
return InArchiveFormat.Iso;
|
||||
}
|
||||
if (SpecialDetect(stream, 0x400, InArchiveFormat.Hfs))
|
||||
{
|
||||
return InArchiveFormat.Hfs;
|
||||
}
|
||||
#region Last resort for tar - can mistake
|
||||
if (stream.Length >= 1024)
|
||||
{
|
||||
stream.Seek(-1024, SeekOrigin.End);
|
||||
byte[] buf = new byte[1024];
|
||||
stream.Read(buf, 0, 1024);
|
||||
bool istar = true;
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
istar = istar && buf[i] == 0;
|
||||
}
|
||||
if (istar)
|
||||
{
|
||||
return InArchiveFormat.Tar;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Check if it is an SFX archive or a file with an embedded archive.
|
||||
if (suspectedFormat != InArchiveFormat.XZ)
|
||||
{
|
||||
#region Get first Min(stream.Length, SFX_SCAN_LENGTH) bytes
|
||||
var scanLength = Math.Min(stream.Length, SFX_SCAN_LENGTH);
|
||||
signature = new byte[scanLength];
|
||||
bytesRequired = (int)scanLength;
|
||||
index = 0;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
while (bytesRequired > 0)
|
||||
{
|
||||
int bytesRead = stream.Read(signature, index, bytesRequired);
|
||||
bytesRequired -= bytesRead;
|
||||
index += bytesRead;
|
||||
}
|
||||
actualSignature = BitConverter.ToString(signature);
|
||||
#endregion
|
||||
|
||||
foreach (var format in new InArchiveFormat[]
|
||||
{
|
||||
InArchiveFormat.Zip,
|
||||
InArchiveFormat.SevenZip,
|
||||
InArchiveFormat.Rar,
|
||||
InArchiveFormat.Cab,
|
||||
InArchiveFormat.Arj
|
||||
})
|
||||
{
|
||||
int pos = actualSignature.IndexOf(Formats.InSignatureFormatsReversed[format]);
|
||||
if (pos > -1)
|
||||
{
|
||||
offset = pos / 3;
|
||||
return format;
|
||||
}
|
||||
}
|
||||
// Nothing
|
||||
if (suspectedFormat == InArchiveFormat.PE)
|
||||
{
|
||||
return InArchiveFormat.PE;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (ThrowExceptions)
|
||||
throw new ArgumentException("The stream is invalid or no corresponding signature was found.");
|
||||
else return InArchiveFormat.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the InArchiveFormat for a specific file name.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The archive file name.</param>
|
||||
/// <param name="offset">The archive beginning offset.</param>
|
||||
/// <param name="isExecutable">True if the original format of the file is PE; otherwise, false.</param>
|
||||
/// <returns>Corresponding InArchiveFormat.</returns>
|
||||
/// <exception cref="System.ArgumentException"/>
|
||||
public static InArchiveFormat CheckSignature(string fileName, out int offset, out bool isExecutable)
|
||||
{
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
try
|
||||
{
|
||||
InArchiveFormat format = CheckSignature(fs, out offset, out isExecutable);
|
||||
if (format != InArchiveFormat.None) return format;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
isExecutable = false;
|
||||
return Formats.FormatByFileName(fileName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,540 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// Readable archive format enumeration.
|
||||
/// </summary>
|
||||
public enum InArchiveFormat
|
||||
{
|
||||
/// <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="http://en.wikipedia.org/wiki/Rar">Wikipedia information</a></remarks>
|
||||
Rar,
|
||||
/// <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>
|
||||
/// Not an archive
|
||||
/// </summary>
|
||||
None
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// Writable archive format enumeration.
|
||||
/// </summary>
|
||||
public enum OutArchiveFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Open 7-zip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/7-zip">Wikipedia information</a></remarks>
|
||||
SevenZip,
|
||||
/// <summary>
|
||||
/// Open Zip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/ZIP_(file_format)">Wikipedia information</a></remarks>
|
||||
Zip,
|
||||
/// <summary>
|
||||
/// Open Gzip archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Gzip">Wikipedia information</a></remarks>
|
||||
GZip,
|
||||
/// <summary>
|
||||
/// Open Bzip2 archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Bzip2">Wikipedia information</a></remarks>
|
||||
BZip2,
|
||||
/// <summary>
|
||||
/// Open Tar archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Tar_(file_format)">Wikipedia information</a></remarks>
|
||||
Tar,
|
||||
/// <summary>
|
||||
/// Open Xz archive format.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Xz">Wikipedia information</a></remarks>
|
||||
XZ
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compression level enumeration
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// No compression
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Very low compression level
|
||||
/// </summary>
|
||||
Fast,
|
||||
/// <summary>
|
||||
/// Low compression level
|
||||
/// </summary>
|
||||
Low,
|
||||
/// <summary>
|
||||
/// Normal compression level (default)
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// High compression level
|
||||
/// </summary>
|
||||
High,
|
||||
/// <summary>
|
||||
/// The best compression level (slow)
|
||||
/// </summary>
|
||||
Ultra
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compression method enumeration.
|
||||
/// </summary>
|
||||
/// <remarks>Some methods are applicable only to Zip format, some - only to 7-zip.</remarks>
|
||||
public enum CompressionMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Zip or 7-zip|no compression method.
|
||||
/// </summary>
|
||||
Copy,
|
||||
/// <summary>
|
||||
/// Zip|Deflate method.
|
||||
/// </summary>
|
||||
Deflate,
|
||||
/// <summary>
|
||||
/// Zip|Deflate64 method.
|
||||
/// </summary>
|
||||
Deflate64,
|
||||
/// <summary>
|
||||
/// Zip or 7-zip|Bzip2 method.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Cabinet_(file_format)">Wikipedia information</a></remarks>
|
||||
BZip2,
|
||||
/// <summary>
|
||||
/// Zip or 7-zip|LZMA method based on Lempel-Ziv algorithm, it is default for 7-zip.
|
||||
/// </summary>
|
||||
Lzma,
|
||||
/// <summary>
|
||||
/// 7-zip|LZMA version 2, LZMA with improved multithreading and usually slight archive size decrease.
|
||||
/// </summary>
|
||||
Lzma2,
|
||||
/// <summary>
|
||||
/// Zip or 7-zip|PPMd method based on Dmitry Shkarin's PPMdH source code, very efficient for compressing texts.
|
||||
/// </summary>
|
||||
/// <remarks><a href="http://en.wikipedia.org/wiki/Prediction_by_Partial_Matching">Wikipedia information</a></remarks>
|
||||
Ppmd,
|
||||
/// <summary>
|
||||
/// No method change.
|
||||
/// </summary>
|
||||
Default
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Archive format routines
|
||||
/// </summary>
|
||||
public static class Formats
|
||||
{
|
||||
/*/// <summary>
|
||||
/// Gets the max value of the specified enum type.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the enum</param>
|
||||
/// <returns>Max value</returns>
|
||||
internal static int GetMaxValue(Type type)
|
||||
{
|
||||
List<int> enumList = new List<int>((IEnumerable<int>)Enum.GetValues(type));
|
||||
enumList.Sort();
|
||||
return enumList[enumList.Count - 1];
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// List of readable archive format interface guids for 7-zip COM interop.
|
||||
/// </summary>
|
||||
internal static readonly Dictionary<InArchiveFormat, Guid> InFormatGuids =
|
||||
new Dictionary<InArchiveFormat, Guid>(20)
|
||||
#region InFormatGuids initialization
|
||||
|
||||
{
|
||||
{InArchiveFormat.SevenZip, new Guid("23170f69-40c1-278a-1000-000110070000")},
|
||||
{InArchiveFormat.Arj, new Guid("23170f69-40c1-278a-1000-000110040000")},
|
||||
{InArchiveFormat.BZip2, new Guid("23170f69-40c1-278a-1000-000110020000")},
|
||||
{InArchiveFormat.Cab, new Guid("23170f69-40c1-278a-1000-000110080000")},
|
||||
{InArchiveFormat.Chm, new Guid("23170f69-40c1-278a-1000-000110e90000")},
|
||||
{InArchiveFormat.Compound, new Guid("23170f69-40c1-278a-1000-000110e50000")},
|
||||
{InArchiveFormat.Cpio, new Guid("23170f69-40c1-278a-1000-000110ed0000")},
|
||||
{InArchiveFormat.Deb, new Guid("23170f69-40c1-278a-1000-000110ec0000")},
|
||||
{InArchiveFormat.GZip, new Guid("23170f69-40c1-278a-1000-000110ef0000")},
|
||||
{InArchiveFormat.Iso, new Guid("23170f69-40c1-278a-1000-000110e70000")},
|
||||
{InArchiveFormat.Lzh, new Guid("23170f69-40c1-278a-1000-000110060000")},
|
||||
{InArchiveFormat.Lzma, new Guid("23170f69-40c1-278a-1000-0001100a0000")},
|
||||
{InArchiveFormat.Nsis, new Guid("23170f69-40c1-278a-1000-000110090000")},
|
||||
{InArchiveFormat.Rar, new Guid("23170f69-40c1-278a-1000-000110030000")},
|
||||
{InArchiveFormat.Rpm, new Guid("23170f69-40c1-278a-1000-000110eb0000")},
|
||||
{InArchiveFormat.Split, new Guid("23170f69-40c1-278a-1000-000110ea0000")},
|
||||
{InArchiveFormat.Tar, new Guid("23170f69-40c1-278a-1000-000110ee0000")},
|
||||
{InArchiveFormat.Wim, new Guid("23170f69-40c1-278a-1000-000110e60000")},
|
||||
{InArchiveFormat.Lzw, new Guid("23170f69-40c1-278a-1000-000110050000")},
|
||||
{InArchiveFormat.Zip, new Guid("23170f69-40c1-278a-1000-000110010000")},
|
||||
{InArchiveFormat.Udf, new Guid("23170f69-40c1-278a-1000-000110E00000")},
|
||||
{InArchiveFormat.Xar, new Guid("23170f69-40c1-278a-1000-000110E10000")},
|
||||
{InArchiveFormat.Mub, new Guid("23170f69-40c1-278a-1000-000110E20000")},
|
||||
{InArchiveFormat.Hfs, new Guid("23170f69-40c1-278a-1000-000110E30000")},
|
||||
{InArchiveFormat.Dmg, new Guid("23170f69-40c1-278a-1000-000110E40000")},
|
||||
{InArchiveFormat.XZ, new Guid("23170f69-40c1-278a-1000-0001100C0000")},
|
||||
{InArchiveFormat.Mslz, new Guid("23170f69-40c1-278a-1000-000110D50000")},
|
||||
{InArchiveFormat.PE, new Guid("23170f69-40c1-278a-1000-000110DD0000")},
|
||||
{InArchiveFormat.Elf, new Guid("23170f69-40c1-278a-1000-000110DE0000")},
|
||||
{InArchiveFormat.Swf, new Guid("23170f69-40c1-278a-1000-000110D70000")},
|
||||
{InArchiveFormat.Vhd, new Guid("23170f69-40c1-278a-1000-000110DC0000")}
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// List of writable archive format interface guids for 7-zip COM interop.
|
||||
/// </summary>
|
||||
internal static readonly Dictionary<OutArchiveFormat, Guid> OutFormatGuids =
|
||||
new Dictionary<OutArchiveFormat, Guid>(2)
|
||||
#region OutFormatGuids initialization
|
||||
|
||||
{
|
||||
{OutArchiveFormat.SevenZip, new Guid("23170f69-40c1-278a-1000-000110070000")},
|
||||
{OutArchiveFormat.Zip, new Guid("23170f69-40c1-278a-1000-000110010000")},
|
||||
{OutArchiveFormat.BZip2, new Guid("23170f69-40c1-278a-1000-000110020000")},
|
||||
{OutArchiveFormat.GZip, new Guid("23170f69-40c1-278a-1000-000110ef0000")},
|
||||
{OutArchiveFormat.Tar, new Guid("23170f69-40c1-278a-1000-000110ee0000")},
|
||||
{OutArchiveFormat.XZ, new Guid("23170f69-40c1-278a-1000-0001100C0000")},
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
internal static readonly Dictionary<CompressionMethod, string> MethodNames =
|
||||
new Dictionary<CompressionMethod, string>(6)
|
||||
#region MethodNames initialization
|
||||
|
||||
{
|
||||
{CompressionMethod.Copy, "Copy"},
|
||||
{CompressionMethod.Deflate, "Deflate"},
|
||||
{CompressionMethod.Deflate64, "Deflate64"},
|
||||
{CompressionMethod.Lzma, "LZMA"},
|
||||
{CompressionMethod.Lzma2, "LZMA2"},
|
||||
{CompressionMethod.Ppmd, "PPMd"},
|
||||
{CompressionMethod.BZip2, "BZip2"}
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
internal static readonly Dictionary<OutArchiveFormat, InArchiveFormat> InForOutFormats =
|
||||
new Dictionary<OutArchiveFormat, InArchiveFormat>(6)
|
||||
#region InForOutFormats initialization
|
||||
|
||||
{
|
||||
{OutArchiveFormat.SevenZip, InArchiveFormat.SevenZip},
|
||||
{OutArchiveFormat.GZip, InArchiveFormat.GZip},
|
||||
{OutArchiveFormat.BZip2, InArchiveFormat.BZip2},
|
||||
{OutArchiveFormat.Tar, InArchiveFormat.Tar},
|
||||
{OutArchiveFormat.XZ, InArchiveFormat.XZ},
|
||||
{OutArchiveFormat.Zip, InArchiveFormat.Zip}
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// List of archive formats corresponding to specific extensions
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, InArchiveFormat> InExtensionFormats =
|
||||
new Dictionary<string, InArchiveFormat>
|
||||
#region InExtensionFormats initialization
|
||||
|
||||
{{"7z", InArchiveFormat.SevenZip},
|
||||
{"gz", InArchiveFormat.GZip},
|
||||
{"tar", InArchiveFormat.Tar},
|
||||
{"rar", InArchiveFormat.Rar},
|
||||
{"zip", InArchiveFormat.Zip},
|
||||
{"lzma", InArchiveFormat.Lzma},
|
||||
{"lzh", InArchiveFormat.Lzh},
|
||||
{"arj", InArchiveFormat.Arj},
|
||||
{"bz2", InArchiveFormat.BZip2},
|
||||
{"cab", InArchiveFormat.Cab},
|
||||
{"chm", InArchiveFormat.Chm},
|
||||
{"deb", InArchiveFormat.Deb},
|
||||
{"iso", InArchiveFormat.Iso},
|
||||
{"rpm", InArchiveFormat.Rpm},
|
||||
{"wim", InArchiveFormat.Wim},
|
||||
{"udf", InArchiveFormat.Udf},
|
||||
{"mub", InArchiveFormat.Mub},
|
||||
{"xar", InArchiveFormat.Xar},
|
||||
{"hfs", InArchiveFormat.Hfs},
|
||||
{"dmg", InArchiveFormat.Dmg},
|
||||
{"Z", InArchiveFormat.Lzw},
|
||||
{"xz", InArchiveFormat.XZ},
|
||||
{"flv", InArchiveFormat.Flv},
|
||||
{"swf", InArchiveFormat.Swf},
|
||||
{"exe", InArchiveFormat.PE},
|
||||
{"dll", InArchiveFormat.PE},
|
||||
{"vhd", InArchiveFormat.Vhd}
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// List of archive formats corresponding to specific signatures
|
||||
/// </summary>
|
||||
/// <remarks>Based on the information at <a href="http://www.garykessler.net/library/file_sigs.html">this site.</a></remarks>
|
||||
internal static readonly Dictionary<string, InArchiveFormat> InSignatureFormats =
|
||||
new Dictionary<string, InArchiveFormat>
|
||||
#region InSignatureFormats initialization
|
||||
|
||||
{{"37-7A-BC-AF-27-1C", InArchiveFormat.SevenZip},
|
||||
{"1F-8B-08", InArchiveFormat.GZip},
|
||||
{"75-73-74-61-72", InArchiveFormat.Tar},
|
||||
//257 byte offset
|
||||
{"52-61-72-21-1A-07-00", InArchiveFormat.Rar},
|
||||
{"50-4B-03-04", InArchiveFormat.Zip},
|
||||
{"5D-00-00-40-00", InArchiveFormat.Lzma},
|
||||
{"2D-6C-68", InArchiveFormat.Lzh},
|
||||
//^ 2 byte offset
|
||||
{"1F-9D-90", InArchiveFormat.Lzw},
|
||||
{"60-EA", InArchiveFormat.Arj},
|
||||
{"42-5A-68", InArchiveFormat.BZip2},
|
||||
//{"4D-53-43-46", InArchiveFormat.Cab},
|
||||
//{"49-54-53-46", InArchiveFormat.Chm},
|
||||
//{"21-3C-61-72-63-68-3E-0A-64-65-62-69-61-6E-2D-62-69-6E-61-72-79", InArchiveFormat.Deb},
|
||||
//{"43-44-30-30-31", InArchiveFormat.Iso},
|
||||
//^ 0x8001, 0x8801 or 0x9001 byte offset
|
||||
//{"ED-AB-EE-DB", InArchiveFormat.Rpm},
|
||||
//{"4D-53-57-49-4D-00-00-00", InArchiveFormat.Wim},
|
||||
//{"udf", InArchiveFormat.Udf},
|
||||
//{"mub", InArchiveFormat.Mub},
|
||||
//{"78-61-72-21", InArchiveFormat.Xar},
|
||||
//0x400 byte offset
|
||||
//{"48-2B", InArchiveFormat.Hfs},
|
||||
{"FD-37-7A-58-5A", InArchiveFormat.XZ},
|
||||
//{"46-4C-56", InArchiveFormat.Flv},
|
||||
//{"46-57-53", InArchiveFormat.Swf},
|
||||
//{"4D-5A", InArchiveFormat.PE},
|
||||
//{"7F-45-4C-46", InArchiveFormat.Elf},
|
||||
//{"78", InArchiveFormat.Dmg},
|
||||
//{"63-6F-6E-65-63-74-69-78", InArchiveFormat.Vhd},
|
||||
{"4E-45-53", InArchiveFormat.None}
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
internal static Dictionary<InArchiveFormat, string> InSignatureFormatsReversed;
|
||||
|
||||
static Formats()
|
||||
{
|
||||
InSignatureFormatsReversed = new Dictionary<InArchiveFormat, string>(InSignatureFormats.Count);
|
||||
foreach (var pair in InSignatureFormats)
|
||||
{
|
||||
InSignatureFormatsReversed.Add(pair.Value, pair.Key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets InArchiveFormat for specified archive file name
|
||||
/// </summary>
|
||||
/// <param name="fileName">Archive file name</param>
|
||||
/// <param name="reportErrors">Indicates whether to throw exceptions</param>
|
||||
/// <returns>InArchiveFormat recognized by the file name extension</returns>
|
||||
/// <exception cref="System.ArgumentException"/>
|
||||
public static InArchiveFormat FormatByFileName(string fileName, bool reportErrors)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileName) && reportErrors)
|
||||
{
|
||||
throw new ArgumentException("File name is null or empty string!");
|
||||
}
|
||||
string extension = Path.GetExtension(fileName);
|
||||
if (extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
if (!InExtensionFormats.ContainsKey(extension) && reportErrors)
|
||||
{
|
||||
if (FileChecker.ThrowExceptions)
|
||||
throw new ArgumentException("Extension \"" + extension + "\" is not a supported archive file name extension.");
|
||||
else return InArchiveFormat.None;
|
||||
|
||||
}
|
||||
return InExtensionFormats[extension];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The set of features supported by the library.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum LibraryFeature : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Default feature.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// The library can extract 7zip archives compressed with LZMA method.
|
||||
/// </summary>
|
||||
Extract7z = 0x1,
|
||||
/// <summary>
|
||||
/// The library can extract 7zip archives compressed with LZMA2 method.
|
||||
/// </summary>
|
||||
Extract7zLZMA2 = 0x2,
|
||||
/// <summary>
|
||||
/// The library can extract 7z archives compressed with all known methods.
|
||||
/// </summary>
|
||||
Extract7zAll = Extract7z|Extract7zLZMA2|0x4,
|
||||
/// <summary>
|
||||
/// The library can extract zip archives.
|
||||
/// </summary>
|
||||
ExtractZip = 0x8,
|
||||
/// <summary>
|
||||
/// The library can extract rar archives.
|
||||
/// </summary>
|
||||
ExtractRar = 0x10,
|
||||
/// <summary>
|
||||
/// The library can extract gzip archives.
|
||||
/// </summary>
|
||||
ExtractGzip = 0x20,
|
||||
/// <summary>
|
||||
/// The library can extract bzip2 archives.
|
||||
/// </summary>
|
||||
ExtractBzip2 = 0x40,
|
||||
/// <summary>
|
||||
/// The library can extract tar archives.
|
||||
/// </summary>
|
||||
ExtractTar = 0x80,
|
||||
/// <summary>
|
||||
/// The library can extract xz archives.
|
||||
/// </summary>
|
||||
ExtractXz = 0x100,
|
||||
/// <summary>
|
||||
/// The library can extract all types of archives supported.
|
||||
/// </summary>
|
||||
ExtractAll = Extract7zAll|ExtractZip|ExtractRar|ExtractGzip|ExtractBzip2|ExtractTar|ExtractXz,
|
||||
/// <summary>
|
||||
/// The library can compress data to 7zip archives with LZMA method.
|
||||
/// </summary>
|
||||
Compress7z = 0x200,
|
||||
/// <summary>
|
||||
/// The library can compress data to 7zip archives with LZMA2 method.
|
||||
/// </summary>
|
||||
Compress7zLZMA2 = 0x400,
|
||||
/// <summary>
|
||||
/// The library can compress data to 7zip archives with all methods known.
|
||||
/// </summary>
|
||||
Compress7zAll = Compress7z|Compress7zLZMA2|0x800,
|
||||
/// <summary>
|
||||
/// The library can compress data to tar archives.
|
||||
/// </summary>
|
||||
CompressTar = 0x1000,
|
||||
/// <summary>
|
||||
/// The library can compress data to gzip archives.
|
||||
/// </summary>
|
||||
CompressGzip = 0x2000,
|
||||
/// <summary>
|
||||
/// The library can compress data to bzip2 archives.
|
||||
/// </summary>
|
||||
CompressBzip2 = 0x4000,
|
||||
/// <summary>
|
||||
/// The library can compress data to xz archives.
|
||||
/// </summary>
|
||||
CompressXz = 0x8000,
|
||||
/// <summary>
|
||||
/// The library can compress data to zip archives.
|
||||
/// </summary>
|
||||
CompressZip = 0x10000,
|
||||
/// <summary>
|
||||
/// The library can compress data to all types of archives supported.
|
||||
/// </summary>
|
||||
CompressAll = Compress7zAll|CompressTar|CompressGzip|CompressBzip2|CompressXz|CompressZip,
|
||||
/// <summary>
|
||||
/// The library can modify archives.
|
||||
/// </summary>
|
||||
Modify = 0x20000
|
||||
}
|
||||
}
|
|
@ -0,0 +1,567 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if !WINCE && !MONO
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Permissions;
|
||||
#endif
|
||||
#if WINCE
|
||||
using OpenNETCF.Diagnostics;
|
||||
#endif
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
/// <summary>
|
||||
/// 7-zip library low-level wrapper.
|
||||
/// </summary>
|
||||
internal static class SevenZipLibraryManager
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
/// <summary>
|
||||
/// Path to the 7-zip dll.
|
||||
/// </summary>
|
||||
/// <remarks>7zxa.dll supports only decoding from .7z archives.
|
||||
/// Features of 7za.dll:
|
||||
/// - Supporting 7z format;
|
||||
/// - Built encoders: LZMA, PPMD, BCJ, BCJ2, COPY, AES-256 Encryption.
|
||||
/// - Built decoders: LZMA, PPMD, BCJ, BCJ2, COPY, AES-256 Encryption, BZip2, Deflate.
|
||||
/// 7z.dll (from the 7-zip distribution) supports every InArchiveFormat for encoding and decoding.
|
||||
/// </remarks>
|
||||
//private static string _libraryFileName = ConfigurationManager.AppSettings["7zLocation"] ?? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll");
|
||||
private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "7z.dll");
|
||||
#endif
|
||||
#if WINCE
|
||||
private static string _libraryFileName =
|
||||
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase), "7z.dll");
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 7-zip library handle.
|
||||
/// </summary>
|
||||
private static IntPtr _modulePtr;
|
||||
|
||||
/// <summary>
|
||||
/// 7-zip library features.
|
||||
/// </summary>
|
||||
private static LibraryFeature? _features;
|
||||
|
||||
private static Dictionary<object, Dictionary<InArchiveFormat, IInArchive>> _inArchives;
|
||||
#if COMPRESS
|
||||
private static Dictionary<object, Dictionary<OutArchiveFormat, IOutArchive>> _outArchives;
|
||||
#endif
|
||||
private static int _totalUsers;
|
||||
|
||||
// private static string _LibraryVersion;
|
||||
private static bool? _modifyCapabale;
|
||||
|
||||
private static void InitUserInFormat(object user, InArchiveFormat format)
|
||||
{
|
||||
if (!_inArchives.ContainsKey(user))
|
||||
{
|
||||
_inArchives.Add(user, new Dictionary<InArchiveFormat, IInArchive>());
|
||||
}
|
||||
if (!_inArchives[user].ContainsKey(format))
|
||||
{
|
||||
_inArchives[user].Add(format, null);
|
||||
_totalUsers++;
|
||||
}
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
private static void InitUserOutFormat(object user, OutArchiveFormat format)
|
||||
{
|
||||
if (!_outArchives.ContainsKey(user))
|
||||
{
|
||||
_outArchives.Add(user, new Dictionary<OutArchiveFormat, IOutArchive>());
|
||||
}
|
||||
if (!_outArchives[user].ContainsKey(format))
|
||||
{
|
||||
_outArchives[user].Add(format, null);
|
||||
_totalUsers++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
_inArchives = new Dictionary<object, Dictionary<InArchiveFormat, IInArchive>>();
|
||||
#if COMPRESS
|
||||
_outArchives = new Dictionary<object, Dictionary<OutArchiveFormat, IOutArchive>>();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the 7-zip library if necessary and adds user to the reference list
|
||||
/// </summary>
|
||||
/// <param name="user">Caller of the function</param>
|
||||
/// <param name="format">Archive format</param>
|
||||
public static void LoadLibrary(object user, Enum format)
|
||||
{
|
||||
if (_inArchives == null
|
||||
#if COMPRESS
|
||||
|| _outArchives == null
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
#if !WINCE && !MONO
|
||||
if (_modulePtr == IntPtr.Zero)
|
||||
{
|
||||
//zero 29-oct-2012 - this check isnt useful since LoadLibrary can pretty much check for the same thing. and it wrecks our dll relocation scheme
|
||||
//if (!File.Exists(_libraryFileName))
|
||||
//{
|
||||
// throw new SevenZipLibraryException("DLL file does not exist.");
|
||||
//}
|
||||
if ((_modulePtr = NativeMethods.LoadLibrary(_libraryFileName)) == IntPtr.Zero)
|
||||
{
|
||||
//try a different directory
|
||||
string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll");
|
||||
if ((_modulePtr = NativeMethods.LoadLibrary(alternateFilename)) == IntPtr.Zero)
|
||||
throw new SevenZipLibraryException("failed to load library.");
|
||||
}
|
||||
if (NativeMethods.GetProcAddress(_modulePtr, "GetHandlerProperty") == IntPtr.Zero)
|
||||
{
|
||||
NativeMethods.FreeLibrary(_modulePtr);
|
||||
throw new SevenZipLibraryException("library is invalid.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (format is InArchiveFormat)
|
||||
{
|
||||
InitUserInFormat(user, (InArchiveFormat) format);
|
||||
return;
|
||||
}
|
||||
#if COMPRESS
|
||||
if (format is OutArchiveFormat)
|
||||
{
|
||||
InitUserOutFormat(user, (OutArchiveFormat) format);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
throw new ArgumentException(
|
||||
"Enum " + format + " is not a valid archive format attribute!");
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Gets the native 7zip library version string.
|
||||
/// </summary>
|
||||
public static string LibraryVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(_LibraryVersion))
|
||||
{
|
||||
FileVersionInfo dllVersionInfo = FileVersionInfo.GetVersionInfo(_libraryFileName);
|
||||
_LibraryVersion = String.Format(
|
||||
System.Globalization.CultureInfo.CurrentCulture,
|
||||
"{0}.{1}",
|
||||
dllVersionInfo.FileMajorPart, dllVersionInfo.FileMinorPart);
|
||||
}
|
||||
return _LibraryVersion;
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whether the library supports modifying archives.
|
||||
/// </summary>
|
||||
public static bool ModifyCapable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_modifyCapabale.HasValue)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
FileVersionInfo dllVersionInfo = FileVersionInfo.GetVersionInfo(_libraryFileName);
|
||||
_modifyCapabale = dllVersionInfo.FileMajorPart >= 9;
|
||||
#else
|
||||
_modifyCapabale = true;
|
||||
#endif
|
||||
}
|
||||
return _modifyCapabale.Value;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly string Namespace = Assembly.GetExecutingAssembly().GetManifestResourceNames()[0].Split('.')[0];
|
||||
|
||||
private static string GetResourceString(string str)
|
||||
{
|
||||
return Namespace + ".arch." + str;
|
||||
}
|
||||
|
||||
private static bool ExtractionBenchmark(string archiveFileName, Stream outStream,
|
||||
ref LibraryFeature? features, LibraryFeature testedFeature)
|
||||
{
|
||||
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
||||
GetResourceString(archiveFileName));
|
||||
try
|
||||
{
|
||||
using (var extr = new SevenZipExtractor(stream))
|
||||
{
|
||||
extr.ExtractFile(0, outStream);
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
features |= testedFeature;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CompressionBenchmark(Stream inStream, Stream outStream,
|
||||
OutArchiveFormat format, CompressionMethod method,
|
||||
ref LibraryFeature? features, LibraryFeature testedFeature)
|
||||
{
|
||||
try
|
||||
{
|
||||
var compr = new SevenZipCompressor {ArchiveFormat = format, CompressionMethod = method};
|
||||
compr.CompressStream(inStream, outStream);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
features |= testedFeature;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static LibraryFeature CurrentLibraryFeatures
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_features != null && _features.HasValue)
|
||||
{
|
||||
return _features.Value;
|
||||
}
|
||||
_features = LibraryFeature.None;
|
||||
#region Benchmark
|
||||
#region Extraction features
|
||||
using (var outStream = new MemoryStream())
|
||||
{
|
||||
ExtractionBenchmark("Test.lzma.7z", outStream, ref _features, LibraryFeature.Extract7z);
|
||||
ExtractionBenchmark("Test.lzma2.7z", outStream, ref _features, LibraryFeature.Extract7zLZMA2);
|
||||
int i = 0;
|
||||
if (ExtractionBenchmark("Test.bzip2.7z", outStream, ref _features, _features.Value))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (ExtractionBenchmark("Test.ppmd.7z", outStream, ref _features, _features.Value))
|
||||
{
|
||||
i++;
|
||||
if (i == 2 && (_features & LibraryFeature.Extract7z) != 0 &&
|
||||
(_features & LibraryFeature.Extract7zLZMA2) != 0)
|
||||
{
|
||||
_features |= LibraryFeature.Extract7zAll;
|
||||
}
|
||||
}
|
||||
ExtractionBenchmark("Test.rar", outStream, ref _features, LibraryFeature.ExtractRar);
|
||||
ExtractionBenchmark("Test.tar", outStream, ref _features, LibraryFeature.ExtractTar);
|
||||
ExtractionBenchmark("Test.txt.bz2", outStream, ref _features, LibraryFeature.ExtractBzip2);
|
||||
ExtractionBenchmark("Test.txt.gz", outStream, ref _features, LibraryFeature.ExtractGzip);
|
||||
ExtractionBenchmark("Test.txt.xz", outStream, ref _features, LibraryFeature.ExtractXz);
|
||||
ExtractionBenchmark("Test.zip", outStream, ref _features, LibraryFeature.ExtractZip);
|
||||
}
|
||||
#endregion
|
||||
#region Compression features
|
||||
using (var inStream = new MemoryStream())
|
||||
{
|
||||
inStream.Write(Encoding.UTF8.GetBytes("Test"), 0, 4);
|
||||
using (var outStream = new MemoryStream())
|
||||
{
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.SevenZip, CompressionMethod.Lzma,
|
||||
ref _features, LibraryFeature.Compress7z);
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.SevenZip, CompressionMethod.Lzma2,
|
||||
ref _features, LibraryFeature.Compress7zLZMA2);
|
||||
int i = 0;
|
||||
if (CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.SevenZip, CompressionMethod.BZip2,
|
||||
ref _features, _features.Value))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.SevenZip, CompressionMethod.Ppmd,
|
||||
ref _features, _features.Value))
|
||||
{
|
||||
i++;
|
||||
if (i == 2 && (_features & LibraryFeature.Compress7z) != 0 &&
|
||||
(_features & LibraryFeature.Compress7zLZMA2) != 0)
|
||||
{
|
||||
_features |= LibraryFeature.Compress7zAll;
|
||||
}
|
||||
}
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.Zip, CompressionMethod.Default,
|
||||
ref _features, LibraryFeature.CompressZip);
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.BZip2, CompressionMethod.Default,
|
||||
ref _features, LibraryFeature.CompressBzip2);
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.GZip, CompressionMethod.Default,
|
||||
ref _features, LibraryFeature.CompressGzip);
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.Tar, CompressionMethod.Default,
|
||||
ref _features, LibraryFeature.CompressTar);
|
||||
CompressionBenchmark(inStream, outStream,
|
||||
OutArchiveFormat.XZ, CompressionMethod.Default,
|
||||
ref _features, LibraryFeature.CompressXz);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
if (ModifyCapable && (_features.Value & LibraryFeature.Compress7z) != 0)
|
||||
{
|
||||
_features |= LibraryFeature.Modify;
|
||||
}
|
||||
return _features.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes user from reference list and frees the 7-zip library if it becomes empty
|
||||
/// </summary>
|
||||
/// <param name="user">Caller of the function</param>
|
||||
/// <param name="format">Archive format</param>
|
||||
public static void FreeLibrary(object user, Enum format)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
|
||||
sp.Demand();
|
||||
#endif
|
||||
if (_modulePtr != IntPtr.Zero)
|
||||
{
|
||||
if (format is InArchiveFormat)
|
||||
{
|
||||
if (_inArchives != null && _inArchives.ContainsKey(user) &&
|
||||
_inArchives[user].ContainsKey((InArchiveFormat) format) &&
|
||||
_inArchives[user][(InArchiveFormat) format] != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Marshal.ReleaseComObject(_inArchives[user][(InArchiveFormat) format]);
|
||||
}
|
||||
catch (InvalidComObjectException) {}
|
||||
_inArchives[user].Remove((InArchiveFormat) format);
|
||||
_totalUsers--;
|
||||
if (_inArchives[user].Count == 0)
|
||||
{
|
||||
_inArchives.Remove(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if COMPRESS
|
||||
if (format is OutArchiveFormat)
|
||||
{
|
||||
if (_outArchives != null && _outArchives.ContainsKey(user) &&
|
||||
_outArchives[user].ContainsKey((OutArchiveFormat) format) &&
|
||||
_outArchives[user][(OutArchiveFormat) format] != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Marshal.ReleaseComObject(_outArchives[user][(OutArchiveFormat) format]);
|
||||
}
|
||||
catch (InvalidComObjectException) {}
|
||||
_outArchives[user].Remove((OutArchiveFormat) format);
|
||||
_totalUsers--;
|
||||
if (_outArchives[user].Count == 0)
|
||||
{
|
||||
_outArchives.Remove(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((_inArchives == null || _inArchives.Count == 0)
|
||||
#if COMPRESS
|
||||
&& (_outArchives == null || _outArchives.Count == 0)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
_inArchives = null;
|
||||
#if COMPRESS
|
||||
_outArchives = null;
|
||||
#endif
|
||||
if (_totalUsers == 0)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
NativeMethods.FreeLibrary(_modulePtr);
|
||||
|
||||
#endif
|
||||
_modulePtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets IInArchive interface to extract 7-zip archives.
|
||||
/// </summary>
|
||||
/// <param name="format">Archive format.</param>
|
||||
/// <param name="user">Archive format user.</param>
|
||||
public static IInArchive InArchive(InArchiveFormat format, object user)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
lock (_libraryFileName)
|
||||
{
|
||||
#endif
|
||||
if (_inArchives[user][format] == null)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
|
||||
sp.Demand();
|
||||
|
||||
if (_modulePtr == IntPtr.Zero)
|
||||
{
|
||||
LoadLibrary(user, format);
|
||||
if (_modulePtr == IntPtr.Zero)
|
||||
{
|
||||
throw new SevenZipLibraryException();
|
||||
}
|
||||
}
|
||||
var createObject = (NativeMethods.CreateObjectDelegate)
|
||||
Marshal.GetDelegateForFunctionPointer(
|
||||
NativeMethods.GetProcAddress(_modulePtr, "CreateObject"),
|
||||
typeof(NativeMethods.CreateObjectDelegate));
|
||||
if (createObject == null)
|
||||
{
|
||||
throw new SevenZipLibraryException();
|
||||
}
|
||||
#endif
|
||||
object result;
|
||||
Guid interfaceId =
|
||||
#if !WINCE && !MONO
|
||||
typeof(IInArchive).GUID;
|
||||
#else
|
||||
new Guid(((GuidAttribute)typeof(IInArchive).GetCustomAttributes(typeof(GuidAttribute), false)[0]).Value);
|
||||
#endif
|
||||
Guid classID = Formats.InFormatGuids[format];
|
||||
try
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
createObject(ref classID, ref interfaceId, out result);
|
||||
#elif !MONO
|
||||
NativeMethods.CreateCOMObject(ref classID, ref interfaceId, out result);
|
||||
#else
|
||||
result = SevenZip.Mono.Factory.CreateInterface<IInArchive>(user, classID, interfaceId);
|
||||
#endif
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new SevenZipLibraryException("Your 7-zip library does not support this archive type.");
|
||||
}
|
||||
InitUserInFormat(user, format);
|
||||
_inArchives[user][format] = result as IInArchive;
|
||||
}
|
||||
#if !WINCE && !MONO
|
||||
}
|
||||
#endif
|
||||
return _inArchives[user][format];
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// Gets IOutArchive interface to pack 7-zip archives.
|
||||
/// </summary>
|
||||
/// <param name="format">Archive format.</param>
|
||||
/// <param name="user">Archive format user.</param>
|
||||
public static IOutArchive OutArchive(OutArchiveFormat format, object user)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
lock (_libraryFileName)
|
||||
{
|
||||
#endif
|
||||
if (_outArchives[user][format] == null)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
|
||||
sp.Demand();
|
||||
if (_modulePtr == IntPtr.Zero)
|
||||
{
|
||||
throw new SevenZipLibraryException();
|
||||
}
|
||||
var createObject = (NativeMethods.CreateObjectDelegate)
|
||||
Marshal.GetDelegateForFunctionPointer(
|
||||
NativeMethods.GetProcAddress(_modulePtr, "CreateObject"),
|
||||
typeof(NativeMethods.CreateObjectDelegate));
|
||||
if (createObject == null)
|
||||
{
|
||||
throw new SevenZipLibraryException();
|
||||
}
|
||||
#endif
|
||||
object result;
|
||||
Guid interfaceId =
|
||||
#if !WINCE && !MONO
|
||||
typeof(IOutArchive).GUID;
|
||||
#else
|
||||
new Guid(((GuidAttribute)typeof(IOutArchive).GetCustomAttributes(typeof(GuidAttribute), false)[0]).Value);
|
||||
#endif
|
||||
Guid classID = Formats.OutFormatGuids[format];
|
||||
try
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
createObject(ref classID, ref interfaceId, out result);
|
||||
#elif !MONO
|
||||
NativeMethods.CreateCOMObject(ref classID, ref interfaceId, out result);
|
||||
#else
|
||||
result = SevenZip.Mono.Factory.CreateInterface<IOutArchive>(classID, interfaceId, user);
|
||||
#endif
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new SevenZipLibraryException("Your 7-zip library does not support this archive type.");
|
||||
}
|
||||
InitUserOutFormat(user, format);
|
||||
_outArchives[user][format] = result as IOutArchive;
|
||||
}
|
||||
#if !WINCE && !MONO
|
||||
}
|
||||
#endif
|
||||
return _outArchives[user][format];
|
||||
}
|
||||
#endif
|
||||
#if !WINCE && !MONO
|
||||
public static void SetLibraryPath(string libraryPath)
|
||||
{
|
||||
if (_modulePtr != IntPtr.Zero && !Path.GetFullPath(libraryPath).Equals(
|
||||
Path.GetFullPath(_libraryFileName), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new SevenZipLibraryException(
|
||||
"can not change the library path while the library \"" + _libraryFileName + "\" is being used.");
|
||||
}
|
||||
if (!File.Exists(libraryPath))
|
||||
{
|
||||
throw new SevenZipLibraryException(
|
||||
"can not change the library path because the file \"" + libraryPath + "\" does not exist.");
|
||||
}
|
||||
_libraryFileName = libraryPath;
|
||||
_features = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using SevenZip.Sdk.Compression.Lzma;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if LZMA_STREAM
|
||||
/// <summary>
|
||||
/// The stream which decompresses data with LZMA on the fly.
|
||||
/// </summary>
|
||||
public class LzmaDecodeStream : Stream
|
||||
{
|
||||
private readonly MemoryStream _buffer = new MemoryStream();
|
||||
private readonly Decoder _decoder = new Decoder();
|
||||
private readonly Stream _input;
|
||||
private byte[] _commonProperties;
|
||||
private bool _error;
|
||||
private bool _firstChunkRead;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaDecodeStream class.
|
||||
/// </summary>
|
||||
/// <param name="encodedStream">A compressed stream.</param>
|
||||
public LzmaDecodeStream(Stream encodedStream)
|
||||
{
|
||||
if (!encodedStream.CanRead)
|
||||
{
|
||||
throw new ArgumentException("The specified stream can not read.", "encodedStream");
|
||||
}
|
||||
_input = encodedStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk size.
|
||||
/// </summary>
|
||||
public int ChunkSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int) _buffer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the output stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_input.CanSeek)
|
||||
{
|
||||
return _input.Length;
|
||||
}
|
||||
return _buffer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the output stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_input.CanSeek)
|
||||
{
|
||||
return _input.Position;
|
||||
}
|
||||
return _buffer.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadChunk()
|
||||
{
|
||||
long size;
|
||||
byte[] properties;
|
||||
try
|
||||
{
|
||||
properties = SevenZipExtractor.GetLzmaProperties(_input, out size);
|
||||
}
|
||||
catch (LzmaException)
|
||||
{
|
||||
_error = true;
|
||||
return;
|
||||
}
|
||||
if (!_firstChunkRead)
|
||||
{
|
||||
_commonProperties = properties;
|
||||
}
|
||||
if (_commonProperties[0] != properties[0] ||
|
||||
_commonProperties[1] != properties[1] ||
|
||||
_commonProperties[2] != properties[2] ||
|
||||
_commonProperties[3] != properties[3] ||
|
||||
_commonProperties[4] != properties[4])
|
||||
{
|
||||
_error = true;
|
||||
return;
|
||||
}
|
||||
if (_buffer.Capacity < (int) size)
|
||||
{
|
||||
_buffer.Capacity = (int) size;
|
||||
}
|
||||
_buffer.SetLength(size);
|
||||
_decoder.SetDecoderProperties(properties);
|
||||
_buffer.Position = 0;
|
||||
_decoder.Code(
|
||||
_input, _buffer, 0, size, null);
|
||||
_buffer.Position = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does nothing.
|
||||
/// </summary>
|
||||
public override void Flush() {}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes from the current stream and decompresses data if necessary.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
/// <returns>The total number of bytes read into the buffer.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_firstChunkRead)
|
||||
{
|
||||
ReadChunk();
|
||||
_firstChunkRead = true;
|
||||
}
|
||||
int readCount = 0;
|
||||
while (count > _buffer.Length - _buffer.Position && !_error)
|
||||
{
|
||||
var buf = new byte[_buffer.Length - _buffer.Position];
|
||||
_buffer.Read(buf, 0, buf.Length);
|
||||
buf.CopyTo(buffer, offset);
|
||||
offset += buf.Length;
|
||||
count -= buf.Length;
|
||||
readCount += buf.Length;
|
||||
ReadChunk();
|
||||
}
|
||||
if (!_error)
|
||||
{
|
||||
_buffer.Read(buffer, offset, count);
|
||||
readCount += count;
|
||||
}
|
||||
return readCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream.
|
||||
/// </summary>
|
||||
/// <param name="offset">A byte offset relative to the origin parameter.</param>
|
||||
/// <param name="origin">A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position.</param>
|
||||
/// <returns>The new position within the current stream.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the current stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The desired length of the current stream in bytes.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the current stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using SevenZip.Sdk.Compression.Lzma;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if LZMA_STREAM
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// The stream which compresses data with LZMA on the fly.
|
||||
/// </summary>
|
||||
public class LzmaEncodeStream : Stream
|
||||
{
|
||||
private const int MAX_BUFFER_CAPACITY = 1 << 30; //1 Gb
|
||||
private readonly MemoryStream _buffer = new MemoryStream();
|
||||
private readonly int _bufferCapacity = 1 << 18; //256 kb
|
||||
private readonly bool _ownOutput;
|
||||
private bool _disposed;
|
||||
private Encoder _lzmaEncoder;
|
||||
private Stream _output;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaEncodeStream class.
|
||||
/// </summary>
|
||||
public LzmaEncodeStream()
|
||||
{
|
||||
_output = new MemoryStream();
|
||||
_ownOutput = true;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaEncodeStream class.
|
||||
/// </summary>
|
||||
/// <param name="bufferCapacity">The buffer size. The bigger size, the better compression.</param>
|
||||
public LzmaEncodeStream(int bufferCapacity)
|
||||
{
|
||||
_output = new MemoryStream();
|
||||
_ownOutput = true;
|
||||
if (bufferCapacity > MAX_BUFFER_CAPACITY)
|
||||
{
|
||||
throw new ArgumentException("Too large capacity.", "bufferCapacity");
|
||||
}
|
||||
_bufferCapacity = bufferCapacity;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaEncodeStream class.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">An output stream which supports writing.</param>
|
||||
public LzmaEncodeStream(Stream outputStream)
|
||||
{
|
||||
if (!outputStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("The specified stream can not write.", "outputStream");
|
||||
}
|
||||
_output = outputStream;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaEncodeStream class.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">An output stream which supports writing.</param>
|
||||
/// <param name="bufferCapacity">A buffer size. The bigger size, the better compression.</param>
|
||||
public LzmaEncodeStream(Stream outputStream, int bufferCapacity)
|
||||
{
|
||||
if (!outputStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("The specified stream can not write.", "outputStream");
|
||||
}
|
||||
_output = outputStream;
|
||||
if (bufferCapacity > 1 << 30)
|
||||
{
|
||||
throw new ArgumentException("Too large capacity.", "bufferCapacity");
|
||||
}
|
||||
_bufferCapacity = bufferCapacity;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
DisposedCheck();
|
||||
return _buffer.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the output stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
DisposedCheck();
|
||||
if (_output.CanSeek)
|
||||
{
|
||||
return _output.Length;
|
||||
}
|
||||
return _buffer.Position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the output stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
DisposedCheck();
|
||||
if (_output.CanSeek)
|
||||
{
|
||||
return _output.Position;
|
||||
}
|
||||
return _buffer.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
_buffer.Capacity = _bufferCapacity;
|
||||
SevenZipCompressor.LzmaDictionarySize = _bufferCapacity;
|
||||
_lzmaEncoder = new Encoder();
|
||||
SevenZipCompressor.WriteLzmaProperties(_lzmaEncoder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checked whether the class was disposed.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ObjectDisposedException" />
|
||||
private void DisposedCheck()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("SevenZipExtractor");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteChunk()
|
||||
{
|
||||
_lzmaEncoder.WriteCoderProperties(_output);
|
||||
long streamSize = _buffer.Position;
|
||||
if (_buffer.Length != _buffer.Position)
|
||||
{
|
||||
_buffer.SetLength(_buffer.Position);
|
||||
}
|
||||
_buffer.Position = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
_output.WriteByte((byte) (streamSize >> (8*i)));
|
||||
}
|
||||
_lzmaEncoder.Code(_buffer, _output, -1, -1, null);
|
||||
_buffer.Position = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the LzmaEncodeStream to the LzmaDecodeStream to read data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public LzmaDecodeStream ToDecodeStream()
|
||||
{
|
||||
DisposedCheck();
|
||||
Flush();
|
||||
return new LzmaDecodeStream(_output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all buffers for this stream and causes any buffered data to be compressed and written.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
DisposedCheck();
|
||||
WriteChunk();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all unmanaged resources used by LzmaEncodeStream.
|
||||
/// </summary>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Flush();
|
||||
_buffer.Close();
|
||||
if (_ownOutput)
|
||||
{
|
||||
_output.Dispose();
|
||||
}
|
||||
_output = null;
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
/// <returns>The total number of bytes read into the buffer.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
DisposedCheck();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream.
|
||||
/// </summary>
|
||||
/// <param name="offset">A byte offset relative to the origin parameter.</param>
|
||||
/// <param name="origin">A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position.</param>
|
||||
/// <returns>The new position within the current stream.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
DisposedCheck();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the current stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The desired length of the current stream in bytes.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
DisposedCheck();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the current stream and compresses it if necessary.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
DisposedCheck();
|
||||
int dataLength = Math.Min(buffer.Length - offset, count);
|
||||
while (_buffer.Position + dataLength >= _bufferCapacity)
|
||||
{
|
||||
int length = _bufferCapacity - (int) _buffer.Position;
|
||||
_buffer.Write(buffer, offset, length);
|
||||
offset = length + offset;
|
||||
dataLength -= length;
|
||||
WriteChunk();
|
||||
}
|
||||
_buffer.Write(buffer, offset, dataLength);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SevenZip.Sdk;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback to implement the ICodeProgress interface
|
||||
/// </summary>
|
||||
internal sealed class LzmaProgressCallback : ICodeProgress
|
||||
{
|
||||
private readonly long _inSize;
|
||||
private float _oldPercentDone;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LzmaProgressCallback class
|
||||
/// </summary>
|
||||
/// <param name="inSize">The input size</param>
|
||||
/// <param name="working">Progress event handler</param>
|
||||
public LzmaProgressCallback(long inSize, EventHandler<ProgressEventArgs> working)
|
||||
{
|
||||
_inSize = inSize;
|
||||
Working += working;
|
||||
}
|
||||
|
||||
#region ICodeProgress Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets the progress
|
||||
/// </summary>
|
||||
/// <param name="inSize">The processed input size</param>
|
||||
/// <param name="outSize">The processed output size</param>
|
||||
public void SetProgress(long inSize, long outSize)
|
||||
{
|
||||
if (Working != null)
|
||||
{
|
||||
float newPercentDone = (inSize + 0.0f) / _inSize;
|
||||
float delta = newPercentDone - _oldPercentDone;
|
||||
if (delta * 100 < 1.0)
|
||||
{
|
||||
delta = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_oldPercentDone = newPercentDone;
|
||||
}
|
||||
Working(this, new ProgressEventArgs(
|
||||
PercentDoneEventArgs.ProducePercentDone(newPercentDone),
|
||||
delta > 0 ? PercentDoneEventArgs.ProducePercentDone(delta) : (byte)0));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event EventHandler<ProgressEventArgs> Working;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
internal static class NativeMethods
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
#region Delegates
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate int CreateObjectDelegate(
|
||||
[In] ref Guid classID,
|
||||
[In] ref Guid interfaceID,
|
||||
[MarshalAs(UnmanagedType.Interface)] out object outObject);
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
|
||||
[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
#endif
|
||||
|
||||
#if WINCE
|
||||
[DllImport("7z.dll", EntryPoint="CreateObject")]
|
||||
public static extern int CreateCOMObject(
|
||||
[In] ref Guid classID,
|
||||
[In] ref Guid interfaceID,
|
||||
[MarshalAs(UnmanagedType.Interface)] out object outObject);
|
||||
#endif
|
||||
|
||||
public static T SafeCast<T>(PropVariant var, T def)
|
||||
{
|
||||
object obj;
|
||||
try
|
||||
{
|
||||
obj = var.Object;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
if (obj != null && obj is T)
|
||||
{
|
||||
return (T) obj;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,689 @@
|
|||
namespace SevenZip
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if DOTNET20
|
||||
using System.Threading;
|
||||
#else
|
||||
using System.Windows.Threading;
|
||||
#endif
|
||||
|
||||
partial class SevenZipCompressor
|
||||
{
|
||||
#region Delegates
|
||||
private delegate void CompressFiles1Delegate(string archiveName, string[] fileFullNames);
|
||||
private delegate void CompressFiles2Delegate(Stream archiveStream, string[] fileFullNames);
|
||||
private delegate void CompressFiles3Delegate(string archiveName, int commonRootLength, string[] fileFullNames);
|
||||
private delegate void CompressFiles4Delegate(Stream archiveStream, int commonRootLength, string[] fileFullNames);
|
||||
|
||||
private delegate void CompressFilesEncrypted1Delegate(string archiveName, string password, string[] fileFullNames);
|
||||
private delegate void CompressFilesEncrypted2Delegate(Stream archiveStream, string password, string[] fileFullNames);
|
||||
private delegate void CompressFilesEncrypted3Delegate(string archiveName, int commonRootLength, string password, string[] fileFullNames);
|
||||
private delegate void CompressFilesEncrypted4Delegate(Stream archiveStream, int commonRootLength, string password, string[] fileFullNames);
|
||||
|
||||
private delegate void CompressDirectory1Delegate(string directory, string archiveName);
|
||||
private delegate void CompressDirectory2Delegate(string directory, Stream archiveStream);
|
||||
private delegate void CompressDirectory3Delegate(string directory, string archiveName, string password);
|
||||
private delegate void CompressDirectory4Delegate(string directory, Stream archiveStream, string password);
|
||||
private delegate void CompressDirectory5Delegate(string directory, string archiveName,
|
||||
string password, string searchPattern, bool recursion);
|
||||
private delegate void CompressDirectory6Delegate(string directory, Stream archiveStream,
|
||||
string password, string searchPattern, bool recursion);
|
||||
|
||||
private delegate void CompressStream1Delegate(Stream inStream, Stream outStream);
|
||||
private delegate void CompressStream2Delegate(Stream inStream, Stream outStream, string password);
|
||||
|
||||
private delegate void ModifyArchive1Delegate(string archiveName, Dictionary<int, string> newFileNames);
|
||||
private delegate void ModifyArchive2Delegate(string archiveName, Dictionary<int, string> newFileNames,
|
||||
string password);
|
||||
#endregion
|
||||
|
||||
#region CompressFiles overloads
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
#endif
|
||||
public void BeginCompressFiles(
|
||||
string archiveName
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFiles1Delegate(CompressFiles)).BeginInvoke(archiveName, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles(string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles(string archiveName ... ) overloads for archiving to disk.</param>
|
||||
#endif
|
||||
public void BeginCompressFiles(
|
||||
Stream archiveStream
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFiles2Delegate(CompressFiles)).BeginInvoke(archiveStream, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
#endif
|
||||
public void BeginCompressFiles(
|
||||
string archiveName, int commonRootLength
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFiles3Delegate(CompressFiles)).BeginInvoke(archiveName, commonRootLength, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles(string archiveName, ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles(string archiveName, ... ) overloads for archiving to disk.</param>
|
||||
#endif
|
||||
public void BeginCompressFiles(
|
||||
Stream archiveStream, int commonRootLength
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFiles4Delegate(CompressFiles)).BeginInvoke(archiveStream, commonRootLength, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
#endif
|
||||
public void BeginCompressFilesEncrypted(
|
||||
string archiveName, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFilesEncrypted1Delegate(CompressFilesEncrypted)).BeginInvoke(archiveName, password, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
#endif
|
||||
public void BeginCompressFilesEncrypted(
|
||||
Stream archiveStream, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFilesEncrypted2Delegate(CompressFilesEncrypted)).BeginInvoke(archiveStream, password, fileFullNames,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveName">The archive file name</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
#endif
|
||||
public void BeginCompressFilesEncrypted(
|
||||
string archiveName, int commonRootLength, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFilesEncrypted3Delegate(CompressFilesEncrypted)).BeginInvoke(archiveName, commonRootLength, password,
|
||||
fileFullNames, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs files into the archive asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fileFullNames">Array of file names to pack.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="commonRootLength">The length of the common root of the file names.</param>
|
||||
#endif
|
||||
public void BeginCompressFilesEncrypted(
|
||||
Stream archiveStream, int commonRootLength, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
, params string[] fileFullNames
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressFilesEncrypted4Delegate(CompressFilesEncrypted)).BeginInvoke(archiveStream, commonRootLength, password,
|
||||
fileFullNames, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BeginCompressDirectory overloads
|
||||
|
||||
#if !CS4
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(
|
||||
string directory, string archiveName
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory1Delegate(CompressDirectory)).BeginInvoke(directory, archiveName,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(
|
||||
string directory, Stream archiveStream
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory2Delegate(CompressDirectory)).BeginInvoke(directory, archiveStream,
|
||||
AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(
|
||||
string directory, string archiveName, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory3Delegate(CompressDirectory)).BeginInvoke(directory, archiveName,
|
||||
password, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Recursively packs all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(
|
||||
string directory, Stream archiveStream, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory4Delegate(CompressDirectory)).BeginInvoke(directory, archiveStream,
|
||||
password, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs all files in the specified directory asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="searchPattern">Search string, such as "*.txt".</param>
|
||||
/// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs all files in the specified directory asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="searchPattern">Search string, such as "*.txt".</param>
|
||||
/// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(string directory, string archiveName,
|
||||
string password
|
||||
#if CS4
|
||||
= ""
|
||||
#endif
|
||||
, string searchPattern
|
||||
#if CS4
|
||||
= "*"
|
||||
#endif
|
||||
, bool recursion
|
||||
#if CS4
|
||||
= true
|
||||
#endif
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory5Delegate(CompressDirectory)).BeginInvoke(directory, archiveName,
|
||||
password, searchPattern, recursion, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Packs all files in the specified directory asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="searchPattern">Search string, such as "*.txt".</param>
|
||||
/// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Packs all files in the specified directory asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to compress.</param>
|
||||
/// <param name="archiveStream">The archive output stream.
|
||||
/// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="searchPattern">Search string, such as "*.txt".</param>
|
||||
/// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
|
||||
#endif
|
||||
public void BeginCompressDirectory(string directory, Stream archiveStream,
|
||||
string password
|
||||
#if CS4
|
||||
= ""
|
||||
#endif
|
||||
, string searchPattern
|
||||
#if CS4
|
||||
= "*"
|
||||
#endif
|
||||
, bool recursion
|
||||
#if CS4
|
||||
= true
|
||||
#endif
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressDirectory6Delegate(CompressDirectory)).BeginInvoke(directory, archiveStream,
|
||||
password, searchPattern, recursion, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BeginCompressStream overloads
|
||||
#if !CS4
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Compresses the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="inStream">The source uncompressed stream.</param>
|
||||
/// <param name="outStream">The destination compressed stream.</param>
|
||||
/// <exception cref="ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Compresses the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="inStream">The source uncompressed stream.</param>
|
||||
/// <param name="outStream">The destination compressed stream.</param>
|
||||
/// <exception cref="System.ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
|
||||
#endif
|
||||
public void BeginCompressStream(Stream inStream, Stream outStream
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressStream1Delegate(CompressStream)).BeginInvoke(inStream, outStream, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Compresses the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="inStream">The source uncompressed stream.</param>
|
||||
/// <param name="outStream">The destination compressed stream.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <exception cref="System.ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Compresses the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="inStream">The source uncompressed stream.</param>
|
||||
/// <param name="outStream">The destination compressed stream.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <exception cref="System.ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
|
||||
#endif
|
||||
public void BeginCompressStream(Stream inStream, Stream outStream, string password
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new CompressStream2Delegate(CompressStream)).BeginInvoke(inStream, outStream, password, AsyncCallbackImplementation, this);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BeginModifyArchive overloads
|
||||
#if !CS4
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Modifies the existing archive asynchronously (renames files or deletes them).
|
||||
/// </summary>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Modifies the existing archive asynchronously (renames files or deletes them).
|
||||
/// </summary>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
|
||||
#endif
|
||||
public void BeginModifyArchive(string archiveName, Dictionary<int, string> newFileNames
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ModifyArchive1Delegate(ModifyArchive)).BeginInvoke(archiveName, newFileNames, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Modifies the existing archive asynchronously (renames files or deletes them).
|
||||
/// </summary>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Modifies the existing archive asynchronously (renames files or deletes them).
|
||||
/// </summary>
|
||||
/// <param name="archiveName">The archive file name.</param>
|
||||
/// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
|
||||
/// <param name="password">The archive password.</param>
|
||||
#endif
|
||||
public void BeginModifyArchive(string archiveName, Dictionary<int, string> newFileNames,
|
||||
string password
|
||||
#if CS4
|
||||
= ""
|
||||
#endif
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ModifyArchive2Delegate(ModifyArchive)).BeginInvoke(archiveName, newFileNames, password, AsyncCallbackImplementation, this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,294 @@
|
|||
namespace SevenZip
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
#if DOTNET20
|
||||
using System.Threading;
|
||||
#else
|
||||
using System.Windows.Threading;
|
||||
#endif
|
||||
|
||||
partial class SevenZipExtractor
|
||||
{
|
||||
#region Asynchronous core methods
|
||||
|
||||
/// <summary>
|
||||
/// Recreates the instance of the SevenZipExtractor class.
|
||||
/// Used in asynchronous methods.
|
||||
/// </summary>
|
||||
private void RecreateInstanceIfNeeded()
|
||||
{
|
||||
if (NeedsToBeRecreated)
|
||||
{
|
||||
NeedsToBeRecreated = false;
|
||||
Stream backupStream = null;
|
||||
string backupFileName = null;
|
||||
if (String.IsNullOrEmpty(_fileName))
|
||||
{
|
||||
backupStream = _inStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
backupFileName = _fileName;
|
||||
}
|
||||
CommonDispose();
|
||||
if (backupStream == null)
|
||||
{
|
||||
Init(backupFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Init(backupStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void SaveContext(
|
||||
#if !DOTNET20
|
||||
DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
DisposedCheck();
|
||||
base.SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delegates
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractArchive.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory where the files are to be unpacked.</param>
|
||||
private delegate void ExtractArchiveDelegate(string directory);
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractFile (by file name).
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file full name in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
private delegate void ExtractFileByFileNameDelegate(string fileName, Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractFile (by index).
|
||||
/// </summary>
|
||||
/// <param name="index">Index in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
private delegate void ExtractFileByIndexDelegate(int index, Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractFiles(string directory, params int[] indexes).
|
||||
/// </summary>
|
||||
/// <param name="indexes">indexes of the files in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
private delegate void ExtractFiles1Delegate(string directory, int[] indexes);
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractFiles(string directory, params string[] fileNames).
|
||||
/// </summary>
|
||||
/// <param name="fileNames">Full file names in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
private delegate void ExtractFiles2Delegate(string directory, string[] fileNames);
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use in BeginExtractFiles(ExtractFileCallback extractFileCallback).
|
||||
/// </summary>
|
||||
/// <param name="extractFileCallback">The callback to call for each file in the archive.</param>
|
||||
private delegate void ExtractFiles3Delegate(ExtractFileCallback extractFileCallback);
|
||||
#endregion
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Unpacks the whole archive asynchronously to the specified directory name at the specified priority.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory where the files are to be unpacked.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Unpacks the whole archive asynchronously to the specified directory name at the specified priority.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory where the files are to be unpacked.</param>
|
||||
#endif
|
||||
public void BeginExtractArchive(string directory
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractArchiveDelegate(ExtractArchive)).BeginInvoke(directory, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Unpacks the file asynchronously by its name to the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file full name in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Unpacks the file asynchronously by its name to the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file full name in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
#endif
|
||||
public void BeginExtractFile(string fileName, Stream stream
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractFileByFileNameDelegate(ExtractFile)).BeginInvoke(fileName, stream, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Unpacks the file asynchronously by its index to the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="index">Index in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Unpacks the file asynchronously by its index to the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="index">Index in the archive file table.</param>
|
||||
/// <param name="stream">The stream where the file is to be unpacked.</param>
|
||||
#endif
|
||||
public void BeginExtractFile(int index, Stream stream
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractFileByIndexDelegate(ExtractFile)).BeginInvoke(index, stream, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Unpacks files asynchronously by their indices to the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="indexes">indexes of the files in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Unpacks files asynchronously by their indices to the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="indexes">indexes of the files in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
#endif
|
||||
public void BeginExtractFiles(string directory
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
, params int[] indexes)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractFiles1Delegate(ExtractFiles)).BeginInvoke(directory, indexes, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Unpacks files asynchronously by their full names to the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="fileNames">Full file names in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Unpacks files asynchronously by their full names to the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="fileNames">Full file names in the archive file table.</param>
|
||||
/// <param name="directory">Directory where the files are to be unpacked.</param>
|
||||
#endif
|
||||
public void BeginExtractFiles(string directory
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
, params string[] fileNames)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractFiles2Delegate(ExtractFiles)).BeginInvoke(directory, fileNames, AsyncCallbackImplementation, this);
|
||||
}
|
||||
|
||||
#if !DOTNET20
|
||||
/// <summary>
|
||||
/// Extracts files from the archive asynchronously, giving a callback the choice what
|
||||
/// to do with each file. The order of the files is given by the archive.
|
||||
/// 7-Zip (and any other solid) archives are NOT supported.
|
||||
/// </summary>
|
||||
/// <param name="extractFileCallback">The callback to call for each file in the archive.</param>
|
||||
/// <param name="eventPriority">The priority of events, relative to the other pending operations in the System.Windows.Threading.Dispatcher event queue, the specified method is invoked.</param>
|
||||
#else
|
||||
/// <summary>
|
||||
/// Extracts files from the archive asynchronously, giving a callback the choice what
|
||||
/// to do with each file. The order of the files is given by the archive.
|
||||
/// 7-Zip (and any other solid) archives are NOT supported.
|
||||
/// </summary>
|
||||
/// <param name="extractFileCallback">The callback to call for each file in the archive.</param>
|
||||
#endif
|
||||
public void BeginExtractFiles(ExtractFileCallback extractFileCallback
|
||||
#if !DOTNET20
|
||||
, DispatcherPriority eventPriority
|
||||
#if CS4
|
||||
= DispatcherPriority.Normal
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SaveContext(
|
||||
#if !DOTNET20
|
||||
eventPriority
|
||||
#endif
|
||||
);
|
||||
(new ExtractFiles3Delegate(ExtractFiles)).BeginInvoke(extractFileCallback, AsyncCallbackImplementation, this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,499 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if SFX
|
||||
using SfxSettings = Dictionary<string, string>;
|
||||
|
||||
/// <summary>
|
||||
/// Sfx module choice enumeration
|
||||
/// </summary>
|
||||
public enum SfxModule
|
||||
{
|
||||
/// <summary>
|
||||
/// Default module (leave this if unsure)
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// The simple sfx module by Igor Pavlov with no adjustable parameters
|
||||
/// </summary>
|
||||
Simple,
|
||||
/// <summary>
|
||||
/// The installer sfx module by Igor Pavlov
|
||||
/// </summary>
|
||||
Installer,
|
||||
/// <summary>
|
||||
/// The extended installer sfx module by Oleg Scherbakov
|
||||
/// </summary>
|
||||
Extended,
|
||||
/// <summary>
|
||||
/// The custom sfx module. First you must specify the module file name.
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The class for making 7-zip based self-extracting archives.
|
||||
/// </summary>
|
||||
public class SevenZipSfx
|
||||
{
|
||||
private static readonly Dictionary<SfxModule, List<string>> SfxSupportedModuleNames =
|
||||
new Dictionary<SfxModule, List<string>>(3)
|
||||
{
|
||||
{SfxModule.Default, new List<string>(1) {"7zxSD_All.sfx"}},
|
||||
{SfxModule.Simple, new List<string>(2) {"7z.sfx", "7zCon.sfx"}},
|
||||
{SfxModule.Installer, new List<string>(2) {"7zS.sfx", "7zSD.sfx"}},
|
||||
{
|
||||
SfxModule.Extended,
|
||||
new List<string>(4) {"7zxSD_All.sfx", "7zxSD_Deflate", "7zxSD_LZMA", "7zxSD_PPMd"}
|
||||
}
|
||||
};
|
||||
|
||||
private SfxModule _module = SfxModule.Default;
|
||||
private string _moduleFileName;
|
||||
private Dictionary<SfxModule, List<string>> _sfxCommands;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfx class.
|
||||
/// </summary>
|
||||
public SevenZipSfx()
|
||||
{
|
||||
_module = SfxModule.Default;
|
||||
CommonInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfx class.
|
||||
/// </summary>
|
||||
/// <param name="module">The sfx module to use as a front-end.</param>
|
||||
public SevenZipSfx(SfxModule module)
|
||||
{
|
||||
if (module == SfxModule.Custom)
|
||||
{
|
||||
throw new ArgumentException("You must specify the custom module executable.", "module");
|
||||
}
|
||||
_module = module;
|
||||
CommonInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SevenZipSfx class.
|
||||
/// </summary>
|
||||
/// <param name="moduleFileName"></param>
|
||||
public SevenZipSfx(string moduleFileName)
|
||||
{
|
||||
_module = SfxModule.Custom;
|
||||
ModuleFileName = moduleFileName;
|
||||
CommonInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sfx module type.
|
||||
/// </summary>
|
||||
public SfxModule SfxModule
|
||||
{
|
||||
get
|
||||
{
|
||||
return _module;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom sfx module file name
|
||||
/// </summary>
|
||||
public string ModuleFileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _moduleFileName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!File.Exists(value))
|
||||
{
|
||||
throw new ArgumentException("The specified file does not exist.");
|
||||
}
|
||||
_moduleFileName = value;
|
||||
_module = SfxModule.Custom;
|
||||
string sfxName = Path.GetFileName(value);
|
||||
foreach (SfxModule mod in SfxSupportedModuleNames.Keys)
|
||||
{
|
||||
if (SfxSupportedModuleNames[mod].Contains(sfxName))
|
||||
{
|
||||
_module = mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CommonInit()
|
||||
{
|
||||
LoadCommandsFromResource("Configs");
|
||||
}
|
||||
|
||||
private static string GetResourceString(string str)
|
||||
{
|
||||
#if !WINCE
|
||||
return "SevenZip.sfx." + str;
|
||||
#else
|
||||
return "SevenZipSharpMobile.sfx." + str;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sfx module enum by the list of supported modules
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private static SfxModule GetModuleByName(string name)
|
||||
{
|
||||
if (name.IndexOf("7z.sfx", StringComparison.Ordinal) > -1)
|
||||
{
|
||||
return SfxModule.Simple;
|
||||
}
|
||||
if (name.IndexOf("7zS.sfx", StringComparison.Ordinal) > -1)
|
||||
{
|
||||
return SfxModule.Installer;
|
||||
}
|
||||
if (name.IndexOf("7zxSD_All.sfx", StringComparison.Ordinal) > -1)
|
||||
{
|
||||
return SfxModule.Extended;
|
||||
}
|
||||
throw new SevenZipSfxValidationException("The specified configuration is unsupported.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the commands for each supported sfx module configuration
|
||||
/// </summary>
|
||||
/// <param name="xmlDefinitions">The resource name for xml definitions</param>
|
||||
private void LoadCommandsFromResource(string xmlDefinitions)
|
||||
{
|
||||
using (Stream cfg = Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
||||
GetResourceString(xmlDefinitions + ".xml")))
|
||||
{
|
||||
if (cfg == null)
|
||||
{
|
||||
throw new SevenZipSfxValidationException("The configuration \"" + xmlDefinitions +
|
||||
"\" does not exist.");
|
||||
}
|
||||
using (Stream schm = Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
||||
GetResourceString(xmlDefinitions + ".xsd")))
|
||||
{
|
||||
if (schm == null)
|
||||
{
|
||||
throw new SevenZipSfxValidationException("The configuration schema \"" + xmlDefinitions +
|
||||
"\" does not exist.");
|
||||
}
|
||||
var sc = new XmlSchemaSet();
|
||||
using (XmlReader scr = XmlReader.Create(schm))
|
||||
{
|
||||
sc.Add(null, scr);
|
||||
var settings = new XmlReaderSettings {ValidationType = ValidationType.Schema, Schemas = sc};
|
||||
string validationErrors = "";
|
||||
settings.ValidationEventHandler +=
|
||||
((s, t) =>
|
||||
{
|
||||
validationErrors += String.Format(CultureInfo.InvariantCulture, "[{0}]: {1}\n",
|
||||
t.Severity.ToString(), t.Message);
|
||||
});
|
||||
using (XmlReader rdr = XmlReader.Create(cfg, settings))
|
||||
{
|
||||
_sfxCommands = new Dictionary<SfxModule, List<string>>();
|
||||
rdr.Read();
|
||||
rdr.Read();
|
||||
rdr.Read();
|
||||
rdr.Read();
|
||||
rdr.Read();
|
||||
rdr.ReadStartElement("sfxConfigs");
|
||||
rdr.Read();
|
||||
do
|
||||
{
|
||||
SfxModule mod = GetModuleByName(rdr["modules"]);
|
||||
rdr.ReadStartElement("config");
|
||||
rdr.Read();
|
||||
if (rdr.Name == "id")
|
||||
{
|
||||
var cmds = new List<string>();
|
||||
_sfxCommands.Add(mod, cmds);
|
||||
do
|
||||
{
|
||||
cmds.Add(rdr["command"]);
|
||||
rdr.Read();
|
||||
rdr.Read();
|
||||
} while (rdr.Name == "id");
|
||||
rdr.ReadEndElement();
|
||||
rdr.Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
_sfxCommands.Add(mod, null);
|
||||
}
|
||||
} while (rdr.Name == "config");
|
||||
}
|
||||
if (!String.IsNullOrEmpty(validationErrors))
|
||||
{
|
||||
throw new SevenZipSfxValidationException(
|
||||
"\n" + validationErrors.Substring(0, validationErrors.Length - 1));
|
||||
}
|
||||
_sfxCommands.Add(SfxModule.Default, _sfxCommands[SfxModule.Extended]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the sfx scenario commands.
|
||||
/// </summary>
|
||||
/// <param name="settings">The sfx settings dictionary to validate.</param>
|
||||
private void ValidateSettings(SfxSettings settings)
|
||||
{
|
||||
if (_module == SfxModule.Custom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<string> commands = _sfxCommands[_module];
|
||||
if (commands == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var invalidCommands = new List<string>();
|
||||
foreach (string command in settings.Keys)
|
||||
{
|
||||
if (!commands.Contains(command))
|
||||
{
|
||||
invalidCommands.Add(command);
|
||||
}
|
||||
}
|
||||
if (invalidCommands.Count > 0)
|
||||
{
|
||||
var invalidText = new StringBuilder("\nInvalid commands:\n");
|
||||
foreach (string str in invalidCommands)
|
||||
{
|
||||
invalidText.Append(str);
|
||||
}
|
||||
throw new SevenZipSfxValidationException(invalidText.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream containing the sfx settings.
|
||||
/// </summary>
|
||||
/// <param name="settings">The sfx settings dictionary.</param>
|
||||
/// <returns></returns>
|
||||
private static Stream GetSettingsStream(SfxSettings settings)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
byte[] buf = Encoding.UTF8.GetBytes(@";!@Install@!UTF-8!" + '\n');
|
||||
ms.Write(buf, 0, buf.Length);
|
||||
foreach (string command in settings.Keys)
|
||||
{
|
||||
buf =
|
||||
Encoding.UTF8.GetBytes(String.Format(CultureInfo.InvariantCulture, "{0}=\"{1}\"\n", command,
|
||||
settings[command]));
|
||||
ms.Write(buf, 0, buf.Length);
|
||||
}
|
||||
buf = Encoding.UTF8.GetBytes(@";!@InstallEnd@!");
|
||||
ms.Write(buf, 0, buf.Length);
|
||||
return ms;
|
||||
}
|
||||
|
||||
private SfxSettings GetDefaultSettings()
|
||||
{
|
||||
switch (_module)
|
||||
{
|
||||
default:
|
||||
return null;
|
||||
case SfxModule.Installer:
|
||||
var settings = new Dictionary<string, string> {{"Title", "7-Zip self-extracting archive"}};
|
||||
return settings;
|
||||
case SfxModule.Default:
|
||||
case SfxModule.Extended:
|
||||
settings = new Dictionary<string, string>
|
||||
{
|
||||
{"GUIMode", "0"},
|
||||
{"InstallPath", "."},
|
||||
{"GUIFlags", "128+8"},
|
||||
{"ExtractPathTitle", "7-Zip self-extracting archive"},
|
||||
{"ExtractPathText", "Specify the path where to extract the files:"}
|
||||
};
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the whole to the other one.
|
||||
/// </summary>
|
||||
/// <param name="src">The source stream to read from.</param>
|
||||
/// <param name="dest">The destination stream to wrie to.</param>
|
||||
private static void WriteStream(Stream src, Stream dest)
|
||||
{
|
||||
src.Seek(0, SeekOrigin.Begin);
|
||||
var buf = new byte[32768];
|
||||
int bytesRead;
|
||||
while ((bytesRead = src.Read(buf, 0, buf.Length)) > 0)
|
||||
{
|
||||
dest.Write(buf, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive stream.</param>
|
||||
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
||||
public void MakeSfx(Stream archive, string sfxFileName)
|
||||
{
|
||||
using (Stream sfxStream = File.Create(sfxFileName))
|
||||
{
|
||||
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive stream.</param>
|
||||
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
||||
public void MakeSfx(Stream archive, Stream sfxStream)
|
||||
{
|
||||
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive stream.</param>
|
||||
/// <param name="settings">The sfx settings.</param>
|
||||
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
||||
public void MakeSfx(Stream archive, SfxSettings settings, string sfxFileName)
|
||||
{
|
||||
using (Stream sfxStream = File.Create(sfxFileName))
|
||||
{
|
||||
MakeSfx(archive, settings, sfxStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive stream.</param>
|
||||
/// <param name="settings">The sfx settings.</param>
|
||||
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
||||
public void MakeSfx(Stream archive, SfxSettings settings, Stream sfxStream)
|
||||
{
|
||||
if (!sfxStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("The specified output stream can not write.", "sfxStream");
|
||||
}
|
||||
ValidateSettings(settings);
|
||||
using (Stream sfx = _module == SfxModule.Default
|
||||
? Assembly.GetExecutingAssembly().GetManifestResourceStream(
|
||||
GetResourceString(SfxSupportedModuleNames[_module][0]))
|
||||
: new FileStream(_moduleFileName, FileMode.Open, FileAccess.Read,
|
||||
FileShare.ReadWrite))
|
||||
{
|
||||
WriteStream(sfx, sfxStream);
|
||||
}
|
||||
if (_module == SfxModule.Custom || _sfxCommands[_module] != null)
|
||||
{
|
||||
using (Stream set = GetSettingsStream(settings))
|
||||
{
|
||||
WriteStream(set, sfxStream);
|
||||
}
|
||||
}
|
||||
WriteStream(archive, sfxStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archiveFileName">The archive file name.</param>
|
||||
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
||||
public void MakeSfx(string archiveFileName, string sfxFileName)
|
||||
{
|
||||
using (Stream sfxStream = File.Create(sfxFileName))
|
||||
{
|
||||
using (
|
||||
Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||
)
|
||||
{
|
||||
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archiveFileName">The archive file name.</param>
|
||||
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
||||
public void MakeSfx(string archiveFileName, Stream sfxStream)
|
||||
{
|
||||
using (Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||
)
|
||||
{
|
||||
MakeSfx(archive, GetDefaultSettings(), sfxStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archiveFileName">The archive file name.</param>
|
||||
/// <param name="settings">The sfx settings.</param>
|
||||
/// <param name="sfxFileName">The name of the self-extracting executable.</param>
|
||||
public void MakeSfx(string archiveFileName, SfxSettings settings, string sfxFileName)
|
||||
{
|
||||
using (Stream sfxStream = File.Create(sfxFileName))
|
||||
{
|
||||
using (
|
||||
Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||
)
|
||||
{
|
||||
MakeSfx(archive, settings, sfxStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the self-extracting archive.
|
||||
/// </summary>
|
||||
/// <param name="archiveFileName">The archive file name.</param>
|
||||
/// <param name="settings">The sfx settings.</param>
|
||||
/// <param name="sfxStream">The stream to write the self-extracting executable to.</param>
|
||||
public void MakeSfx(string archiveFileName, SfxSettings settings, Stream sfxStream)
|
||||
{
|
||||
using (Stream archive = new FileStream(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||
)
|
||||
{
|
||||
MakeSfx(archive, settings, sfxStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,545 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if MONO
|
||||
using SevenZip.Mono.COM;
|
||||
#endif
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
#if UNMANAGED
|
||||
|
||||
/// <summary>
|
||||
/// A class that has DisposeStream property.
|
||||
/// </summary>
|
||||
internal class DisposeVariableWrapper
|
||||
{
|
||||
public bool DisposeStream { protected get; set; }
|
||||
|
||||
protected DisposeVariableWrapper(bool disposeStream) { DisposeStream = disposeStream; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stream wrapper used in InStreamWrapper
|
||||
/// </summary>
|
||||
internal class StreamWrapper : DisposeVariableWrapper, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// File name associated with the stream (for date fix)
|
||||
/// </summary>
|
||||
private readonly string _fileName;
|
||||
|
||||
private readonly DateTime _fileTime;
|
||||
|
||||
/// <summary>
|
||||
/// Worker stream for reading, writing and seeking.
|
||||
/// </summary>
|
||||
private Stream _baseStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWrapper class
|
||||
/// </summary>
|
||||
/// <param name="baseStream">Worker stream for reading, writing and seeking</param>
|
||||
/// <param name="fileName">File name associated with the stream (for attributes fix)</param>
|
||||
/// <param name="time">File last write time (for attributes fix)</param>
|
||||
/// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
|
||||
protected StreamWrapper(Stream baseStream, string fileName, DateTime time, bool disposeStream)
|
||||
: base(disposeStream)
|
||||
{
|
||||
_baseStream = baseStream;
|
||||
_fileName = fileName;
|
||||
_fileTime = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWrapper class
|
||||
/// </summary>
|
||||
/// <param name="baseStream">Worker stream for reading, writing and seeking</param>
|
||||
/// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
|
||||
protected StreamWrapper(Stream baseStream, bool disposeStream)
|
||||
: base(disposeStream)
|
||||
{
|
||||
_baseStream = baseStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the worker stream for reading, writing and seeking.
|
||||
/// </summary>
|
||||
protected Stream BaseStream
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream;
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up any resources used and fixes file attributes.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_baseStream != null && DisposeStream)
|
||||
{
|
||||
try
|
||||
{
|
||||
_baseStream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
_baseStream = null;
|
||||
}
|
||||
if (!String.IsNullOrEmpty(_fileName) && File.Exists(_fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
#if !WINCE
|
||||
|
||||
File.SetLastWriteTime(_fileName, _fileTime);
|
||||
File.SetLastAccessTime(_fileName, _fileTime);
|
||||
File.SetCreationTime(_fileName, _fileTime);
|
||||
#elif WINCE
|
||||
OpenNETCF.IO.FileHelper.SetLastWriteTime(_fileName, _fileTime);
|
||||
OpenNETCF.IO.FileHelper.SetLastAccessTime(_fileName, _fileTime);
|
||||
OpenNETCF.IO.FileHelper.SetCreationTime(_fileName, _fileTime);
|
||||
#endif
|
||||
//TODO: time support for Windows Phone
|
||||
}
|
||||
catch (ArgumentOutOfRangeException) {}
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual void Seek(long offset, SeekOrigin seekOrigin, IntPtr newPosition)
|
||||
{
|
||||
if (BaseStream != null)
|
||||
{
|
||||
long position = BaseStream.Seek(offset, seekOrigin);
|
||||
if (newPosition != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt64(newPosition, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IInStream wrapper used in stream read operations.
|
||||
/// </summary>
|
||||
internal sealed class InStreamWrapper : StreamWrapper, ISequentialInStream, IInStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the InStreamWrapper class.
|
||||
/// </summary>
|
||||
/// <param name="baseStream">Stream for writing data</param>
|
||||
/// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
|
||||
public InStreamWrapper(Stream baseStream, bool disposeStream) : base(baseStream, disposeStream) { }
|
||||
|
||||
#region ISequentialInStream Members
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the stream.
|
||||
/// </summary>
|
||||
/// <param name="data">A data array.</param>
|
||||
/// <param name="size">The array size.</param>
|
||||
/// <returns>The read bytes count.</returns>
|
||||
public int Read(byte[] data, uint size)
|
||||
{
|
||||
int readCount = 0;
|
||||
if (BaseStream != null)
|
||||
{
|
||||
readCount = BaseStream.Read(data, 0, (int) size);
|
||||
if (readCount > 0)
|
||||
{
|
||||
OnBytesRead(new IntEventArgs(readCount));
|
||||
}
|
||||
}
|
||||
return readCount;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when IntEventArgs.Value bytes were read from the source.
|
||||
/// </summary>
|
||||
public event EventHandler<IntEventArgs> BytesRead;
|
||||
|
||||
private void OnBytesRead(IntEventArgs e)
|
||||
{
|
||||
if (BytesRead != null)
|
||||
{
|
||||
BytesRead(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IOutStream wrapper used in stream write operations.
|
||||
/// </summary>
|
||||
internal sealed class OutStreamWrapper : StreamWrapper, ISequentialOutStream, IOutStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the OutStreamWrapper class
|
||||
/// </summary>
|
||||
/// <param name="baseStream">Stream for writing data</param>
|
||||
/// <param name="fileName">File name (for attributes fix)</param>
|
||||
/// <param name="time">Time of the file creation (for attributes fix)</param>
|
||||
/// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
|
||||
public OutStreamWrapper(Stream baseStream, string fileName, DateTime time, bool disposeStream) :
|
||||
base(baseStream, fileName, time, disposeStream) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the OutStreamWrapper class
|
||||
/// </summary>
|
||||
/// <param name="baseStream">Stream for writing data</param>
|
||||
/// <param name="disposeStream">Indicates whether to dispose the baseStream</param>
|
||||
public OutStreamWrapper(Stream baseStream, bool disposeStream) :
|
||||
base(baseStream, disposeStream) {}
|
||||
|
||||
#region IOutStream Members
|
||||
|
||||
public int SetSize(long newSize)
|
||||
{
|
||||
BaseStream.SetLength(newSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISequentialOutStream Members
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the stream
|
||||
/// </summary>
|
||||
/// <param name="data">Data array</param>
|
||||
/// <param name="size">Array size</param>
|
||||
/// <param name="processedSize">Count of written bytes</param>
|
||||
/// <returns>Zero if Ok</returns>
|
||||
public int Write(byte[] data, uint size, IntPtr processedSize)
|
||||
{
|
||||
BaseStream.Write(data, 0, (int) size);
|
||||
if (processedSize != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt32(processedSize, (int) size);
|
||||
}
|
||||
OnBytesWritten(new IntEventArgs((int) size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when IntEventArgs.Value bytes were written.
|
||||
/// </summary>
|
||||
public event EventHandler<IntEventArgs> BytesWritten;
|
||||
|
||||
private void OnBytesWritten(IntEventArgs e)
|
||||
{
|
||||
if (BytesWritten != null)
|
||||
{
|
||||
BytesWritten(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base multi volume stream wrapper class.
|
||||
/// </summary>
|
||||
internal class MultiStreamWrapper : DisposeVariableWrapper, IDisposable
|
||||
{
|
||||
protected readonly Dictionary<int, KeyValuePair<long, long>> StreamOffsets =
|
||||
new Dictionary<int, KeyValuePair<long, long>>();
|
||||
|
||||
protected readonly List<Stream> Streams = new List<Stream>();
|
||||
protected int CurrentStream;
|
||||
protected long Position;
|
||||
protected long StreamLength;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MultiStreamWrapper class.
|
||||
/// </summary>
|
||||
/// <param name="dispose">Perform Dispose() if requested to.</param>
|
||||
protected MultiStreamWrapper(bool dispose) : base(dispose) {}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total length of input data.
|
||||
/// </summary>
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return StreamLength;
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up any resources used and fixes file attributes.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (DisposeStream)
|
||||
{
|
||||
foreach (Stream stream in Streams)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException) {}
|
||||
}
|
||||
Streams.Clear();
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected static string VolumeNumber(int num)
|
||||
{
|
||||
if (num < 10)
|
||||
{
|
||||
return ".00" + num.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (num > 9 && num < 100)
|
||||
{
|
||||
return ".0" + num.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (num > 99 && num < 1000)
|
||||
{
|
||||
return "." + num.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
private int StreamNumberByOffset(long offset)
|
||||
{
|
||||
foreach (int number in StreamOffsets.Keys)
|
||||
{
|
||||
if (StreamOffsets[number].Key <= offset &&
|
||||
StreamOffsets[number].Value >= offset)
|
||||
{
|
||||
return number;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Seek(long offset, SeekOrigin seekOrigin, IntPtr newPosition)
|
||||
{
|
||||
long absolutePosition = (seekOrigin == SeekOrigin.Current)
|
||||
? Position + offset
|
||||
: offset;
|
||||
CurrentStream = StreamNumberByOffset(absolutePosition);
|
||||
long delta = Streams[CurrentStream].Seek(
|
||||
absolutePosition - StreamOffsets[CurrentStream].Key, SeekOrigin.Begin);
|
||||
Position = StreamOffsets[CurrentStream].Key + delta;
|
||||
if (newPosition != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt64(newPosition, Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IInStream wrapper used in stream multi volume read operations.
|
||||
/// </summary>
|
||||
internal sealed class InMultiStreamWrapper : MultiStreamWrapper, ISequentialInStream, IInStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the InMultiStreamWrapper class.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The archive file name.</param>
|
||||
/// <param name="dispose">Perform Dispose() if requested to.</param>
|
||||
public InMultiStreamWrapper(string fileName, bool dispose) :
|
||||
base(dispose)
|
||||
{
|
||||
string baseName = fileName.Substring(0, fileName.Length - 4);
|
||||
int i = 0;
|
||||
while (File.Exists(fileName))
|
||||
{
|
||||
Streams.Add(new FileStream(fileName, FileMode.Open));
|
||||
long length = Streams[i].Length;
|
||||
StreamOffsets.Add(i++, new KeyValuePair<long, long>(StreamLength, StreamLength + length));
|
||||
StreamLength += length;
|
||||
fileName = baseName + VolumeNumber(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#region ISequentialInStream Members
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the stream.
|
||||
/// </summary>
|
||||
/// <param name="data">A data array.</param>
|
||||
/// <param name="size">The array size.</param>
|
||||
/// <returns>The read bytes count.</returns>
|
||||
public int Read(byte[] data, uint size)
|
||||
{
|
||||
var readSize = (int) size;
|
||||
int readCount = Streams[CurrentStream].Read(data, 0, readSize);
|
||||
readSize -= readCount;
|
||||
Position += readCount;
|
||||
while (readCount < (int) size)
|
||||
{
|
||||
if (CurrentStream == Streams.Count - 1)
|
||||
{
|
||||
return readCount;
|
||||
}
|
||||
CurrentStream++;
|
||||
Streams[CurrentStream].Seek(0, SeekOrigin.Begin);
|
||||
int count = Streams[CurrentStream].Read(data, readCount, readSize);
|
||||
readCount += count;
|
||||
readSize -= count;
|
||||
Position += count;
|
||||
}
|
||||
return readCount;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#if COMPRESS
|
||||
/// <summary>
|
||||
/// IOutStream wrapper used in multi volume stream write operations.
|
||||
/// </summary>
|
||||
internal sealed class OutMultiStreamWrapper : MultiStreamWrapper, ISequentialOutStream, IOutStream
|
||||
{
|
||||
private readonly string _archiveName;
|
||||
private readonly int _volumeSize;
|
||||
private long _overallLength;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the OutMultiStreamWrapper class.
|
||||
/// </summary>
|
||||
/// <param name="archiveName">The archive name.</param>
|
||||
/// <param name="volumeSize">The volume size.</param>
|
||||
public OutMultiStreamWrapper(string archiveName, int volumeSize) :
|
||||
base(true)
|
||||
{
|
||||
_archiveName = archiveName;
|
||||
_volumeSize = volumeSize;
|
||||
CurrentStream = -1;
|
||||
NewVolumeStream();
|
||||
}
|
||||
|
||||
#region IOutStream Members
|
||||
|
||||
public int SetSize(long newSize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISequentialOutStream Members
|
||||
|
||||
public int Write(byte[] data, uint size, IntPtr processedSize)
|
||||
{
|
||||
int offset = 0;
|
||||
var originalSize = (int) size;
|
||||
Position += size;
|
||||
_overallLength = Math.Max(Position + 1, _overallLength);
|
||||
while (size > _volumeSize - Streams[CurrentStream].Position)
|
||||
{
|
||||
var count = (int) (_volumeSize - Streams[CurrentStream].Position);
|
||||
Streams[CurrentStream].Write(data, offset, count);
|
||||
size -= (uint) count;
|
||||
offset += count;
|
||||
NewVolumeStream();
|
||||
}
|
||||
Streams[CurrentStream].Write(data, offset, (int) size);
|
||||
if (processedSize != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt32(processedSize, originalSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
int lastIndex = Streams.Count - 1;
|
||||
Streams[lastIndex].SetLength(lastIndex > 0? Streams[lastIndex].Position : _overallLength);
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
private void NewVolumeStream()
|
||||
{
|
||||
CurrentStream++;
|
||||
Streams.Add(File.Create(_archiveName + VolumeNumber(CurrentStream + 1)));
|
||||
Streams[CurrentStream].SetLength(_volumeSize);
|
||||
StreamOffsets.Add(CurrentStream, new KeyValuePair<long, long>(0, _volumeSize - 1));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal sealed class FakeOutStreamWrapper : ISequentialOutStream, IDisposable
|
||||
{
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISequentialOutStream Members
|
||||
|
||||
/// <summary>
|
||||
/// Does nothing except calling the BytesWritten event
|
||||
/// </summary>
|
||||
/// <param name="data">Data array</param>
|
||||
/// <param name="size">Array size</param>
|
||||
/// <param name="processedSize">Count of written bytes</param>
|
||||
/// <returns>Zero if Ok</returns>
|
||||
public int Write(byte[] data, uint size, IntPtr processedSize)
|
||||
{
|
||||
OnBytesWritten(new IntEventArgs((int) size));
|
||||
if (processedSize != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt32(processedSize, (int) size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when IntEventArgs.Value bytes were written
|
||||
/// </summary>
|
||||
public event EventHandler<IntEventArgs> BytesWritten;
|
||||
|
||||
private void OnBytesWritten(IntEventArgs e)
|
||||
{
|
||||
if (BytesWritten != null)
|
||||
{
|
||||
BytesWritten(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
Test
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,75 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SevenZip.Sdk
|
||||
{
|
||||
internal class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
private uint _value = 0xFFFFFFFF;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
Table = new uint[256];
|
||||
const uint kPoly = 0xEDB88320;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((r & 1) != 0)
|
||||
r = (r >> 1) ^ kPoly;
|
||||
else
|
||||
r >>= 1;
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_value = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
_value = Table[(((byte) (_value)) ^ b)] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public void Update(byte[] data, uint offset, uint size)
|
||||
{
|
||||
for (uint i = 0; i < size; i++)
|
||||
_value = Table[(((byte) (_value)) ^ data[offset + i])] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public uint GetDigest()
|
||||
{
|
||||
return _value ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
private static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
var crc = new CRC();
|
||||
// crc.Init();
|
||||
crc.Update(data, offset, size);
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return (CalculateDigest(data, offset, size) == digest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Buffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the input buffer work
|
||||
/// </summary>
|
||||
internal class InBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private readonly uint m_BufferSize;
|
||||
private uint m_Limit;
|
||||
private uint m_Pos;
|
||||
private ulong m_ProcessedSize;
|
||||
private Stream m_Stream;
|
||||
private bool m_StreamWasExhausted;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the input buffer
|
||||
/// </summary>
|
||||
/// <param name="bufferSize"></param>
|
||||
private InBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the class
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
private void Init(Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Limit = 0;
|
||||
m_Pos = 0;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the whole block
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
return false;
|
||||
m_ProcessedSize += m_Pos;
|
||||
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int) m_BufferSize);
|
||||
m_Pos = 0;
|
||||
m_Limit = (uint) aNumProcessedBytes;
|
||||
m_StreamWasExhausted = (aNumProcessedBytes == 0);
|
||||
return (!m_StreamWasExhausted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the stream
|
||||
/// </summary>
|
||||
private void ReleaseStream()
|
||||
{
|
||||
// m_Stream.Close();
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the byte to check it
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
private bool ReadByte(out byte b)
|
||||
{
|
||||
b = 0;
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return false;
|
||||
b = m_Buffer[m_Pos++];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next byte
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private byte ReadByte()
|
||||
{
|
||||
// return (byte)m_Stream.ReadByte();
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return 0xFF;
|
||||
return m_Buffer[m_Pos++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets processed size
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Buffer
|
||||
{
|
||||
internal class OutBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private readonly uint m_BufferSize;
|
||||
private uint m_Pos;
|
||||
private ulong m_ProcessedSize;
|
||||
private Stream m_Stream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the OutBuffer class
|
||||
/// </summary>
|
||||
/// <param name="bufferSize"></param>
|
||||
public OutBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void SetStream(Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
m_Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
m_Stream.Close();
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_ProcessedSize = 0;
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
m_Buffer[m_Pos++] = b;
|
||||
if (m_Pos >= m_BufferSize)
|
||||
FlushData();
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
if (m_Pos == 0)
|
||||
return;
|
||||
m_Stream.Write(m_Buffer, 0, (int) m_Pos);
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.LZ
|
||||
{
|
||||
internal interface IInWindowStream
|
||||
{
|
||||
void SetStream(Stream inStream);
|
||||
void Init();
|
||||
void ReleaseStream();
|
||||
Byte GetIndexByte(Int32 index);
|
||||
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
|
||||
UInt32 GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
internal interface IMatchFinder : IInWindowStream
|
||||
{
|
||||
void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
|
||||
|
||||
UInt32 GetMatches(UInt32[] distances);
|
||||
void Skip(UInt32 num);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,405 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.LZ
|
||||
{
|
||||
internal class BinTree : InWindow, IMatchFinder
|
||||
{
|
||||
private const UInt32 kBT2HashSize = 1 << 16;
|
||||
private const UInt32 kEmptyHashValue = 0;
|
||||
private const UInt32 kHash2Size = 1 << 10;
|
||||
private const UInt32 kHash3Offset = kHash2Size;
|
||||
private const UInt32 kHash3Size = 1 << 16;
|
||||
private const UInt32 kMaxValForNormalize = ((UInt32) 1 << 31) - 1;
|
||||
private const UInt32 kStartMaxLen = 1;
|
||||
private UInt32 _cutValue = 0xFF;
|
||||
private UInt32 _cyclicBufferPos;
|
||||
private UInt32 _cyclicBufferSize;
|
||||
private UInt32[] _hash;
|
||||
|
||||
private UInt32 _hashMask;
|
||||
private UInt32 _hashSizeSum;
|
||||
private UInt32 _matchMaxLen;
|
||||
|
||||
private UInt32[] _son;
|
||||
|
||||
private bool HASH_ARRAY = true;
|
||||
|
||||
private UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
private UInt32 kMinMatchCheck = 4;
|
||||
private UInt32 kNumHashDirectBytes;
|
||||
|
||||
#region IMatchFinder Members
|
||||
|
||||
public new void SetStream(Stream stream)
|
||||
{
|
||||
base.SetStream(stream);
|
||||
}
|
||||
|
||||
public new void ReleaseStream()
|
||||
{
|
||||
base.ReleaseStream();
|
||||
}
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
_hash[i] = kEmptyHashValue;
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index)
|
||||
{
|
||||
return base.GetIndexByte(index);
|
||||
}
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
return base.GetMatchLen(index, distance, limit);
|
||||
}
|
||||
|
||||
public new UInt32 GetNumAvailableBytes()
|
||||
{
|
||||
return base.GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize + 256 > kMaxValForNormalize)
|
||||
{
|
||||
throw new ArgumentException("historySize + 256 > kMaxValForNormalize", "historySize");
|
||||
}
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = (historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter)/2 + 256;
|
||||
|
||||
base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize)*2];
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
hs >>= 1;
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = (temp & (((int) kHash2Size) - 1));
|
||||
temp ^= (uint) ((_bufferBase[cur + 2]) << 8);
|
||||
hash3Value = (temp & (((int) kHash3Size) - 1));
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32) (_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
if (curMatch3 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
offset -= 2;
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0)
|
||||
{
|
||||
if (curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos)
|
||||
?
|
||||
(_cyclicBufferPos - delta)
|
||||
:
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = (temp & (((int) kHash2Size) - 1));
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= ((UInt32) (_bufferBase[cur + 2]) << 8);
|
||||
UInt32 hash3Value = (temp & (((int) kHash3Size) - 1));
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32) (_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos)
|
||||
?
|
||||
(_cyclicBufferPos - delta)
|
||||
:
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = (numHashBytes > 2);
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
_cyclicBufferPos = 0;
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
Normalize();
|
||||
}
|
||||
|
||||
private static void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize*2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32) subValue);
|
||||
}
|
||||
|
||||
//public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.LZ
|
||||
{
|
||||
/// <summary>
|
||||
/// Input window class
|
||||
/// </summary>
|
||||
internal class InWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of Allocated memory block
|
||||
/// </summary>
|
||||
public UInt32 _blockSize;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to buffer with data
|
||||
/// </summary>
|
||||
public Byte[] _bufferBase;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer offset value
|
||||
/// </summary>
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
/// <summary>
|
||||
/// How many BYTEs must be kept buffer after _pos
|
||||
/// </summary>
|
||||
private UInt32 _keepSizeAfter;
|
||||
|
||||
/// <summary>
|
||||
/// How many BYTEs must be kept in buffer before _pos
|
||||
/// </summary>
|
||||
private UInt32 _keepSizeBefore;
|
||||
|
||||
private UInt32 _pointerToLastSafePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Offset (from _buffer) of curent byte
|
||||
/// </summary>
|
||||
public UInt32 _pos;
|
||||
|
||||
private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
private Stream _stream;
|
||||
private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
/// <summary>
|
||||
/// Offset (from _buffer) of first not read byte from Stream
|
||||
/// </summary>
|
||||
public UInt32 _streamPos;
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = (_bufferOffset) + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
offset--;
|
||||
|
||||
UInt32 numBytes = (_bufferOffset) + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
return;
|
||||
while (true)
|
||||
{
|
||||
var size = (int) ((0 - _bufferOffset) + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
return;
|
||||
int numReadBytes = _stream.Read(_bufferBase, (int) (_bufferOffset + _streamPos), size);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
_posLimit = (_pointerToLastSafePosition - _bufferOffset);
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32) numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
|
||||
private void Free()
|
||||
{
|
||||
_bufferBase = null;
|
||||
}
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
}
|
||||
|
||||
public void SetStream(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
MoveBlock();
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index)
|
||||
{
|
||||
return _bufferBase[_bufferOffset + _pos + index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// index + limit have not to exceed _keepSizeAfter
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="distance"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <returns></returns>
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
if ((_pos + index) + limit > _streamPos)
|
||||
limit = _streamPos - (UInt32) (_pos + index);
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32) index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) ;
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes()
|
||||
{
|
||||
return _streamPos - _pos;
|
||||
}
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32) subValue;
|
||||
_posLimit -= (UInt32) subValue;
|
||||
_pos -= (UInt32) subValue;
|
||||
_streamPos -= (UInt32) subValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.LZ
|
||||
{
|
||||
internal class OutWindow
|
||||
{
|
||||
private byte[] _buffer;
|
||||
private uint _pos;
|
||||
private Stream _stream;
|
||||
private uint _streamPos;
|
||||
private uint _windowSize;
|
||||
public uint TrainSize;
|
||||
|
||||
public void Create(uint windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
{
|
||||
// System.GC.Collect();
|
||||
_buffer = new byte[windowSize];
|
||||
}
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
|
||||
public void Init(Stream stream, bool solid)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
if (!solid)
|
||||
{
|
||||
_streamPos = 0;
|
||||
_pos = 0;
|
||||
TrainSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Train(Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
uint size = (len < _windowSize) ? (uint) len : _windowSize;
|
||||
TrainSize = size;
|
||||
stream.Position = len - size;
|
||||
_streamPos = _pos = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
uint curSize = _windowSize - _pos;
|
||||
if (size < curSize)
|
||||
curSize = size;
|
||||
int numReadBytes = stream.Read(_buffer, (int) _pos, (int) curSize);
|
||||
if (numReadBytes == 0)
|
||||
return false;
|
||||
size -= (uint) numReadBytes;
|
||||
_pos += (uint) numReadBytes;
|
||||
_streamPos += (uint) numReadBytes;
|
||||
if (_pos == _windowSize)
|
||||
_streamPos = _pos = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
uint size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
return;
|
||||
_stream.Write(_buffer, (int) _streamPos, (int) size);
|
||||
if (_pos >= _windowSize)
|
||||
_pos = 0;
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(uint distance, uint len)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
for (; len > 0; len--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
pos = 0;
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
|
||||
public byte GetByte(uint distance)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
return _buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SevenZip.Sdk.Compression.Lzma
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kAlignMask = (kAlignTableSize - 1);
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int) kEndPosModelIndex/2);
|
||||
public const int kNumHighLenBits = 8;
|
||||
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
|
||||
public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
return len;
|
||||
return (kNumLenToPosStates - 1);
|
||||
}
|
||||
|
||||
#region Nested type: State
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4) Index = 0;
|
||||
else if (Index < 10) Index -= 3;
|
||||
else Index -= 6;
|
||||
}
|
||||
|
||||
public void UpdateMatch()
|
||||
{
|
||||
Index = (uint) (Index < 7 ? 7 : 10);
|
||||
}
|
||||
|
||||
public void UpdateRep()
|
||||
{
|
||||
Index = (uint) (Index < 7 ? 8 : 11);
|
||||
}
|
||||
|
||||
public void UpdateShortRep()
|
||||
{
|
||||
Index = (uint) (Index < 7 ? 9 : 11);
|
||||
}
|
||||
|
||||
public bool IsCharState()
|
||||
{
|
||||
return Index < 7;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,480 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using SevenZip.Sdk.Compression.LZ;
|
||||
using SevenZip.Sdk.Compression.RangeCoder;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.Lzma
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZMA decoder class
|
||||
/// </summary>
|
||||
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
private readonly BitDecoder[] m_IsRep0LongDecoders =
|
||||
new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
|
||||
private readonly LenDecoder m_LenDecoder = new LenDecoder();
|
||||
|
||||
private readonly LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
|
||||
private readonly OutWindow m_OutWindow = new OutWindow();
|
||||
private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
private readonly RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
|
||||
private readonly LenDecoder m_RepLenDecoder = new LenDecoder();
|
||||
private bool _solid;
|
||||
|
||||
private uint m_DictionarySize;
|
||||
private uint m_DictionarySizeCheck;
|
||||
private BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
|
||||
|
||||
private uint m_PosStateMask;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Lzma Decoder class.
|
||||
/// </summary>
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = 0xFFFFFFFF;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
|
||||
#region ICoder Members
|
||||
|
||||
/// <summary>
|
||||
/// Codes a stream with LZMA algorithm to an output stream
|
||||
/// </summary>
|
||||
/// <param name="inStream">The input stream</param>
|
||||
/// <param name="inSize">The input size</param>
|
||||
/// <param name="outSize">The output size</param>
|
||||
/// <param name="outStream">The output stream</param>
|
||||
/// <param name="progress">Progress interface</param>
|
||||
public void Code(Stream inStream, Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress)
|
||||
{
|
||||
Init(inStream, outStream);
|
||||
|
||||
var state = new Base.State();
|
||||
state.Init();
|
||||
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
|
||||
|
||||
UInt64 nowPos64 = 0;
|
||||
var outSize64 = (UInt64) outSize;
|
||||
if (nowPos64 < outSize64)
|
||||
{
|
||||
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
|
||||
throw new DataErrorException();
|
||||
state.UpdateChar();
|
||||
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
|
||||
m_OutWindow.PutByte(b);
|
||||
nowPos64++;
|
||||
}
|
||||
while (nowPos64 < outSize64)
|
||||
{
|
||||
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
|
||||
// while(nowPos64 < next)
|
||||
{
|
||||
uint posState = (uint) nowPos64 & m_PosStateMask;
|
||||
if (
|
||||
m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) ==
|
||||
0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = m_OutWindow.GetByte(0);
|
||||
if (!state.IsCharState())
|
||||
b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
|
||||
(uint) nowPos64, prevByte,
|
||||
m_OutWindow.GetByte(rep0));
|
||||
else
|
||||
b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint) nowPos64, prevByte);
|
||||
m_OutWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
nowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
if (
|
||||
m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(
|
||||
m_RangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
|
||||
nowPos64++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
distance = rep2;
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
var numDirectBits = (int) ((posSlot >> 1) - 1);
|
||||
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, m_RangeDecoder,
|
||||
numDirectBits);
|
||||
else
|
||||
{
|
||||
rep0 += (m_RangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 = posSlot;
|
||||
}
|
||||
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
break;
|
||||
throw new DataErrorException();
|
||||
}
|
||||
m_OutWindow.CopyBlock(rep0, len);
|
||||
nowPos64 += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_OutWindow.Flush();
|
||||
m_OutWindow.ReleaseStream();
|
||||
m_RangeDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISetDecoderProperties Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets decoder properties
|
||||
/// </summary>
|
||||
/// <param name="properties">Array of byte properties</param>
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 5)
|
||||
throw new InvalidParamException();
|
||||
int lc = properties[0]%9;
|
||||
int remainder = properties[0]/9;
|
||||
int lp = remainder%5;
|
||||
int pb = remainder/5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
UInt32 dictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
dictionarySize += ((UInt32) (properties[1 + i])) << (i*8);
|
||||
SetDictionarySize(dictionarySize);
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void SetDictionarySize(uint dictionarySize)
|
||||
{
|
||||
if (m_DictionarySize != dictionarySize)
|
||||
{
|
||||
m_DictionarySize = dictionarySize;
|
||||
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
|
||||
uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
throw new InvalidParamException();
|
||||
if (lc > 8)
|
||||
throw new InvalidParamException();
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
private void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
uint numPosStates = (uint) 1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
private void Init(Stream inStream, Stream outStream)
|
||||
{
|
||||
m_RangeDecoder.Init(inStream);
|
||||
m_OutWindow.Init(outStream, _solid);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i].Init();
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
m_PosDecoders[i].Init();
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trains a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to train.</param>
|
||||
/// <returns>true if Ok; otherwise, false.</returns>
|
||||
public bool Train(Stream stream)
|
||||
{
|
||||
_solid = true;
|
||||
return m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
#region Nested type: LenDecoder
|
||||
|
||||
private class LenDecoder
|
||||
{
|
||||
private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private BitDecoder m_Choice;
|
||||
private BitDecoder m_Choice2;
|
||||
private BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
|
||||
private uint m_NumPosStates;
|
||||
|
||||
internal void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
internal void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the stream
|
||||
/// </summary>
|
||||
/// <param name="rangeDecoder">The specified RangeCoder</param>
|
||||
/// <param name="posState">The position state</param>
|
||||
/// <returns></returns>
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: LiteralDecoder
|
||||
|
||||
private class LiteralDecoder
|
||||
{
|
||||
private Decoder2[] m_Coders;
|
||||
private int m_NumPosBits;
|
||||
private int m_NumPrevBits;
|
||||
private uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
return;
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint) 1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint) 1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint) 1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
|
||||
private uint GetState(uint pos, byte prevByte)
|
||||
{
|
||||
return ((pos & m_PosMask) << m_NumPrevBits) + (uint) (prevByte >> (8 - m_NumPrevBits));
|
||||
}
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{
|
||||
return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder);
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{
|
||||
return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte);
|
||||
}
|
||||
|
||||
#region Nested type: Decoder2
|
||||
|
||||
private struct Decoder2
|
||||
{
|
||||
private BitDecoder[] m_Decoders;
|
||||
|
||||
public void Create()
|
||||
{
|
||||
m_Decoders = new BitDecoder[0x300];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (int i = 0; i < 0x300; i++) m_Decoders[i].Init();
|
||||
}
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); while (symbol < 0x100);
|
||||
return (byte) symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint) (matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
break;
|
||||
}
|
||||
} while (symbol < 0x100);
|
||||
return (byte) symbol;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
} ;
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,249 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.RangeCoder
|
||||
{
|
||||
internal class Encoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
private byte _cache;
|
||||
private uint _cacheSize;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
|
||||
private long StartPosition;
|
||||
private Stream Stream;
|
||||
|
||||
public void SetStream(Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ShiftLow();
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
/*public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}*/
|
||||
|
||||
/*public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}*/
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint) Low < 0xFF000000 || (uint) (Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte) (temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
} while (--_cacheSize != 0);
|
||||
_cache = (byte) (((uint) Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint) Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
Low += Range;
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
Range = newBound;
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}*/
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Decoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
public uint Code;
|
||||
public uint Range;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public Stream Stream;
|
||||
|
||||
public void Init(Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
Code = (Code << 8) | (byte) Stream.ReadByte();
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
/*public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}*/
|
||||
|
||||
/*public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}*/
|
||||
|
||||
/*public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}*/
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte) Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}*/
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitEncoder
|
||||
{
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
private const int kNumMoveBits = 5;
|
||||
private const int kNumMoveReducingBits = 2;
|
||||
private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
private uint Prob;
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32) 1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32) 1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
ProbPrices[j] = ((UInt32) i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Prob = kBitModelTotal >> 1;
|
||||
}
|
||||
|
||||
/*public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}*/
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits)*Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ ((-(int) symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
|
||||
public uint GetPrice0()
|
||||
{
|
||||
return ProbPrices[Prob >> kNumMoveReducingBits];
|
||||
}
|
||||
|
||||
public uint GetPrice1()
|
||||
{
|
||||
return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits];
|
||||
}
|
||||
}
|
||||
|
||||
internal struct BitDecoder
|
||||
{
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
private const int kNumMoveBits = 5;
|
||||
|
||||
private uint Prob;
|
||||
|
||||
/*public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> numMoveBits;
|
||||
}*/
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Prob = kBitModelTotal >> 1;
|
||||
}
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits)*Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte) rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte) rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Sdk.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitTreeEncoder
|
||||
{
|
||||
private readonly BitEncoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct BitTreeDecoder
|
||||
{
|
||||
private readonly BitDecoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
return m - ((uint) 1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/* This file is part of SevenZipSharp.
|
||||
|
||||
SevenZipSharp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SevenZipSharp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SevenZip.Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class DataErrorException : ApplicationException
|
||||
{
|
||||
public DataErrorException() : base("Data Error") {}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
internal class InvalidParamException : ApplicationException
|
||||
{
|
||||
public InvalidParamException() : base("Invalid Parameter") {}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback progress interface.
|
||||
/// </summary>
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// Processed input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// Processed output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
} ;
|
||||
|
||||
/// <summary>
|
||||
/// Stream coder interface
|
||||
/// </summary>
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="SevenZip.Sdk.DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(Stream inStream, Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress);
|
||||
} ;
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropId
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker = 0x490
|
||||
} ;
|
||||
|
||||
/// <summary>
|
||||
/// The ISetCoderProperties interface
|
||||
/// </summary>
|
||||
internal interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropId[] propIDs, object[] properties);
|
||||
} ;
|
||||
|
||||
/// <summary>
|
||||
/// The IWriteCoderProperties interface
|
||||
/// </summary>
|
||||
internal interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(Stream outStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ISetDecoderPropertiesinterface
|
||||
/// </summary>
|
||||
internal interface ISetDecoderProperties
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets decoder properties
|
||||
/// </summary>
|
||||
/// <param name="properties">Array of byte properties</param>
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{24A0AA3C-B25F-4197-B23D-476D6462DBA0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>BizHawk.Client.Common</RootNamespace>
|
||||
<AssemblyName>BizHawk.Client.Common</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;DOTNET20;UNMANAGED;COMPRESS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;DOTNET20;UNMANAGED;COMPRESS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="7z\ArchiveEmulationStreamProxy.cs" />
|
||||
<Compile Include="7z\ArchiveExtractCallback.cs" />
|
||||
<Compile Include="7z\ArchiveOpenCallback.cs" />
|
||||
<Compile Include="7z\ArchiveUpdateCallback.cs" />
|
||||
<Compile Include="7z\COM.cs" />
|
||||
<Compile Include="7z\Common.cs" />
|
||||
<Compile Include="7z\EventArgs.cs" />
|
||||
<Compile Include="7z\Exceptions.cs" />
|
||||
<Compile Include="7z\FileSignatureChecker.cs" />
|
||||
<Compile Include="7z\Formats.cs" />
|
||||
<Compile Include="7z\LibraryFeature.cs" />
|
||||
<Compile Include="7z\LibraryManager.cs" />
|
||||
<Compile Include="7z\LzmaDecodeStream.cs" />
|
||||
<Compile Include="7z\LzmaEncodeStream.cs" />
|
||||
<Compile Include="7z\LzmaProgressCallback.cs" />
|
||||
<Compile Include="7z\NativeMethods.cs" />
|
||||
<Compile Include="7z\sdk\Common\CRC.cs" />
|
||||
<Compile Include="7z\sdk\Common\InBuffer.cs" />
|
||||
<Compile Include="7z\sdk\Common\OutBuffer.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZMA\LzmaBase.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZMA\LzmaDecoder.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZMA\LzmaEncoder.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZ\IMatchFinder.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZ\LzBinTree.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZ\LzInWindow.cs" />
|
||||
<Compile Include="7z\sdk\Compress\LZ\LzOutWindow.cs" />
|
||||
<Compile Include="7z\sdk\Compress\RangeCoder\RangeCoder.cs" />
|
||||
<Compile Include="7z\sdk\Compress\RangeCoder\RangeCoderBit.cs" />
|
||||
<Compile Include="7z\sdk\Compress\RangeCoder\RangeCoderBitTree.cs" />
|
||||
<Compile Include="7z\sdk\ICoder.cs" />
|
||||
<Compile Include="7z\SevenZipCompressor.cs" />
|
||||
<Compile Include="7z\SevenZipCompressorAsynchronous.cs" />
|
||||
<Compile Include="7z\SevenZipExtractor.cs" />
|
||||
<Compile Include="7z\SevenZipExtractorAsynchronous.cs" />
|
||||
<Compile Include="7z\SevenZipSfx.cs" />
|
||||
<Compile Include="7z\StreamWrappers.cs" />
|
||||
<Compile Include="config\Binding.cs" />
|
||||
<Compile Include="config\Config.cs" />
|
||||
<Compile Include="config\ConfigService.cs" />
|
||||
<Compile Include="CoreFileProvider.cs" />
|
||||
<Compile Include="FirmwareManager.cs" />
|
||||
<Compile Include="Global.cs" />
|
||||
<Compile Include="HawkFile.cs" />
|
||||
<Compile Include="helpers\InputValidate.cs" />
|
||||
<Compile Include="KeyTurbo.cs" />
|
||||
<Compile Include="movie\InputAdapters.cs" />
|
||||
<Compile Include="movie\Movie.cs" />
|
||||
<Compile Include="movie\MovieHeader.cs" />
|
||||
<Compile Include="movie\MovieLog.cs" />
|
||||
<Compile Include="movie\MovieMnemonics.cs" />
|
||||
<Compile Include="movie\MovieSession.cs" />
|
||||
<Compile Include="movie\MultitrackRecording.cs" />
|
||||
<Compile Include="movie\Subtitle.cs" />
|
||||
<Compile Include="movie\SubtitleList.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RecentFiles.cs" />
|
||||
<Compile Include="helpers\StringHelpers.cs" />
|
||||
<Compile Include="RomGame.cs" />
|
||||
<Compile Include="tools\Cheat.cs" />
|
||||
<Compile Include="tools\CheatList.cs" />
|
||||
<Compile Include="tools\Watch.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BizHawk.Emulation\BizHawk.Emulation.csproj">
|
||||
<Project>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</Project>
|
||||
<Name>BizHawk.Emulation</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="7z\arch\Test.bzip2.7z" />
|
||||
<None Include="7z\arch\Test.lzma.7z" />
|
||||
<None Include="7z\arch\Test.lzma2.7z" />
|
||||
<None Include="7z\arch\Test.ppmd.7z" />
|
||||
<None Include="7z\arch\Test.rar" />
|
||||
<None Include="7z\arch\Test.tar" />
|
||||
<None Include="7z\arch\Test.txt.bz2" />
|
||||
<None Include="7z\arch\Test.txt.gz" />
|
||||
<None Include="7z\arch\Test.txt.xz" />
|
||||
<None Include="7z\arch\Test.zip" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="7z\arch\Test.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class CoreFileProvider : ICoreFileProvider
|
||||
{
|
||||
public string SubfileDirectory;
|
||||
public FirmwareManager FirmwareManager;
|
||||
|
||||
public Stream OpenFirmware(string sysId, string key)
|
||||
{
|
||||
var fn = PathFirmware(sysId, key);
|
||||
return new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
}
|
||||
|
||||
public string PathFirmware(string sysId, string key)
|
||||
{
|
||||
return FirmwareManager.Request(sysId, key);
|
||||
}
|
||||
|
||||
public string PathSubfile(string fname)
|
||||
{
|
||||
return Path.Combine(Path.GetDirectoryName(SubfileDirectory), fname);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
//IDEA: put filesizes in DB too. then scans can go real quick by only scanning filesizes that match (and then scanning filesizes that dont match, in case of an emergency)
|
||||
//this would be adviseable if we end up with a very large firmware file
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class FirmwareManager
|
||||
{
|
||||
//represents a file found on disk in the user's firmware directory matching a file in our database
|
||||
class RealFirmwareFile
|
||||
{
|
||||
public FileInfo fi;
|
||||
public string hash;
|
||||
}
|
||||
|
||||
public class ResolutionInfo
|
||||
{
|
||||
public bool UserSpecified;
|
||||
public bool Missing;
|
||||
public bool KnownMismatching;
|
||||
public FirmwareDatabase.FirmwareFile KnownFirmwareFile;
|
||||
public string FilePath;
|
||||
public string Hash;
|
||||
}
|
||||
|
||||
Dictionary<FirmwareDatabase.FirmwareRecord, ResolutionInfo> ResolutionDictionary = new Dictionary<FirmwareDatabase.FirmwareRecord, ResolutionInfo>();
|
||||
|
||||
|
||||
public ResolutionInfo Resolve(string sysId, string firmwareId)
|
||||
{
|
||||
return Resolve(FirmwareDatabase.LookupFirmwareRecord(sysId, firmwareId));
|
||||
}
|
||||
|
||||
public ResolutionInfo Resolve(FirmwareDatabase.FirmwareRecord record)
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
RETRY:
|
||||
|
||||
ResolutionInfo resolved = null;
|
||||
ResolutionDictionary.TryGetValue(record, out resolved);
|
||||
|
||||
//couldnt find it! do a scan and resolve to try harder
|
||||
if (resolved == null && first)
|
||||
{
|
||||
DoScanAndResolve();
|
||||
first = false;
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
//Requests the spcified firmware. tries really hard to scan and resolve as necessary
|
||||
public string Request(string sysId, string firmwareId)
|
||||
{
|
||||
var resolved = Resolve(sysId, firmwareId);
|
||||
if (resolved == null) return null;
|
||||
return resolved.FilePath;
|
||||
}
|
||||
|
||||
class RealFirmwareReader
|
||||
{
|
||||
byte[] buffer = new byte[0];
|
||||
public RealFirmwareFile Read(FileInfo fi)
|
||||
{
|
||||
RealFirmwareFile rff = new RealFirmwareFile();
|
||||
rff.fi = fi;
|
||||
long len = fi.Length;
|
||||
if (len > buffer.Length) buffer = new byte[len];
|
||||
using (var fs = fi.OpenRead()) fs.Read(buffer, 0, (int)len);
|
||||
rff.hash = Util.Hash_SHA1(buffer, 0, (int)len);
|
||||
dict[rff.hash] = rff;
|
||||
files.Add(rff);
|
||||
return rff;
|
||||
}
|
||||
public Dictionary<string, RealFirmwareFile> dict = new Dictionary<string, RealFirmwareFile>();
|
||||
public List<RealFirmwareFile> files = new List<RealFirmwareFile>();
|
||||
}
|
||||
|
||||
public void DoScanAndResolve()
|
||||
{
|
||||
RealFirmwareReader reader = new RealFirmwareReader();
|
||||
|
||||
//build a list of files under the global firmwares path, and build a hash for each of them while we're at it
|
||||
var todo = new Queue<DirectoryInfo>(new[] { new DirectoryInfo(Global.Config.PathEntries.FirmwaresPath) });
|
||||
|
||||
while (todo.Count != 0)
|
||||
{
|
||||
var di = todo.Dequeue();
|
||||
|
||||
//we're going to allow recursing into subdirectories, now. its been verified to work OK
|
||||
foreach (var disub in di.GetDirectories()) todo.Enqueue(disub);
|
||||
|
||||
foreach (var fi in di.GetFiles())
|
||||
{
|
||||
reader.Read(fi);
|
||||
}
|
||||
}
|
||||
|
||||
//now, for each firmware record, try to resolve it
|
||||
foreach (var fr in FirmwareDatabase.FirmwareRecords)
|
||||
{
|
||||
//clear previous resolution results
|
||||
ResolutionDictionary.Remove(fr);
|
||||
|
||||
//get all options for this firmware (in order)
|
||||
var options =
|
||||
from fo in FirmwareDatabase.FirmwareOptions
|
||||
where fo.systemId == fr.systemId && fo.firmwareId == fr.firmwareId
|
||||
select fo;
|
||||
|
||||
//try each option
|
||||
foreach (var fo in options)
|
||||
{
|
||||
var hash = fo.hash;
|
||||
//did we find this firmware?
|
||||
if (reader.dict.ContainsKey(hash))
|
||||
{
|
||||
//rad! then we can use it
|
||||
var ri = new ResolutionInfo();
|
||||
ri.FilePath = reader.dict[hash].fi.FullName;
|
||||
ri.KnownFirmwareFile = FirmwareDatabase.FirmwareFilesByHash[hash];
|
||||
ri.Hash = hash;
|
||||
ResolutionDictionary[fr] = ri;
|
||||
goto DONE_FIRMWARE;
|
||||
}
|
||||
}
|
||||
|
||||
DONE_FIRMWARE: ;
|
||||
|
||||
}
|
||||
|
||||
//apply user overrides
|
||||
foreach (var fr in FirmwareDatabase.FirmwareRecords)
|
||||
{
|
||||
string userSpec = null;
|
||||
|
||||
//do we have a user specification for this firmware record?
|
||||
if (Global.Config.FirmwareUserSpecifications.TryGetValue(fr.ConfigKey, out userSpec))
|
||||
{
|
||||
//flag it as user specified
|
||||
ResolutionInfo ri = null;
|
||||
if (!ResolutionDictionary.TryGetValue(fr, out ri))
|
||||
{
|
||||
ri = new ResolutionInfo();
|
||||
ResolutionDictionary[fr] = ri;
|
||||
}
|
||||
ri.UserSpecified = true;
|
||||
ri.KnownFirmwareFile = null;
|
||||
ri.FilePath = userSpec;
|
||||
ri.Hash = null;
|
||||
|
||||
//check whether it exists
|
||||
var fi = new FileInfo(userSpec);
|
||||
if (!fi.Exists)
|
||||
{
|
||||
ri.Missing = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
//compute its hash
|
||||
var rff = reader.Read(fi);
|
||||
ri.Hash = rff.hash;
|
||||
|
||||
//check whether it was a known file anyway, and go ahead and bind to the known file, as a perk (the firmwares config doesnt really use this information right now)
|
||||
FirmwareDatabase.FirmwareFile ff = null;
|
||||
if(FirmwareDatabase.FirmwareFilesByHash.TryGetValue(rff.hash,out ff))
|
||||
{
|
||||
ri.KnownFirmwareFile = ff;
|
||||
|
||||
//if the known firmware file is for a different firmware, flag it so we can show a warning
|
||||
var option =
|
||||
(from fo in FirmwareDatabase.FirmwareOptions
|
||||
where fo.hash == rff.hash && fo.ConfigKey != fr.ConfigKey
|
||||
select fr).FirstOrDefault();
|
||||
if (option != null)
|
||||
ri.KnownMismatching = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
public static IEmulator Emulator;
|
||||
public static Config Config;
|
||||
public static GameInfo Game;
|
||||
public static CheatList CheatList;
|
||||
|
||||
//Movie
|
||||
|
||||
/// <summary>
|
||||
/// the global MovieSession can use this to deal with multitrack player remapping (should this be here? maybe it should be in MovieSession)
|
||||
/// </summary>
|
||||
public static MultitrackRewiringControllerAdapter MultitrackRewiringControllerAdapter = new MultitrackRewiringControllerAdapter();
|
||||
public static MovieSession MovieSession = new MovieSession();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
//todo:
|
||||
//split into "bind" and "open (the bound thing)"
|
||||
//scan archive to flatten interior directories down to a path (maintain our own archive item list)
|
||||
|
||||
public class HawkFile : IDisposable
|
||||
{
|
||||
public static bool ExistsAt(string path)
|
||||
{
|
||||
using (var file = new HawkFile(path))
|
||||
{
|
||||
return file.Exists;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(string path)
|
||||
{
|
||||
using (var file = new HawkFile(path))
|
||||
{
|
||||
if (!file.Exists) throw new FileNotFoundException(path);
|
||||
using (Stream stream = file.GetStream())
|
||||
{
|
||||
MemoryStream ms = new MemoryStream((int)stream.Length);
|
||||
stream.CopyTo(ms);
|
||||
return ms.GetBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// returns whether a bound file exists. if there is no bound file, it can't exist
|
||||
/// </summary>
|
||||
public bool Exists { get { return exists; } }
|
||||
|
||||
/// <summary>
|
||||
/// gets the directory containing the root
|
||||
/// </summary>
|
||||
public string Directory { get { return Path.GetDirectoryName(rootPath); } }
|
||||
|
||||
/// <summary>
|
||||
/// returns a stream for the currently bound file
|
||||
/// </summary>
|
||||
public Stream GetStream()
|
||||
{
|
||||
if (boundStream == null)
|
||||
throw new InvalidOperationException("HawkFile: Can't call GetStream() before youve successfully bound something!");
|
||||
return boundStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// indicates whether this instance is bound
|
||||
/// </summary>
|
||||
public bool IsBound { get { return boundStream != null; } }
|
||||
|
||||
/// <summary>
|
||||
/// returns the complete canonical full path ("c:\path\to\archive|member") of the bound file
|
||||
/// </summary>
|
||||
public string CanonicalFullPath { get { return MakeCanonicalName(rootPath, memberPath); } }
|
||||
|
||||
/// <summary>
|
||||
/// returns the complete canonical name ("archive|member") of the bound file
|
||||
/// </summary>
|
||||
public string CanonicalName { get { return MakeCanonicalName(Path.GetFileName(rootPath), memberPath); } }
|
||||
|
||||
/// <summary>
|
||||
/// returns the virtual name of the bound file (disregarding the archive)
|
||||
/// </summary>
|
||||
public string Name { get { return GetBoundNameFromCanonical(MakeCanonicalName(rootPath, memberPath)); } }
|
||||
|
||||
/// <summary>
|
||||
/// returns the extension of Name
|
||||
/// </summary>
|
||||
public string Extension { get { return Path.GetExtension(Name).ToUpper(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this file is an archive
|
||||
/// </summary>
|
||||
public bool IsArchive { get { return extractor != null; } }
|
||||
|
||||
int? BoundIndex = null;
|
||||
|
||||
public int? GetBoundIndex()
|
||||
{
|
||||
return BoundIndex;
|
||||
}
|
||||
|
||||
|
||||
public class ArchiveItem
|
||||
{
|
||||
public string name;
|
||||
public long size;
|
||||
public int index;
|
||||
}
|
||||
|
||||
public IEnumerable<ArchiveItem> ArchiveItems
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsArchive) throw new InvalidOperationException("Cant get archive items from non-archive");
|
||||
return archiveItems;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// these extensions won't even be tried as archives (removes spurious archive detects since some of the signatures are pretty damn weak)
|
||||
/// </summary>
|
||||
public string[] NonArchiveExtensions = new string[] { };
|
||||
|
||||
//---
|
||||
bool exists;
|
||||
bool rootExists;
|
||||
string rootPath;
|
||||
string memberPath;
|
||||
Stream rootStream, boundStream;
|
||||
SevenZip.SevenZipExtractor extractor;
|
||||
List<ArchiveItem> archiveItems;
|
||||
|
||||
public HawkFile()
|
||||
{
|
||||
}
|
||||
|
||||
public void Open(string path)
|
||||
{
|
||||
if (rootPath != null) throw new InvalidOperationException("Don't reopen a HawkFile.");
|
||||
|
||||
string autobind = null;
|
||||
bool isArchivePath = IsCanonicalArchivePath(path);
|
||||
if (isArchivePath)
|
||||
{
|
||||
string[] parts = path.Split('|');
|
||||
path = parts[0];
|
||||
autobind = parts[1];
|
||||
}
|
||||
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
rootExists = fi.Exists;
|
||||
if (fi.Exists == false)
|
||||
return;
|
||||
|
||||
rootPath = path;
|
||||
exists = true;
|
||||
|
||||
AnalyzeArchive(path);
|
||||
if (extractor == null)
|
||||
{
|
||||
rootStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
//we could autobind here, but i dont want to
|
||||
//bind it later with the desired extensions.
|
||||
}
|
||||
|
||||
if (autobind == null)
|
||||
{
|
||||
//non-archive files can be automatically bound this way
|
||||
if (!isArchivePath)
|
||||
BindRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
autobind = autobind.ToUpperInvariant();
|
||||
for (int i = 0; i < extractor.ArchiveFileData.Count; i++)
|
||||
{
|
||||
if (FixArchiveFilename(extractor.ArchiveFileNames[i]).ToUpperInvariant() == autobind)
|
||||
{
|
||||
BindArchiveMember(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
exists = false;
|
||||
}
|
||||
}
|
||||
|
||||
public HawkFile(string path)
|
||||
{
|
||||
Open(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is the supplied path a canonical name including an archive?
|
||||
/// </summary>
|
||||
bool IsCanonicalArchivePath(string path)
|
||||
{
|
||||
return (path.IndexOf('|') != -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// converts a canonical name to a bound name (the bound part, whether or not it is an archive)
|
||||
/// </summary>
|
||||
string GetBoundNameFromCanonical(string canonical)
|
||||
{
|
||||
string[] parts = canonical.Split('|');
|
||||
return parts[parts.Length - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// makes a canonical name from two parts
|
||||
/// </summary>
|
||||
string MakeCanonicalName(string root, string member)
|
||||
{
|
||||
if (member == null) return root;
|
||||
else return string.Format("{0}|{1}", root, member);
|
||||
}
|
||||
|
||||
string FixArchiveFilename(string fn)
|
||||
{
|
||||
return fn.Replace('\\', '/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// binds the specified ArchiveItem which you should have gotten by interrogating an archive hawkfile
|
||||
/// </summary>
|
||||
public HawkFile BindArchiveMember(ArchiveItem item)
|
||||
{
|
||||
return BindArchiveMember(item.index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// finds an ArchiveItem with the specified name (path) within the archive; returns null if it doesnt exist
|
||||
/// </summary>
|
||||
public ArchiveItem FindArchiveMember(string name)
|
||||
{
|
||||
return ArchiveItems.FirstOrDefault(ai => ai.name == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// binds a path within the archive; returns null if that path didnt exist.
|
||||
/// </summary>
|
||||
public HawkFile BindArchiveMember(string name)
|
||||
{
|
||||
var ai = FindArchiveMember(name);
|
||||
if (ai == null) return null;
|
||||
else return BindArchiveMember(ai);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// binds the selected archive index
|
||||
/// </summary>
|
||||
public HawkFile BindArchiveMember(int archiveIndex)
|
||||
{
|
||||
if (!rootExists) return this;
|
||||
if (boundStream != null) throw new InvalidOperationException("stream already bound!");
|
||||
|
||||
boundStream = new MemoryStream();
|
||||
extractor.ExtractFile(archiveIndex, boundStream);
|
||||
boundStream.Position = 0;
|
||||
memberPath = FixArchiveFilename(extractor.ArchiveFileNames[archiveIndex]); //TODO - maybe go through our own list of names? maybe not, its indexes dont match..
|
||||
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
||||
BoundIndex = archiveIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes any existing binding
|
||||
/// </summary>
|
||||
public void Unbind()
|
||||
{
|
||||
if (boundStream != null && boundStream != rootStream) boundStream.Close();
|
||||
boundStream = null;
|
||||
memberPath = null;
|
||||
BoundIndex = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// causes the root to be bound (in the case of non-archive files)
|
||||
/// </summary>
|
||||
void BindRoot()
|
||||
{
|
||||
boundStream = rootStream;
|
||||
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds the first item in the archive (or the file itself). Supposing that there is anything in the archive.
|
||||
/// </summary>
|
||||
public HawkFile BindFirst()
|
||||
{
|
||||
BindFirstOf();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// binds one of the supplied extensions if there is only one match in the archive
|
||||
/// </summary>
|
||||
public HawkFile BindSoleItemOf(params string[] extensions)
|
||||
{
|
||||
return BindByExtensionCore(false, extensions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds the first item in the archive (or the file itself) if the extension matches one of the supplied templates.
|
||||
/// You probably should not use this. use BindSoleItemOf or the archive chooser instead
|
||||
/// </summary>
|
||||
public HawkFile BindFirstOf(params string[] extensions)
|
||||
{
|
||||
return BindByExtensionCore(true, extensions);
|
||||
}
|
||||
|
||||
HawkFile BindByExtensionCore(bool first, params string[] extensions)
|
||||
{
|
||||
if (!rootExists) return this;
|
||||
if (boundStream != null) throw new InvalidOperationException("stream already bound!");
|
||||
|
||||
if (extractor == null)
|
||||
{
|
||||
//open uncompressed file
|
||||
string extension = Path.GetExtension(rootPath).Substring(1).ToUpperInvariant();
|
||||
if (extensions.Length == 0 || extension.In(extensions))
|
||||
{
|
||||
BindRoot();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
var candidates = new List<int>();
|
||||
for (int i = 0; i < extractor.ArchiveFileData.Count; i++)
|
||||
{
|
||||
var e = extractor.ArchiveFileData[i];
|
||||
if (e.IsDirectory) continue;
|
||||
var extension = Path.GetExtension(e.FileName).ToUpperInvariant();
|
||||
extension = extension.TrimStart('.');
|
||||
if (extensions.Length == 0 || extension.In(extensions))
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
BindArchiveMember(i);
|
||||
return this;
|
||||
}
|
||||
candidates.Add(i);
|
||||
}
|
||||
}
|
||||
if (candidates.Count == 1)
|
||||
BindArchiveMember(candidates[0]);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
void ScanArchive()
|
||||
{
|
||||
archiveItems = new List<ArchiveItem>();
|
||||
for (int i = 0; i < extractor.ArchiveFileData.Count; i++)
|
||||
{
|
||||
var afd = extractor.ArchiveFileData[i];
|
||||
if (afd.IsDirectory) continue;
|
||||
var ai = new ArchiveItem {name = FixArchiveFilename(afd.FileName), size = (long) afd.Size, index = i};
|
||||
archiveItems.Add(ai);
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeArchive(string path)
|
||||
{
|
||||
SevenZip.FileChecker.ThrowExceptions = false;
|
||||
int offset;
|
||||
bool isExecutable;
|
||||
if (NonArchiveExtensions.Any(ext => Path.GetExtension(path).Substring(1).ToLower() == ext.ToLower()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SevenZip.FileChecker.CheckSignature(path, out offset, out isExecutable) != SevenZip.InArchiveFormat.None)
|
||||
{
|
||||
extractor = new SevenZip.SevenZipExtractor(path);
|
||||
try
|
||||
{
|
||||
ScanArchive();
|
||||
}
|
||||
catch
|
||||
{
|
||||
extractor.Dispose();
|
||||
extractor = null;
|
||||
archiveItems = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Unbind();
|
||||
|
||||
if (extractor != null) extractor.Dispose();
|
||||
if (rootStream != null) rootStream.Dispose();
|
||||
|
||||
extractor = null;
|
||||
rootStream = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class TurboKey
|
||||
{
|
||||
public void Reset(int downTime, int upTime)
|
||||
{
|
||||
Value = false;
|
||||
_timer = 0;
|
||||
_upTime = upTime;
|
||||
_downTime = downTime;
|
||||
}
|
||||
|
||||
public void Tick(bool down)
|
||||
{
|
||||
if (!down)
|
||||
{
|
||||
Reset(_downTime, _upTime);
|
||||
return;
|
||||
}
|
||||
|
||||
_timer++;
|
||||
|
||||
Value = true;
|
||||
if (_timer > _downTime)
|
||||
Value = false;
|
||||
if(_timer > (_upTime+_downTime))
|
||||
{
|
||||
_timer = 0;
|
||||
Value = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Value;
|
||||
private int _upTime, _downTime, _timer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Client.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Client.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8281b376-a1d5-4157-97b8-dab7246ef4c8")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,101 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class RecentFiles : IEnumerable
|
||||
{
|
||||
private readonly int MAX_RECENT_FILES; //Maximum number of files
|
||||
private readonly List<string> recentlist; //List of recent files
|
||||
|
||||
public bool AutoLoad = false;
|
||||
|
||||
public RecentFiles() : this(8) { }
|
||||
public RecentFiles(int max)
|
||||
{
|
||||
recentlist = new List<string>();
|
||||
MAX_RECENT_FILES = max;
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
return recentlist.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
recentlist.Clear();
|
||||
}
|
||||
|
||||
public bool Empty
|
||||
{
|
||||
get { return recentlist.Count == 0; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return recentlist.Count; }
|
||||
}
|
||||
|
||||
public void Add(string newFile)
|
||||
{
|
||||
for (int x = 0; x < recentlist.Count; x++)
|
||||
{
|
||||
if (string.Compare(newFile, recentlist[x]) == 0)
|
||||
{
|
||||
recentlist.Remove(newFile); //intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place
|
||||
}
|
||||
}
|
||||
recentlist.Insert(0, newFile);
|
||||
if (recentlist.Count > MAX_RECENT_FILES)
|
||||
{
|
||||
recentlist.Remove(recentlist[recentlist.Count - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(string newFile)
|
||||
{
|
||||
bool removed = false;
|
||||
for (int x = 0; x < recentlist.Count; x++)
|
||||
{
|
||||
if (string.Compare(newFile, recentlist[x]) == 0)
|
||||
{
|
||||
recentlist.Remove(newFile); //intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public List<string> GetRecentListTruncated(int length)
|
||||
{
|
||||
return recentlist.Select(t => t.Substring(0, length)).ToList();
|
||||
}
|
||||
|
||||
public string this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (recentlist.Any())
|
||||
{
|
||||
return recentlist[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleAutoLoad()
|
||||
{
|
||||
AutoLoad ^= true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.MultiClient
|
||||
{
|
||||
public class RomGame
|
||||
{
|
||||
public byte[] RomData;
|
||||
public byte[] FileData;
|
||||
public GameInfo GameInfo;
|
||||
public string Extension;
|
||||
|
||||
private const int BankSize = 1024;
|
||||
|
||||
public RomGame() { }
|
||||
|
||||
public RomGame(HawkFile file) : this(file, null) { }
|
||||
|
||||
public RomGame(HawkFile file, string patch)
|
||||
{
|
||||
if (!file.Exists)
|
||||
throw new Exception("The file needs to exist, yo.");
|
||||
|
||||
Extension = file.Extension;
|
||||
|
||||
var stream = file.GetStream();
|
||||
int fileLength = (int)stream.Length;
|
||||
|
||||
//read the entire contents of the file into memory.
|
||||
//unfortunate in the case of large files, but thats what we've got to work with for now.
|
||||
|
||||
// if we're offset exactly 512 bytes from a 1024-byte boundary,
|
||||
// assume we have a header of that size. Otherwise, assume it's just all rom.
|
||||
// Other 'recognized' header sizes may need to be added.
|
||||
int headerOffset = fileLength % BankSize;
|
||||
if (headerOffset.In(0, 512) == false)
|
||||
{
|
||||
Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset);
|
||||
headerOffset = 0;
|
||||
}
|
||||
else if (headerOffset > 0)
|
||||
Console.WriteLine("Assuming header of {0} bytes.", headerOffset);
|
||||
|
||||
//read the entire file into FileData.
|
||||
FileData = new byte[fileLength];
|
||||
stream.Read(FileData, 0, fileLength);
|
||||
|
||||
//if there was no header offset, RomData is equivalent to FileData
|
||||
//(except in cases where the original interleaved file data is necessary.. in that case we'll have problems..
|
||||
//but this whole architecture is not going to withstand every peculiarity and be fast as well.
|
||||
if (headerOffset == 0)
|
||||
{
|
||||
RomData = FileData;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if there was a header offset, read the whole file into FileData and then copy it into RomData (this is unfortunate, in case RomData isnt needed)
|
||||
int romLength = fileLength - headerOffset;
|
||||
RomData = new byte[romLength];
|
||||
Buffer.BlockCopy(FileData, headerOffset, RomData, 0, romLength);
|
||||
}
|
||||
|
||||
if (file.Extension == ".SMD")
|
||||
RomData = DeInterleaveSMD(RomData);
|
||||
|
||||
if (file.Extension == ".Z64" || file.Extension == ".N64" || file.Extension == ".V64")
|
||||
RomData = MutateSwapN64(RomData);
|
||||
|
||||
//note: this will be taking several hashes, of a potentially large amount of data.. yikes!
|
||||
GameInfo = Database.GetGameInfo(RomData, file.Name);
|
||||
|
||||
CheckForPatchOptions();
|
||||
|
||||
if (patch != null)
|
||||
{
|
||||
using (var patchFile = new HawkFile(patch))
|
||||
{
|
||||
patchFile.BindFirstOf("IPS");
|
||||
if (patchFile.IsBound)
|
||||
IPS.Patch(RomData, patchFile.GetStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] DeInterleaveSMD(byte[] source)
|
||||
{
|
||||
// SMD files are interleaved in pages of 16k, with the first 8k containing all
|
||||
// odd bytes and the second 8k containing all even bytes.
|
||||
|
||||
int size = source.Length;
|
||||
if (size > 0x400000) size = 0x400000;
|
||||
int pages = size / 0x4000;
|
||||
byte[] output = new byte[size];
|
||||
|
||||
for (int page = 0; page < pages; page++)
|
||||
{
|
||||
for (int i = 0; i < 0x2000; i++)
|
||||
{
|
||||
output[(page * 0x4000) + (i * 2) + 0] = source[(page * 0x4000) + 0x2000 + i];
|
||||
output[(page * 0x4000) + (i * 2) + 1] = source[(page * 0x4000) + 0x0000 + i];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private unsafe static byte[] MutateSwapN64(byte[] source)
|
||||
{
|
||||
// N64 roms are in one of the following formats:
|
||||
// .Z64 = No swapping
|
||||
// .N64 = Word Swapped
|
||||
// .V64 = Bytse Swapped
|
||||
|
||||
// File extension does not always match the format
|
||||
|
||||
int size = source.Length;
|
||||
|
||||
// V64 format
|
||||
fixed (byte* pSource = &source[0])
|
||||
{
|
||||
if (pSource[0] == 0x37)
|
||||
{
|
||||
for (int i = 0; i < size; i += 2)
|
||||
{
|
||||
byte temp = pSource[i];
|
||||
pSource[i] = pSource[i + 1];
|
||||
pSource[i + 1] = temp;
|
||||
}
|
||||
}
|
||||
// N64 format
|
||||
else if (pSource[0] == 0x40)
|
||||
{
|
||||
for (int i = 0; i < size; i += 4)
|
||||
{
|
||||
//output[i] = source[i + 3];
|
||||
//output[i + 3] = source[i];
|
||||
//output[i + 1] = source[i + 2];
|
||||
//output[i + 2] = source[i + 1];
|
||||
|
||||
byte temp = pSource[i];
|
||||
pSource[i] = source[i + 3];
|
||||
pSource[i + 3] = temp;
|
||||
|
||||
temp = pSource[i + 1];
|
||||
pSource[i + 1] = pSource[i + 2];
|
||||
pSource[i + 2] = temp;
|
||||
}
|
||||
}
|
||||
// Z64 format (or some other unknown format)
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private void CheckForPatchOptions()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (GameInfo["PatchBytes"])
|
||||
{
|
||||
string args = GameInfo.OptionValue("PatchBytes");
|
||||
foreach (var val in args.Split(','))
|
||||
{
|
||||
var split = val.Split(':');
|
||||
int offset = int.Parse(split[0], NumberStyles.HexNumber);
|
||||
byte value = byte.Parse(split[1], NumberStyles.HexNumber);
|
||||
RomData[offset] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { } // No need for errors in patching to propagate.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class Binding
|
||||
{
|
||||
public string DisplayName;
|
||||
public string Bindings;
|
||||
public string DefaultBinding;
|
||||
public string TabGroup;
|
||||
public int Ordinal = 0;
|
||||
}
|
||||
|
||||
public class BindingCollection : IEnumerable<Binding>
|
||||
{
|
||||
public List<Binding> Bindings { get; private set; }
|
||||
|
||||
public BindingCollection()
|
||||
{
|
||||
Bindings = new List<Binding>();
|
||||
Bindings.AddRange(DefaultValues);
|
||||
}
|
||||
|
||||
public void Add(Binding b)
|
||||
{
|
||||
Bindings.Add(b);
|
||||
}
|
||||
|
||||
public IEnumerator<Binding> GetEnumerator()
|
||||
{
|
||||
return Bindings.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Binding this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Bindings.FirstOrDefault(x => x.DisplayName == index) ?? new Binding();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveWithDefaults()
|
||||
{
|
||||
//Add missing entries
|
||||
foreach (Binding default_binding in DefaultValues)
|
||||
{
|
||||
var binding = Bindings.FirstOrDefault(x => x.DisplayName == default_binding.DisplayName);
|
||||
if (binding == null)
|
||||
{
|
||||
Bindings.Add(default_binding);
|
||||
}
|
||||
}
|
||||
|
||||
List<Binding> entriesToRemove = (from entry in Bindings let binding = DefaultValues.FirstOrDefault(x => x.DisplayName == entry.DisplayName) where binding == null select entry).ToList();
|
||||
|
||||
//Remove entries that no longer exist in defaults
|
||||
|
||||
foreach (Binding entry in entriesToRemove)
|
||||
{
|
||||
Bindings.Remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Binding> DefaultValues
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<Binding>
|
||||
{
|
||||
//General
|
||||
new Binding { DisplayName = "Frame Advance", Bindings = "F", TabGroup = "General", DefaultBinding = "F", Ordinal = 0 },
|
||||
new Binding { DisplayName = "Rewind", Bindings = "Shift+R, J1 B7, X1 Left Trigger", TabGroup = "General", DefaultBinding = "Shift+R, J1 B7, X1 Left Trigger", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Pause", Bindings = "Pause", TabGroup = "General", DefaultBinding = "Pause", Ordinal = 2 },
|
||||
new Binding { DisplayName = "Fast Forward", Bindings = "Tab, J1 B8, X1 Right Trigger", TabGroup = "General", DefaultBinding = "Tab, J1 B8, X1 Right Trigger", Ordinal = 3 },
|
||||
new Binding { DisplayName = "Turbo", Bindings = "Shift+Tab", TabGroup = "General", DefaultBinding = "Shift+Tab", Ordinal = 4 },
|
||||
new Binding { DisplayName = "Toggle Throttle", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 5 },
|
||||
new Binding { DisplayName = "Soft Reset", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 6 },
|
||||
new Binding { DisplayName = "Hard Reset", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 7 },
|
||||
new Binding { DisplayName = "Quick Load", Bindings = "P", TabGroup = "General", DefaultBinding = "P", Ordinal = 8 },
|
||||
new Binding { DisplayName = "Quick Save", Bindings = "I", TabGroup = "General", DefaultBinding = "I", Ordinal = 9 },
|
||||
new Binding { DisplayName = "Autohold", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 10 },
|
||||
new Binding { DisplayName = "Clear Autohold", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 11 },
|
||||
new Binding { DisplayName = "Screenshot", Bindings = "F12", TabGroup = "General", DefaultBinding = "F12", Ordinal = 12 },
|
||||
new Binding { DisplayName = "Full Screen", Bindings = "Alt+Return", TabGroup = "General", DefaultBinding = "Alt+Return", Ordinal = 13 },
|
||||
new Binding { DisplayName = "Open ROM", Bindings = "Ctrl+O", TabGroup = "General", DefaultBinding = "Ctrl+O", Ordinal = 14 },
|
||||
new Binding { DisplayName = "Close ROM", Bindings = "Ctrl+W", TabGroup = "General", DefaultBinding = "Ctrl+W", Ordinal = 15 },
|
||||
new Binding { DisplayName = "Display FPS", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 16 },
|
||||
new Binding { DisplayName = "Frame Counter", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 17 },
|
||||
new Binding { DisplayName = "Lag Counter", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 18 },
|
||||
new Binding { DisplayName = "Input Display", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 19 },
|
||||
new Binding { DisplayName = "Toggle BG Input", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 20 },
|
||||
new Binding { DisplayName = "Toggle Menu", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 21 },
|
||||
new Binding { DisplayName = "Volume Up", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 22 },
|
||||
new Binding { DisplayName = "Volume Down", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 23 },
|
||||
new Binding { DisplayName = "Record A/V", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 24 },
|
||||
new Binding { DisplayName = "Stop A/V", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 25 },
|
||||
new Binding { DisplayName = "Larger Window", Bindings = "Alt+UpArrow", TabGroup = "General", DefaultBinding = "Alt+UpArrow", Ordinal = 26 },
|
||||
new Binding { DisplayName = "Smaller Window", Bindings = "Alt+DownArrow", TabGroup = "General", DefaultBinding = "Alt+DownArrow", Ordinal = 27 },
|
||||
new Binding { DisplayName = "Increase Speed", Bindings = "Equals", TabGroup = "General", DefaultBinding = "Equals", Ordinal = 28 },
|
||||
new Binding { DisplayName = "Decrease Speed", Bindings = "Minus", TabGroup = "General", DefaultBinding = "Minus", Ordinal = 29 },
|
||||
new Binding { DisplayName = "Reboot Core", Bindings = "Ctrl+R", TabGroup = "General", DefaultBinding = "Ctrl+R", Ordinal = 30 },
|
||||
new Binding { DisplayName = "Autofire", Bindings = "", TabGroup = "General", DefaultBinding = "", Ordinal = 31 },
|
||||
|
||||
//Save States
|
||||
new Binding { DisplayName = "Save State 0", Bindings = "Shift+F10", TabGroup = "Save States", DefaultBinding = "Shift+F10", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Save State 1", Bindings = "Shift+F1", TabGroup = "Save States", DefaultBinding = "Shift+F1", Ordinal = 2 },
|
||||
new Binding { DisplayName = "Save State 2", Bindings = "Shift+F2", TabGroup = "Save States", DefaultBinding = "Shift+F2", Ordinal = 3 },
|
||||
new Binding { DisplayName = "Save State 3", Bindings = "Shift+F3", TabGroup = "Save States", DefaultBinding = "Shift+F3", Ordinal = 4 },
|
||||
new Binding { DisplayName = "Save State 4", Bindings = "Shift+F4", TabGroup = "Save States", DefaultBinding = "Shift+F4", Ordinal = 5 },
|
||||
new Binding { DisplayName = "Save State 5", Bindings = "Shift+F5", TabGroup = "Save States", DefaultBinding = "Shift+F5", Ordinal = 6 },
|
||||
new Binding { DisplayName = "Save State 6", Bindings = "Shift+F6", TabGroup = "Save States", DefaultBinding = "Shift+F6", Ordinal = 7 },
|
||||
new Binding { DisplayName = "Save State 7", Bindings = "Shift+F7", TabGroup = "Save States", DefaultBinding = "Shift+F7", Ordinal = 8 },
|
||||
new Binding { DisplayName = "Save State 8", Bindings = "Shift+F8", TabGroup = "Save States", DefaultBinding = "Shift+F8", Ordinal = 9 },
|
||||
new Binding { DisplayName = "Save State 9", Bindings = "Shift+F9", TabGroup = "Save States", DefaultBinding = "Shift+F9", Ordinal = 10 },
|
||||
new Binding { DisplayName = "Load State 0", Bindings = "F10", TabGroup = "Save States", DefaultBinding = "F10", Ordinal = 11 },
|
||||
new Binding { DisplayName = "Load State 1", Bindings = "F1", TabGroup = "Save States", DefaultBinding = "F1", Ordinal = 12 },
|
||||
new Binding { DisplayName = "Load State 2", Bindings = "F2", TabGroup = "Save States", DefaultBinding = "F2", Ordinal = 13 },
|
||||
new Binding { DisplayName = "Load State 3", Bindings = "F3", TabGroup = "Save States", DefaultBinding = "F3", Ordinal = 14 },
|
||||
new Binding { DisplayName = "Load State 4", Bindings = "F4", TabGroup = "Save States", DefaultBinding = "F4", Ordinal = 15 },
|
||||
new Binding { DisplayName = "Load State 5", Bindings = "F5", TabGroup = "Save States", DefaultBinding = "F5", Ordinal = 16 },
|
||||
new Binding { DisplayName = "Load State 6", Bindings = "F6", TabGroup = "Save States", DefaultBinding = "F6", Ordinal = 17 },
|
||||
new Binding { DisplayName = "Load State 7", Bindings = "F7", TabGroup = "Save States", DefaultBinding = "F7", Ordinal = 18 },
|
||||
new Binding { DisplayName = "Load State 8", Bindings = "F8", TabGroup = "Save States", DefaultBinding = "F8", Ordinal = 19 },
|
||||
new Binding { DisplayName = "Load State 9", Bindings = "F9", TabGroup = "Save States", DefaultBinding = "F9", Ordinal = 20 },
|
||||
new Binding { DisplayName = "Select State 0", Bindings = "D0", TabGroup = "Save States", DefaultBinding = "D0", Ordinal = 21 },
|
||||
new Binding { DisplayName = "Select State 1", Bindings = "D1", TabGroup = "Save States", DefaultBinding = "D1", Ordinal = 22 },
|
||||
new Binding { DisplayName = "Select State 2", Bindings = "D2", TabGroup = "Save States", DefaultBinding = "D2", Ordinal = 23 },
|
||||
new Binding { DisplayName = "Select State 3", Bindings = "D3", TabGroup = "Save States", DefaultBinding = "D3", Ordinal = 24 },
|
||||
new Binding { DisplayName = "Select State 4", Bindings = "D4", TabGroup = "Save States", DefaultBinding = "D4", Ordinal = 25 },
|
||||
new Binding { DisplayName = "Select State 5", Bindings = "D5", TabGroup = "Save States", DefaultBinding = "D5", Ordinal = 26 },
|
||||
new Binding { DisplayName = "Select State 6", Bindings = "D6", TabGroup = "Save States", DefaultBinding = "D6", Ordinal = 27 },
|
||||
new Binding { DisplayName = "Select State 7", Bindings = "D7", TabGroup = "Save States", DefaultBinding = "D7", Ordinal = 28 },
|
||||
new Binding { DisplayName = "Select State 8", Bindings = "D8", TabGroup = "Save States", DefaultBinding = "D8", Ordinal = 29 },
|
||||
new Binding { DisplayName = "Select State 9", Bindings = "D9", TabGroup = "Save States", DefaultBinding = "D9", Ordinal = 30 },
|
||||
new Binding { DisplayName = "Save Named State", Bindings = "", TabGroup = "Save States", DefaultBinding = "", Ordinal = 31 },
|
||||
new Binding { DisplayName = "Load Named State", Bindings = "", TabGroup = "Save States", DefaultBinding = "", Ordinal = 32 },
|
||||
new Binding { DisplayName = "Previous Slot", Bindings = "", TabGroup = "Save States", DefaultBinding = "", Ordinal = 33 },
|
||||
new Binding { DisplayName = "Next Slot", Bindings = "", TabGroup = "Save States", DefaultBinding = "", Ordinal = 34 },
|
||||
|
||||
//Movie
|
||||
new Binding { DisplayName = "Toggle read-only", Bindings = "Q", TabGroup = "Movie", DefaultBinding = "Q", Ordinal = 0 },
|
||||
new Binding { DisplayName = "Play Movie", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Record Movie", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 2 },
|
||||
new Binding { DisplayName = "Stop Movie", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 3 },
|
||||
new Binding { DisplayName = "Play from beginning", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 4 },
|
||||
new Binding { DisplayName = "Save Movie", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 5 },
|
||||
new Binding { DisplayName = "Toggle MultiTrack", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 6 },
|
||||
new Binding { DisplayName = "MT Select All", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 7 },
|
||||
new Binding { DisplayName = "MT Select None", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 8 },
|
||||
new Binding { DisplayName = "MT Increment Player", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 9 },
|
||||
new Binding { DisplayName = "MT Decrement Player", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 10 },
|
||||
new Binding { DisplayName = "Movie Poke", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 11 },
|
||||
new Binding { DisplayName = "Scrub Input", Bindings = "", TabGroup = "Movie", DefaultBinding = "", Ordinal = 12 },
|
||||
|
||||
//Tools
|
||||
new Binding { DisplayName = "Ram Watch", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 0 },
|
||||
new Binding { DisplayName = "Ram Search", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Hex Editor", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 3 },
|
||||
new Binding { DisplayName = "Trace Logger", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 4 },
|
||||
new Binding { DisplayName = "Lua Console", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 5 },
|
||||
new Binding { DisplayName = "Cheats", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 6 },
|
||||
new Binding { DisplayName = "TAStudio", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 7 },
|
||||
new Binding { DisplayName = "ToolBox", Bindings = "T", TabGroup = "Tools", DefaultBinding = "", Ordinal = 8 },
|
||||
new Binding { DisplayName = "Virtual Pad", Bindings = "", TabGroup = "Tools", DefaultBinding = "", Ordinal = 9 },
|
||||
|
||||
new Binding { DisplayName = "New Search", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 10 },
|
||||
new Binding { DisplayName = "Do Search", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 11 },
|
||||
new Binding { DisplayName = "Previous Compare To", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 12 },
|
||||
new Binding { DisplayName = "Next Compare To", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 13 },
|
||||
new Binding { DisplayName = "Previous Operator", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 14 },
|
||||
new Binding { DisplayName = "Next Operator", Bindings = "", TabGroup = "Ram Search", DefaultBinding = "", Ordinal = 15 },
|
||||
|
||||
//SNES
|
||||
new Binding { DisplayName = "Toggle BG 1", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 0 },
|
||||
new Binding { DisplayName = "Toggle BG 2", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Toggle BG 3", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 2 },
|
||||
new Binding { DisplayName = "Toggle BG 4", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 3 },
|
||||
new Binding { DisplayName = "Toggle OBJ 1", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 4 },
|
||||
new Binding { DisplayName = "Toggle OBJ 2", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 5 },
|
||||
new Binding { DisplayName = "Toggle OBJ 3", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 6 },
|
||||
new Binding { DisplayName = "Toggle OBJ 4", Bindings = "", TabGroup = "SNES", DefaultBinding = "", Ordinal = 7 },
|
||||
|
||||
//Analog
|
||||
new Binding { DisplayName = "Y Up Small", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 0 },
|
||||
new Binding { DisplayName = "Y Up Large", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 1 },
|
||||
new Binding { DisplayName = "Y Down Small", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 2 },
|
||||
new Binding { DisplayName = "Y Down Large", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 3 },
|
||||
new Binding { DisplayName = "X Up Small", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 4 },
|
||||
new Binding { DisplayName = "X Up Large", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 5 },
|
||||
new Binding { DisplayName = "X Down Small", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 6 },
|
||||
new Binding { DisplayName = "X Down Large", Bindings = "", TabGroup = "Analog", DefaultBinding = "", Ordinal = 7 },
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public static class ConfigService
|
||||
{
|
||||
public static T Load<T>(string filepath, T currentConfig) where T : new()
|
||||
{
|
||||
T config = new T();
|
||||
|
||||
try
|
||||
{
|
||||
var file = new FileInfo(filepath);
|
||||
if (file.Exists)
|
||||
using (var reader = file.OpenText())
|
||||
{
|
||||
var s = new JsonSerializer {SuppressMissingMemberException = true, SuppressDuplicateMemberException = true};
|
||||
var r = new JsonReader(reader);
|
||||
config = (T)s.Deserialize(r, typeof(T));
|
||||
}
|
||||
}
|
||||
catch (Exception e) { /*TODO MessageBox.Show(e.ToString(), "Config Error"); */ }
|
||||
if (config == null) return new T();
|
||||
|
||||
//patch up arrays in the config with the minimum number of things
|
||||
foreach(var fi in typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
|
||||
if (fi.FieldType.IsArray)
|
||||
{
|
||||
Array aold = fi.GetValue(currentConfig) as Array;
|
||||
Array anew = fi.GetValue(config) as Array;
|
||||
if (aold.Length == anew.Length) continue;
|
||||
|
||||
//create an array of the right size
|
||||
Array acreate = Array.CreateInstance(fi.FieldType.GetElementType(), Math.Max(aold.Length,anew.Length));
|
||||
|
||||
//copy the old values in, (presumably the defaults), and then copy the new ones on top
|
||||
Array.Copy(aold, acreate, Math.Min(aold.Length,acreate.Length));
|
||||
Array.Copy(anew, acreate, Math.Min(anew.Length, acreate.Length));
|
||||
|
||||
//stash it into the config struct
|
||||
fi.SetValue(config, acreate);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static void Save(string filepath, object config)
|
||||
{
|
||||
var file = new FileInfo(filepath);
|
||||
using (var writer = file.CreateText())
|
||||
{
|
||||
var s = new JsonSerializer();
|
||||
var w = new JsonWriter(writer) { Formatting = Formatting.Indented };
|
||||
s.Serialize(w, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Includes helper functions to validate user input
|
||||
/// </summary>
|
||||
public static class InputValidate
|
||||
{
|
||||
public static bool IsValidUnsignedNumber(string Str)
|
||||
{
|
||||
char[] input = (Str.ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] < 47 || bc[0] > 58)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidUnsignedNumber(char c)
|
||||
{
|
||||
if (c < 47 || c > 58)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates all chars are 0-9 or a dash as the first value
|
||||
/// </summary>
|
||||
/// <param name="Str"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidSignedNumber(string Str)
|
||||
{
|
||||
char[] input = (Str.Trim().ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] > 58)
|
||||
return false;
|
||||
|
||||
if (bc[0] < 47)
|
||||
{
|
||||
if (bc[0] == 45 && x == 0)
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidSignedNumber(char c)
|
||||
{
|
||||
if (c == 45) return true;
|
||||
|
||||
if (c < 47 || c > 58)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// validates is a Hex number 0-9, A-F (must be capital letters)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidHexNumber(string Str)
|
||||
{
|
||||
char[] input = (Str.ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] < 47) //0
|
||||
return false;
|
||||
if (bc[0] > 58) //9
|
||||
{
|
||||
if (bc[0] < 65) //A
|
||||
return false;
|
||||
|
||||
if (bc[0] > 70) //F
|
||||
{
|
||||
if (bc[0] < 97 || bc[0] > 102) //a-f
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidHexNumber(char c)
|
||||
{
|
||||
if (c < 47) return false; //0
|
||||
|
||||
if (c > 58) //9
|
||||
{
|
||||
if (c < 65) //A
|
||||
return false;
|
||||
|
||||
if (c > 70) //F
|
||||
{
|
||||
if (c < 97 || c > 102) //a-f
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes any string and removes any value that is not a valid hex value (0-9, a-f, A-F), returns the remaining characters in uppercase
|
||||
/// </summary>
|
||||
/// <param name="raw"></param>
|
||||
/// <returns></returns>
|
||||
public static string DoHexString(string raw)
|
||||
{
|
||||
raw = raw.ToUpper();
|
||||
StringBuilder output = new StringBuilder();
|
||||
foreach (char x in raw)
|
||||
{
|
||||
if (x >= 'A' && x <= 'F')
|
||||
{
|
||||
output.Append(x);
|
||||
}
|
||||
else if (x >= '0' && x <= '9')
|
||||
{
|
||||
output.Append(x);
|
||||
}
|
||||
}
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
|
||||
public static bool IsValidBinaryNumber(string s)
|
||||
{
|
||||
char[] input = (s.ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] != 48 && bc[0] != 49) //0 or 1
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidBinaryNumber(char c)
|
||||
{
|
||||
return (c == 48 || c == 49);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates all chars are 0-9 or decimal
|
||||
/// </summary>
|
||||
/// <param name="Str"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidFixedPointNumber(string Str)
|
||||
{
|
||||
if (StringHelpers.HowMany(Str, '.') > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] input = (Str.Trim().ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] > 58)
|
||||
return false;
|
||||
|
||||
if (bc[0] == 46)
|
||||
continue;
|
||||
|
||||
if (bc[0] < 48)
|
||||
{
|
||||
if (bc[0] == 45 && x == 0)
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidFixedPointNumber(char c)
|
||||
{
|
||||
if (c == 46 || c == 45) return true;
|
||||
|
||||
if (c < 48 || c > 58)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates all chars are 0-9 or decimal or dash as the first character
|
||||
/// </summary>
|
||||
/// <param name="Str"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidDecimalNumber(string Str)
|
||||
{
|
||||
if (StringHelpers.HowMany(Str, '.') > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] input = (Str.Trim().ToCharArray());
|
||||
ASCIIEncoding AE = new ASCIIEncoding();
|
||||
// Check each character in the new label to determine if it is a number.
|
||||
for (int x = 0; x < input.Length; x++)
|
||||
{
|
||||
// Encode the character from the character array to its ASCII code.
|
||||
byte[] bc = AE.GetBytes(input[x].ToString());
|
||||
|
||||
// Determine if the ASCII code is within the valid range of numerical values.
|
||||
if (bc[0] > 58)
|
||||
return false;
|
||||
|
||||
if (bc[0] == 46)
|
||||
continue;
|
||||
|
||||
if (bc[0] < 48)
|
||||
{
|
||||
if (bc[0] == 45 && x == 0)
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidDecimalNumber(char c)
|
||||
{
|
||||
if (c == 45 || c == 46) //45 = dash, 46 = dot
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (c < 48 || c > 58)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public static class StringHelpers
|
||||
{
|
||||
public static int HowMany(string str, char c)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(str))
|
||||
{
|
||||
return str.Count(t => t == c);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int HowMany(string str, string s)
|
||||
{
|
||||
int count = 0;
|
||||
for (int x = 0; x < (str.Length - s.Length); x++)
|
||||
{
|
||||
if (str.Substring(x, s.Length) == s)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: put it in its own file
|
||||
public static class IntHelpers //TODO: a less lame name
|
||||
{
|
||||
public static int GetNumDigits(Int32 i)
|
||||
{
|
||||
//if (i == 0) return 0;
|
||||
//if (i < 0x10) return 1;
|
||||
if (i < 0x100) return 2;
|
||||
//if (i < 0x1000) return 3; //adelikat: let's only do even numbers
|
||||
if (i < 0x10000) return 4;
|
||||
if (i < 0x1000000) return 6;
|
||||
else return 8;
|
||||
}
|
||||
|
||||
public static uint MaxHexValueFromMaxDigits(Int32 i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return 0xF;
|
||||
case 2:
|
||||
return 0xFF;
|
||||
case 3:
|
||||
return 0xFFF;
|
||||
case 4:
|
||||
return 0xFFFF;
|
||||
case 5:
|
||||
return 0xFFFFF;
|
||||
case 6:
|
||||
return 0xFFFFFF;
|
||||
case 7:
|
||||
return 0xFFFFFFF;
|
||||
case 8:
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return int.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// will hold buttons for 1 frame and then release them. (Calling Click() from your button click is what you want to do)
|
||||
/// TODO - should the duration be controllable?
|
||||
/// </summary>
|
||||
public class ClickyVirtualPadController : IController
|
||||
{
|
||||
public ControllerDefinition Type { get; set; }
|
||||
public bool this[string button] { get { return IsPressed(button); } }
|
||||
public float GetFloat(string name) { return 0.0f; } //TODO
|
||||
public void UpdateControls(int frame) { }
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
return Pressed.Contains(button);
|
||||
}
|
||||
/// <summary>
|
||||
/// call this once per frame to do the timekeeping for the hold and release
|
||||
/// </summary>
|
||||
public void FrameTick()
|
||||
{
|
||||
Pressed.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// call this to hold the button down for one frame
|
||||
/// </summary>
|
||||
public void Click(string button)
|
||||
{
|
||||
Pressed.Add(button);
|
||||
}
|
||||
|
||||
public void Unclick(string button)
|
||||
{
|
||||
Pressed.Remove(button);
|
||||
}
|
||||
|
||||
public void Toggle(string button)
|
||||
{
|
||||
if (IsPressed(button))
|
||||
{
|
||||
Pressed.Remove(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pressed.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
readonly HashSet<string> Pressed = new HashSet<string>();
|
||||
}
|
||||
|
||||
//filters input for things called Up and Down while considering the client's AllowUD_LR option.
|
||||
//this is a bit gross but it is unclear how to do it more nicely
|
||||
public class UD_LR_ControllerAdapter : IController
|
||||
{
|
||||
public ControllerDefinition Type { get { return Source.Type; } }
|
||||
public IController Source;
|
||||
|
||||
public bool this[string button] { get { return IsPressed(button); } }
|
||||
// the float format implies no U+D and no L+R no matter what, so just passthru
|
||||
public float GetFloat(string name) { return Source.GetFloat(name); }
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
if (Global.Config.AllowUD_LR)
|
||||
{
|
||||
return Source.IsPressed(button);
|
||||
}
|
||||
|
||||
string prefix;
|
||||
|
||||
if (button.Contains("Down") && !button.Contains(" C "))
|
||||
{
|
||||
prefix = button.GetPrecedingString("Down");
|
||||
if (Source.IsPressed(prefix + "Up"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (button.Contains("Right") && !button.Contains(" C "))
|
||||
{
|
||||
prefix = button.GetPrecedingString("Right");
|
||||
if (Source.IsPressed(prefix + "Left"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Source.IsPressed(button);
|
||||
}
|
||||
}
|
||||
|
||||
public class SimpleController : IController
|
||||
{
|
||||
public ControllerDefinition Type { get; set; }
|
||||
|
||||
protected WorkingDictionary<string, bool> Buttons = new WorkingDictionary<string, bool>();
|
||||
protected WorkingDictionary<string, float> Floats = new WorkingDictionary<string, float>();
|
||||
public virtual bool this[string button] { get { return Buttons[button]; } set { Buttons[button] = value; } }
|
||||
public virtual bool IsPressed(string button) { return this[button]; }
|
||||
public float GetFloat(string name) { return Floats[name]; }
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
public IEnumerable<KeyValuePair<string, bool>> BoolButtons()
|
||||
{
|
||||
foreach (var kvp in Buttons) yield return kvp;
|
||||
}
|
||||
|
||||
public virtual void LatchFrom(IController source)
|
||||
{
|
||||
foreach (string button in source.Type.BoolButtons)
|
||||
{
|
||||
Buttons[button] = source[button];
|
||||
}
|
||||
}
|
||||
|
||||
public void AcceptNewFloats(IEnumerable<Tuple<string, float>> NewValues)
|
||||
{
|
||||
foreach (var sv in NewValues)
|
||||
Floats[sv.Item1] = sv.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
public class ORAdapter : IController
|
||||
{
|
||||
public bool IsPressed(string button) { return this[button]; }
|
||||
// pass floats solely from the original source
|
||||
// this works in the code because SourceOr is the autofire controller
|
||||
public float GetFloat(string name) { return Source.GetFloat(name); }
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
public IController Source;
|
||||
public IController SourceOr;
|
||||
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
|
||||
|
||||
public bool this[string button]
|
||||
{
|
||||
get
|
||||
{
|
||||
bool source = Source[button] | SourceOr[button];
|
||||
return source;
|
||||
}
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ForceOffAdaptor : IController
|
||||
{
|
||||
public bool IsPressed(string button) { return this[button]; }
|
||||
// what exactly would we want to do here with floats?
|
||||
// ForceOffAdaptor is only used by lua, and the code there looks like a big mess...
|
||||
public float GetFloat(string name) { return Source.GetFloat(name); }
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
protected HashSet<string> stickySet = new HashSet<string>();
|
||||
public IController Source;
|
||||
public IController SourceOr;
|
||||
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
|
||||
|
||||
public bool this[string button]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (stickySet.Contains(button))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Source[button];
|
||||
}
|
||||
}
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
public void SetSticky(string button, bool isSticky)
|
||||
{
|
||||
if (isSticky)
|
||||
stickySet.Add(button);
|
||||
else stickySet.Remove(button);
|
||||
}
|
||||
}
|
||||
|
||||
public class StickyXORAdapter : IController
|
||||
{
|
||||
protected HashSet<string> stickySet = new HashSet<string>();
|
||||
public IController Source;
|
||||
|
||||
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
|
||||
public bool Locked = false; //Pretty much a hack,
|
||||
|
||||
public bool IsPressed(string button) { return this[button]; }
|
||||
|
||||
// if SetFloat() is called (typically virtual pads), then that float will entirely override the Source input
|
||||
// otherwise, the source is passed thru.
|
||||
WorkingDictionary<string,float?> FloatSet = new WorkingDictionary<string,float?>();
|
||||
public void SetFloat(string name, float? value)
|
||||
{
|
||||
if (value.HasValue)
|
||||
FloatSet[name] = value;
|
||||
else FloatSet.Remove(name);
|
||||
}
|
||||
public float GetFloat(string name)
|
||||
{
|
||||
return FloatSet[name] ?? Source.GetFloat(name);
|
||||
}
|
||||
public void ClearStickyFloats()
|
||||
{
|
||||
FloatSet.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
public bool this[string button] {
|
||||
get
|
||||
{
|
||||
bool source = Source[button];
|
||||
if (source)
|
||||
{
|
||||
}
|
||||
source ^= stickySet.Contains(button);
|
||||
return source;
|
||||
}
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
public void SetSticky(string button, bool isSticky)
|
||||
{
|
||||
if(isSticky)
|
||||
stickySet.Add(button);
|
||||
else stickySet.Remove(button);
|
||||
}
|
||||
|
||||
public bool IsSticky(string button)
|
||||
{
|
||||
return stickySet.Contains(button);
|
||||
}
|
||||
|
||||
public HashSet<string> CurrentStickies
|
||||
{
|
||||
get
|
||||
{
|
||||
return stickySet;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearStickies()
|
||||
{
|
||||
stickySet.Clear();
|
||||
}
|
||||
|
||||
public void MassToggleStickyState(List<string> buttons)
|
||||
{
|
||||
foreach (string button in buttons)
|
||||
{
|
||||
if (!JustPressed.Contains(button))
|
||||
{
|
||||
if (stickySet.Contains(button))
|
||||
{
|
||||
stickySet.Remove(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
stickySet.Add(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
JustPressed = buttons;
|
||||
}
|
||||
|
||||
private List<string> JustPressed = new List<string>();
|
||||
}
|
||||
|
||||
public class AutoFireStickyXORAdapter : IController
|
||||
{
|
||||
public int On { get; set; }
|
||||
public int Off { get; set; }
|
||||
public WorkingDictionary<string, int> buttonStarts = new WorkingDictionary<string, int>();
|
||||
|
||||
private readonly HashSet<string> stickySet = new HashSet<string>();
|
||||
|
||||
public IController Source;
|
||||
|
||||
public void SetOnOffPatternFromConfig()
|
||||
{
|
||||
On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
|
||||
Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
|
||||
}
|
||||
|
||||
public AutoFireStickyXORAdapter()
|
||||
{
|
||||
//On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
|
||||
//Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
|
||||
On = 1;
|
||||
Off = 1;
|
||||
}
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
if (stickySet.Contains(button))
|
||||
{
|
||||
int a = (Global.Emulator.Frame - buttonStarts[button]) % (On + Off);
|
||||
if (a < On)
|
||||
return this[button];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Source[button];
|
||||
}
|
||||
}
|
||||
|
||||
public bool this[string button]
|
||||
{
|
||||
get
|
||||
{
|
||||
bool source = Source[button];
|
||||
if (source)
|
||||
{
|
||||
}
|
||||
if (stickySet.Contains(button))
|
||||
{
|
||||
|
||||
|
||||
int a = (Global.Emulator.Frame - buttonStarts[button]) % (On + Off);
|
||||
if (a < On)
|
||||
{
|
||||
source ^= true;
|
||||
}
|
||||
else
|
||||
{
|
||||
source ^= false;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
|
||||
public bool Locked = false; //Pretty much a hack,
|
||||
|
||||
// dumb passthrough for floats, because autofire doesn't care about them
|
||||
public float GetFloat(string name) { return Source.GetFloat(name); }
|
||||
public void UpdateControls(int frame) { }
|
||||
|
||||
public void SetSticky(string button, bool isSticky)
|
||||
{
|
||||
if (isSticky)
|
||||
stickySet.Add(button);
|
||||
else stickySet.Remove(button);
|
||||
}
|
||||
|
||||
public bool IsSticky(string button)
|
||||
{
|
||||
return stickySet.Contains(button);
|
||||
}
|
||||
|
||||
public HashSet<string> CurrentStickies
|
||||
{
|
||||
get
|
||||
{
|
||||
return stickySet;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearStickies()
|
||||
{
|
||||
stickySet.Clear();
|
||||
}
|
||||
|
||||
public void MassToggleStickyState(List<string> buttons)
|
||||
{
|
||||
foreach (string button in buttons)
|
||||
{
|
||||
if (!JustPressed.Contains(button))
|
||||
{
|
||||
if (stickySet.Contains(button))
|
||||
{
|
||||
stickySet.Remove(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
stickySet.Add(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
JustPressed = buttons;
|
||||
}
|
||||
|
||||
private List<string> JustPressed = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// just copies source to sink, or returns whatever a NullController would if it is disconnected. useful for immovable hardpoints.
|
||||
/// </summary>
|
||||
public class CopyControllerAdapter : IController
|
||||
{
|
||||
public IController Source;
|
||||
|
||||
private readonly NullController _null = new NullController();
|
||||
|
||||
IController Curr
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Source == null) return _null;
|
||||
else return Source;
|
||||
}
|
||||
}
|
||||
|
||||
public ControllerDefinition Type { get { return Curr.Type; } }
|
||||
public bool this[string button] { get { return Curr[button]; } }
|
||||
public bool IsPressed(string button) { return Curr.IsPressed(button); }
|
||||
public float GetFloat(string name) { return Curr.GetFloat(name); }
|
||||
public void UpdateControls(int frame) { Curr.UpdateControls(frame); }
|
||||
}
|
||||
|
||||
class ButtonNameParser
|
||||
{
|
||||
ButtonNameParser()
|
||||
{
|
||||
}
|
||||
|
||||
public static ButtonNameParser Parse(string button)
|
||||
{
|
||||
//see if we're being asked for a button that we know how to rewire
|
||||
string[] parts = button.Split(' ');
|
||||
if (parts.Length < 2) return null;
|
||||
if (parts[0][0] != 'P') return null;
|
||||
int player;
|
||||
if (!int.TryParse(parts[0].Substring(1), out player))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ButtonNameParser { PlayerNum = player, ButtonPart = button.Substring(parts[0].Length + 1) };
|
||||
}
|
||||
}
|
||||
|
||||
public int PlayerNum;
|
||||
public string ButtonPart;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("P{0} {1}", PlayerNum, ButtonPart);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rewires player1 controls to playerN
|
||||
/// </summary>
|
||||
public class MultitrackRewiringControllerAdapter : IController
|
||||
{
|
||||
public IController Source;
|
||||
public int PlayerSource = 1;
|
||||
public int PlayerTargetMask = 0;
|
||||
|
||||
public ControllerDefinition Type { get { return Source.Type; } }
|
||||
public bool this[string button] { get { return IsPressed(button); } }
|
||||
// floats can be player number remapped just like boolbuttons
|
||||
public float GetFloat(string name) { return Source.GetFloat(RemapButtonName(name)); }
|
||||
public void UpdateControls(int frame) { Source.UpdateControls(frame); }
|
||||
|
||||
string RemapButtonName(string button)
|
||||
{
|
||||
//do we even have a source?
|
||||
if (PlayerSource == -1) return button;
|
||||
|
||||
//see if we're being asked for a button that we know how to rewire
|
||||
ButtonNameParser bnp = ButtonNameParser.Parse(button);
|
||||
if (bnp == null) return button;
|
||||
|
||||
//ok, this looks like a normal `P1 Button` type thing. we can handle it
|
||||
//were we supposed to replace this one?
|
||||
int foundPlayerMask = (1 << bnp.PlayerNum);
|
||||
if ((PlayerTargetMask & foundPlayerMask) == 0) return button;
|
||||
//ok, we were. swap out the source player and then grab his button
|
||||
bnp.PlayerNum = PlayerSource;
|
||||
return bnp.ToString();
|
||||
}
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
return Source.IsPressed(RemapButtonName(button));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//not being used..
|
||||
|
||||
///// <summary>
|
||||
///// adapts an IController to force some buttons to a different state.
|
||||
///// unforced button states will flow through to the adaptee
|
||||
///// </summary>
|
||||
//public class ForceControllerAdapter : IController
|
||||
//{
|
||||
// public IController Controller;
|
||||
|
||||
// public Dictionary<string, bool> Forces = new Dictionary<string, bool>();
|
||||
// public void Clear()
|
||||
// {
|
||||
// Forces.Clear();
|
||||
// }
|
||||
|
||||
// public ControllerDefinition Type { get { return Controller.Type; } }
|
||||
|
||||
// public bool this[string button] { get { return IsPressed(button); } }
|
||||
|
||||
// public bool IsPressed(string button)
|
||||
// {
|
||||
// if (Forces.ContainsKey(button))
|
||||
// return Forces[button];
|
||||
// else return Controller.IsPressed(button);
|
||||
// }
|
||||
|
||||
// public float GetFloat(string name)
|
||||
// {
|
||||
// return Controller.GetFloat(name); //TODO!
|
||||
// }
|
||||
|
||||
// public void UpdateControls(int frame)
|
||||
// {
|
||||
// Controller.UpdateControls(frame);
|
||||
// }
|
||||
//}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class MovieHeader
|
||||
{
|
||||
//Required Header Params
|
||||
//Emulation - Core version, will be 1.0.0 until there is a versioning system
|
||||
//Movie - Versioning for the Movie code itself, or perhaps this could be changed client version?
|
||||
//Platform - Must know what platform we are making a movie on!
|
||||
//GameName - Which game
|
||||
//TODO: checksum of game, other stuff
|
||||
|
||||
public Dictionary<string, string> HeaderParams = new Dictionary<string, string>(); //Platform specific options go here
|
||||
public List<string> Comments = new List<string>();
|
||||
|
||||
public Dictionary<string, string> BoardProperties = new Dictionary<string, string>();
|
||||
|
||||
public const string EMULATIONVERSION = "emuVersion";
|
||||
public const string MOVIEVERSION = "MovieVersion";
|
||||
public const string PLATFORM = "Platform";
|
||||
public const string GAMENAME = "GameName";
|
||||
public const string AUTHOR = "Author";
|
||||
public const string RERECORDS = "rerecordCount";
|
||||
public const string GUID = "GUID";
|
||||
public const string STARTSFROMSAVESTATE = "StartsFromSavestate";
|
||||
public const string FOURSCORE = "FourScore";
|
||||
public const string SHA1 = "SHA1";
|
||||
public const string FIRMWARESHA1 = "FirmwareSHA1";
|
||||
public const string PAL = "PAL";
|
||||
public const string BOARDNAME = "BoardName";
|
||||
|
||||
//Gameboy Settings that affect sync
|
||||
public const string GB_FORCEDMG = "Force_DMG_Mode";
|
||||
public const string GB_GBA_IN_CGB = "GBA_In_CGB";
|
||||
public const string SGB = "SGB"; //a snes movie will set this to indicate that it's actually SGB
|
||||
|
||||
//BIO skipping setting (affects sync)
|
||||
public const string SKIPBIOS = "Skip_Bios";
|
||||
|
||||
//Plugin Settings
|
||||
public const string VIDEOPLUGIN = "VideoPlugin";
|
||||
|
||||
//Board properties
|
||||
public const string BOARDPROPERTIES = "BoardProperty";
|
||||
|
||||
public static string MovieVersion = "BizHawk v0.0.1";
|
||||
|
||||
public static string MakeGUID()
|
||||
{
|
||||
return System.Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public MovieHeader(string version) //All required fields will be set to default values
|
||||
{
|
||||
|
||||
HeaderParams.Add(EMULATIONVERSION, version);
|
||||
HeaderParams.Add(MOVIEVERSION, MovieVersion);
|
||||
HeaderParams.Add(PLATFORM, "");
|
||||
HeaderParams.Add(GAMENAME, "");
|
||||
HeaderParams.Add(AUTHOR, "");
|
||||
HeaderParams.Add(RERECORDS, "0");
|
||||
HeaderParams.Add(GUID, MakeGUID());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the key value pair to header params. If key already exists, value will be updated
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddHeaderLine(string key, string value)
|
||||
{
|
||||
string temp;
|
||||
|
||||
if (!HeaderParams.TryGetValue(key, out temp)) //TODO: does a failed attempt mess with value?
|
||||
HeaderParams.Add(key, value);
|
||||
}
|
||||
|
||||
public void UpdateRerecordCount(int count)
|
||||
{
|
||||
HeaderParams[RERECORDS] = count.ToString();
|
||||
}
|
||||
|
||||
public bool RemoveHeaderLine(string key)
|
||||
{
|
||||
return HeaderParams.Remove(key);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
HeaderParams.Clear();
|
||||
}
|
||||
|
||||
public string GetHeaderLine(string key)
|
||||
{
|
||||
string value;
|
||||
HeaderParams.TryGetValue(key, out value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void SetHeaderLine(string key, string value)
|
||||
{
|
||||
HeaderParams[key] = value;
|
||||
}
|
||||
|
||||
public void WriteText(StreamWriter sw)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> kvp in HeaderParams)
|
||||
{
|
||||
sw.WriteLine(kvp.Key + " " + kvp.Value);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> kvp in BoardProperties)
|
||||
{
|
||||
sw.WriteLine(BOARDPROPERTIES + " " + kvp.Key + " " + kvp.Value);
|
||||
}
|
||||
|
||||
foreach (string t in Comments)
|
||||
{
|
||||
sw.WriteLine(t);
|
||||
}
|
||||
}
|
||||
|
||||
private string ParseHeader(string line, string headerName)
|
||||
{
|
||||
int x = line.LastIndexOf(headerName) + headerName.Length;
|
||||
string str = line.Substring(x + 1, line.Length - x - 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
//TODO: replace Movie Preload & Load functions with this
|
||||
/// <summary>
|
||||
/// Receives a line and attempts to add as a header, returns false if not a useable header line
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddHeaderFromLine(string line)
|
||||
{
|
||||
if (line.Length == 0) return false;
|
||||
else if (line.Contains(EMULATIONVERSION))
|
||||
{
|
||||
line = ParseHeader(line, EMULATIONVERSION);
|
||||
AddHeaderLine(EMULATIONVERSION, line);
|
||||
}
|
||||
else if (line.Contains(MOVIEVERSION))
|
||||
{
|
||||
line = ParseHeader(line, MOVIEVERSION);
|
||||
AddHeaderLine(MOVIEVERSION, line);
|
||||
}
|
||||
else if (line.Contains(PLATFORM))
|
||||
{
|
||||
line = ParseHeader(line, PLATFORM);
|
||||
AddHeaderLine(PLATFORM, line);
|
||||
}
|
||||
else if (line.Contains(GAMENAME))
|
||||
{
|
||||
line = ParseHeader(line, GAMENAME);
|
||||
AddHeaderLine(GAMENAME, line);
|
||||
}
|
||||
else if (line.Contains(RERECORDS))
|
||||
{
|
||||
line = ParseHeader(line, RERECORDS);
|
||||
AddHeaderLine(RERECORDS, line);
|
||||
}
|
||||
else if (line.Contains(AUTHOR))
|
||||
{
|
||||
line = ParseHeader(line, AUTHOR);
|
||||
AddHeaderLine(AUTHOR, line);
|
||||
}
|
||||
else if (line.ToUpper().Contains(GUID))
|
||||
{
|
||||
line = ParseHeader(line, GUID);
|
||||
AddHeaderLine(GUID, line);
|
||||
}
|
||||
else if (line.Contains(STARTSFROMSAVESTATE))
|
||||
{
|
||||
line = ParseHeader(line, STARTSFROMSAVESTATE);
|
||||
AddHeaderLine(STARTSFROMSAVESTATE, line);
|
||||
}
|
||||
else if (line.Contains(SHA1))
|
||||
{
|
||||
line = ParseHeader(line, SHA1);
|
||||
AddHeaderLine(SHA1, line);
|
||||
}
|
||||
else if (line.Contains(SKIPBIOS))
|
||||
{
|
||||
line = ParseHeader(line, SKIPBIOS);
|
||||
AddHeaderLine(SKIPBIOS, line);
|
||||
}
|
||||
else if (line.Contains(GB_FORCEDMG))
|
||||
{
|
||||
line = ParseHeader(line, GB_FORCEDMG);
|
||||
AddHeaderLine(GB_FORCEDMG, line);
|
||||
}
|
||||
else if (line.Contains(GB_GBA_IN_CGB))
|
||||
{
|
||||
line = ParseHeader(line, GB_GBA_IN_CGB);
|
||||
AddHeaderLine(GB_GBA_IN_CGB, line);
|
||||
}
|
||||
else if (line.Contains(SGB))
|
||||
{
|
||||
line = ParseHeader(line, SGB);
|
||||
AddHeaderLine(SGB, line);
|
||||
}
|
||||
else if (line.Contains(PAL))
|
||||
{
|
||||
line = ParseHeader(line, PAL);
|
||||
AddHeaderLine(PAL, line);
|
||||
}
|
||||
else if (line.Contains(VIDEOPLUGIN))
|
||||
{
|
||||
line = ParseHeader(line, VIDEOPLUGIN);
|
||||
AddHeaderLine(VIDEOPLUGIN, line);
|
||||
}
|
||||
else if (line.Contains(BOARDPROPERTIES))
|
||||
{
|
||||
line = ParseHeader(line, BOARDPROPERTIES);
|
||||
string[] vals = line.Split(' ');
|
||||
BoardProperties.Add(vals[0], vals[1]);
|
||||
}
|
||||
else if (line.StartsWith("subtitle") || line.StartsWith("sub"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (line.StartsWith("comment"))
|
||||
{
|
||||
Comments.Add(line.Substring(8, line.Length - 8));
|
||||
}
|
||||
else if (line[0] == '|')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HeaderParams[PLATFORM] == "N64")
|
||||
{
|
||||
if (HeaderParams.ContainsKey(VIDEOPLUGIN))
|
||||
{
|
||||
if (HeaderParams[VIDEOPLUGIN] == "Rice")
|
||||
{
|
||||
ICollection<string> settings = Global.Config.RicePlugin.GetPluginSettings().Keys;
|
||||
foreach (string setting in settings)
|
||||
{
|
||||
if (line.Contains(setting))
|
||||
{
|
||||
line = ParseHeader(line, setting);
|
||||
AddHeaderLine(setting, line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (HeaderParams[VIDEOPLUGIN] == "Glide64")
|
||||
{
|
||||
ICollection<string> settings = Global.Config.GlidePlugin.GetPluginSettings().Keys;
|
||||
foreach (string setting in settings)
|
||||
{
|
||||
if (line.Contains(setting))
|
||||
{
|
||||
line = ParseHeader(line, setting);
|
||||
AddHeaderLine(setting, line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Comments.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReadHeader(StreamReader reader)
|
||||
{
|
||||
string str;
|
||||
while ((str = reader.ReadLine()) != null)
|
||||
{
|
||||
AddHeaderFromLine(str);
|
||||
}
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
//TODO: what is this object really trying to accomplish? COnsider making it a collection (ICollection, IEnumerable perhaps)
|
||||
|
||||
/// <summary>
|
||||
/// Represents the controller key presses of a movie
|
||||
/// </summary>
|
||||
public class MovieLog
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public byte[] InitState { get; private set; }
|
||||
|
||||
public int StateCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _state_records.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _movie_records.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public int StateFirstIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_state_records.Count == 0) ? -1 : _state_records[0].Index;
|
||||
}
|
||||
}
|
||||
|
||||
public int StateLastIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_state_records.Count == 0) ? -1 : _state_records[_state_records.Count - 1].Index;
|
||||
}
|
||||
}
|
||||
|
||||
public int StateSizeInBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_state_records.Count > 0)
|
||||
{
|
||||
return StateCount * _state_records[0].State.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_movie_records.Clear();
|
||||
_state_records.Clear();
|
||||
}
|
||||
|
||||
public void ClearStates()
|
||||
{
|
||||
_state_records.Clear();
|
||||
}
|
||||
|
||||
public void AppendFrame(string frame)
|
||||
{
|
||||
_movie_records.Add(frame);
|
||||
}
|
||||
|
||||
public void AddState(byte[] state)
|
||||
{
|
||||
if (Global.Emulator.Frame == 0)
|
||||
{
|
||||
InitState = state;
|
||||
}
|
||||
if (Global.Emulator.Frame < StateFirstIndex)
|
||||
{
|
||||
_state_records.Clear();
|
||||
_state_records.Add(new StateRecord(Global.Emulator.Frame, state));
|
||||
}
|
||||
if (Global.Emulator.Frame > StateLastIndex)
|
||||
{
|
||||
if (StateSizeInBytes + state.Length > MAXSTATERECORDSIZE)
|
||||
{
|
||||
// Discard the oldest state to save space.
|
||||
_state_records.RemoveAt(0);
|
||||
}
|
||||
_state_records.Add(new StateRecord(Global.Emulator.Frame,state));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFrameAt(int frameNum, string frame)
|
||||
{
|
||||
if (frameNum < StateLastIndex && (frameNum < StateFirstIndex || frame != GetFrame(frameNum)))
|
||||
{
|
||||
TruncateStates(frameNum+1);
|
||||
}
|
||||
|
||||
if (_movie_records.Count > frameNum)
|
||||
{
|
||||
_movie_records[frameNum] = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
_movie_records.Add(frame);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFrameAt(int frame, string record)
|
||||
{
|
||||
_movie_records.Insert(frame, record);
|
||||
|
||||
if (frame <= StateLastIndex)
|
||||
{
|
||||
if (frame <= StateFirstIndex)
|
||||
{
|
||||
_state_records.Clear();
|
||||
//Global.MovieSession.Movie.RewindToFrame(0); //TODO: unbreak this, also don't do it this way
|
||||
}
|
||||
else
|
||||
{
|
||||
_state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
|
||||
//Global.MovieSession.Movie.RewindToFrame(frame); //TODO: unbreak this, also don't do it this way
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetState(int frame)
|
||||
{
|
||||
return _state_records[frame - StateFirstIndex].State;
|
||||
}
|
||||
|
||||
public void DeleteFrame(int frame)
|
||||
{
|
||||
_movie_records.RemoveAt(frame);
|
||||
if (frame <= StateLastIndex)
|
||||
{
|
||||
if (frame <= StateFirstIndex)
|
||||
{
|
||||
_state_records.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TruncateStates(int frame)
|
||||
{
|
||||
if (frame >= 0)
|
||||
{
|
||||
if (frame < StateFirstIndex)
|
||||
{
|
||||
_state_records.Clear();
|
||||
}
|
||||
else if (frame <= StateLastIndex)
|
||||
{
|
||||
_state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GetFrame(int frame)
|
||||
{
|
||||
if (frame >= 0 && frame < _movie_records.Count)
|
||||
{
|
||||
return _movie_records[frame];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ""; //TODO: throw an exception?
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteText(StreamWriter sw)
|
||||
{
|
||||
for (int i = 0; i < _movie_records.Count; i++)
|
||||
{
|
||||
sw.WriteLine(GetFrame(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void TruncateMovie(int frame)
|
||||
{
|
||||
if (frame < _movie_records.Count)
|
||||
{
|
||||
_movie_records.RemoveRange(frame, _movie_records.Count - frame);
|
||||
TruncateStates(frame);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FrameLagged(int frame)
|
||||
{
|
||||
if (frame >= StateFirstIndex && frame <= StateLastIndex && frame <= _state_records.Count)
|
||||
{
|
||||
if (frame < _state_records.Count)
|
||||
{
|
||||
return _state_records[frame].Lagged;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region private fields
|
||||
|
||||
private class StateRecord
|
||||
{
|
||||
public StateRecord(int index, byte[] state)
|
||||
{
|
||||
Index = index;
|
||||
State = state;
|
||||
Lagged = Global.Emulator.IsLagFrame;
|
||||
}
|
||||
|
||||
public readonly int Index;
|
||||
public readonly byte[] State;
|
||||
public readonly bool Lagged;
|
||||
}
|
||||
|
||||
private readonly List<string> _movie_records = new List<string>();
|
||||
private readonly List<StateRecord> _state_records = new List<StateRecord>();
|
||||
|
||||
//TODO: Make this size limit configurable by the user
|
||||
private const int MAXSTATERECORDSIZE = 512*1024*1024; //To limit memory usage.
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class MovieSession
|
||||
{
|
||||
public MultitrackRecording MultiTrack = new MultitrackRecording();
|
||||
public Movie Movie;
|
||||
public MovieControllerAdapter MovieControllerAdapter = new MovieControllerAdapter();
|
||||
|
||||
public void LatchMultitrackPlayerInput(IController playerSource, MultitrackRewiringControllerAdapter rewiredSource)
|
||||
{
|
||||
if (MultiTrack.IsActive)
|
||||
{
|
||||
rewiredSource.PlayerSource = 1;
|
||||
rewiredSource.PlayerTargetMask = 1 << (MultiTrack.CurrentPlayer);
|
||||
if (MultiTrack.RecordAll) rewiredSource.PlayerTargetMask = unchecked((int)0xFFFFFFFF);
|
||||
}
|
||||
else rewiredSource.PlayerSource = -1;
|
||||
|
||||
MovieControllerAdapter.LatchPlayerFromSource(rewiredSource, MultiTrack.CurrentPlayer);
|
||||
}
|
||||
|
||||
public void LatchInputFromPlayer(IController source)
|
||||
{
|
||||
MovieControllerAdapter.LatchFromSource(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// latch input from the input log, if available
|
||||
/// </summary>
|
||||
public void LatchInputFromLog()
|
||||
{
|
||||
string loggedFrame = Movie.GetInput(Global.Emulator.Frame);
|
||||
MovieControllerAdapter.SetControllersAsMnemonic(loggedFrame);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class MultitrackRecording
|
||||
{
|
||||
public bool IsActive;
|
||||
public int CurrentPlayer;
|
||||
public bool RecordAll;
|
||||
public MultitrackRecording()
|
||||
{
|
||||
IsActive = false;
|
||||
CurrentPlayer = 0;
|
||||
RecordAll = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class Subtitle
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public int Frame { get; set; }
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public uint Color { get; set; }
|
||||
|
||||
public Subtitle()
|
||||
{
|
||||
Message = String.Empty;
|
||||
X = 0;
|
||||
Y = 0;
|
||||
Duration = 120;
|
||||
Frame = 0;
|
||||
Color = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
public Subtitle(Subtitle s)
|
||||
{
|
||||
Message = s.Message;
|
||||
Frame = s.Frame;
|
||||
X = s.X;
|
||||
Y = s.Y;
|
||||
Duration = s.Duration;
|
||||
Color = s.Color;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("subtitle ");
|
||||
sb
|
||||
.Append(Frame.ToString()).Append(" ")
|
||||
.Append(X.ToString()).Append(" ")
|
||||
.Append(Y.ToString()).Append(" ")
|
||||
.Append(Duration.ToString()).Append(" ")
|
||||
.Append(String.Format("{0:X8}", Color)).Append(" ")
|
||||
.Append(Message);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class SubtitleList : IEnumerable<Subtitle>
|
||||
{
|
||||
private readonly List<Subtitle> _subtitles = new List<Subtitle>();
|
||||
|
||||
public SubtitleList() { }
|
||||
|
||||
public SubtitleList(SubtitleList subtitles)
|
||||
{
|
||||
foreach (var subtitle in subtitles)
|
||||
{
|
||||
_subtitles.Add(new Subtitle(subtitle)); //TODO: Multiclient.EditSubtitlesForm needs a deep copy here, refactor it so that it doesn't
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<Subtitle> GetEnumerator()
|
||||
{
|
||||
return _subtitles.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Subtitle this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _subtitles[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the logic of what subtitle should be displayed on any given frame based on frame & duration
|
||||
/// </summary>
|
||||
/// <param name="frame"></param>
|
||||
/// <returns></returns>
|
||||
public string GetSubtitleMessage(int frame)
|
||||
{
|
||||
if (_subtitles.Count == 0) return "";
|
||||
|
||||
foreach (Subtitle t in _subtitles)
|
||||
{
|
||||
if (frame >= t.Frame && frame <= t.Frame + t.Duration)
|
||||
{
|
||||
return t.Message;
|
||||
}
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public Subtitle GetSubtitle(int frame)
|
||||
{
|
||||
if (_subtitles.Any())
|
||||
{
|
||||
foreach (Subtitle t in _subtitles)
|
||||
{
|
||||
if (frame >= t.Frame && frame <= t.Frame + t.Duration)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Subtitle();
|
||||
}
|
||||
|
||||
public List<Subtitle> GetSubtitles(int frame)
|
||||
{
|
||||
return _subtitles.Where(t => frame >= t.Frame && frame <= t.Frame + t.Duration).ToList();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _subtitles.Count; }
|
||||
}
|
||||
|
||||
//TODO
|
||||
public Point GetSubtitlePoint(int frame)
|
||||
{
|
||||
Point p = new Point(0, 0);
|
||||
return p;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse string for necessary subtitle information, required is a frame and a message, space delminated, the word subtitle assumed to be first
|
||||
/// </summary>
|
||||
/// <param name="subtitleStr"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddSubtitle(string subtitleStr) //TODO: refactor with String.Split
|
||||
{
|
||||
if (!String.IsNullOrWhiteSpace(subtitleStr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Subtitle s = new Subtitle();
|
||||
|
||||
int x = subtitleStr.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
|
||||
//remove "subtitle"
|
||||
string str = subtitleStr.Substring(x + 1, subtitleStr.Length - x - 1);
|
||||
|
||||
x = str.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
|
||||
string frame = str.Substring(0, x);
|
||||
str = str.Substring(x + 1, str.Length - x - 1);
|
||||
|
||||
try
|
||||
{
|
||||
s.Frame = int.Parse(frame);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x = str.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
string X = str.Substring(0, x);
|
||||
str = str.Substring(x + 1, str.Length - x - 1);
|
||||
try
|
||||
{
|
||||
s.X = int.Parse(X);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x = str.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
string Y = str.Substring(0, x);
|
||||
str = str.Substring(x + 1, str.Length - x - 1);
|
||||
try
|
||||
{
|
||||
s.Y = int.Parse(Y);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x = str.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
string Duration = str.Substring(0, x);
|
||||
str = str.Substring(x + 1, str.Length - x - 1);
|
||||
try
|
||||
{
|
||||
s.Duration = int.Parse(Duration);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x = str.IndexOf(' ');
|
||||
if (x <= 0) return false;
|
||||
string Color = str.Substring(0, x);
|
||||
str = str.Substring(x + 1, str.Length - x - 1);
|
||||
try
|
||||
{
|
||||
s.Color = uint.Parse(Color, NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
s.Message = str;
|
||||
_subtitles.Add(s);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddSubtitle(Subtitle s)
|
||||
{
|
||||
_subtitles.Add(s);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_subtitles.Clear();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index >= _subtitles.Count) return;
|
||||
|
||||
_subtitles.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void WriteText(StreamWriter sw)
|
||||
{
|
||||
foreach(var subtitle in _subtitles)
|
||||
{
|
||||
sw.WriteLine(subtitle.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class Cheat
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public Cheat(Watch watch, int value, int? compare = null, bool enabled = true)
|
||||
{
|
||||
_enabled = enabled;
|
||||
_watch = watch;
|
||||
_compare = compare;
|
||||
_val = value;
|
||||
|
||||
Pulse();
|
||||
}
|
||||
|
||||
public Cheat(Cheat cheat)
|
||||
{
|
||||
if (cheat.IsSeparator)
|
||||
{
|
||||
_enabled = false;
|
||||
_watch = SeparatorWatch.Instance;
|
||||
_compare = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_enabled = cheat.Enabled;
|
||||
_watch = Watch.GenerateWatch(cheat.Domain,
|
||||
cheat.Address ?? 0,
|
||||
cheat.Size,
|
||||
cheat.Type,
|
||||
cheat.Name,
|
||||
cheat.BigEndian ?? false
|
||||
);
|
||||
_compare = cheat.Compare;
|
||||
_val = cheat.Value ?? 0;
|
||||
|
||||
Pulse();
|
||||
}
|
||||
}
|
||||
|
||||
public static Cheat Separator
|
||||
{
|
||||
get { return new Cheat(SeparatorWatch.Instance, 0, null, false); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public bool IsSeparator
|
||||
{
|
||||
get { return _watch.IsSeparator; }
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get { if (IsSeparator) return false; else return _enabled; }
|
||||
}
|
||||
|
||||
public int? Address
|
||||
{
|
||||
get { return _watch.Address; }
|
||||
}
|
||||
|
||||
public int? Value
|
||||
{
|
||||
get { return _watch.Value; }
|
||||
}
|
||||
|
||||
public bool? BigEndian
|
||||
{
|
||||
get { if (IsSeparator) return null; else return _watch.BigEndian; }
|
||||
}
|
||||
|
||||
public int? Compare
|
||||
{
|
||||
get { if (_compare.HasValue && !IsSeparator) return _compare; else return null; }
|
||||
}
|
||||
|
||||
public MemoryDomain Domain
|
||||
{
|
||||
get { return _watch.Domain; }
|
||||
}
|
||||
|
||||
public Watch.WatchSize Size
|
||||
{
|
||||
get { return _watch.Size; }
|
||||
}
|
||||
|
||||
public char SizeAsChar
|
||||
{
|
||||
get { return _watch.SizeAsChar; }
|
||||
}
|
||||
|
||||
public Watch.DisplayType Type
|
||||
{
|
||||
get { return _watch.Type; }
|
||||
}
|
||||
|
||||
public char TypeAsChar
|
||||
{
|
||||
get { return _watch.TypeAsChar; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { if (IsSeparator) return String.Empty; else return _watch.Notes; }
|
||||
}
|
||||
|
||||
public string AddressStr
|
||||
{
|
||||
get { return _watch.AddressString; }
|
||||
}
|
||||
|
||||
public string ValueStr
|
||||
{
|
||||
get { return _watch.ValueString; }
|
||||
}
|
||||
|
||||
public string CompareStr
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_compare.HasValue)
|
||||
{
|
||||
switch (_watch.Size)
|
||||
{
|
||||
default:
|
||||
case Watch.WatchSize.Separator:
|
||||
return String.Empty;
|
||||
case Watch.WatchSize.Byte:
|
||||
return (_watch as ByteWatch).FormatValue((byte)_compare.Value);
|
||||
case Watch.WatchSize.Word:
|
||||
return (_watch as WordWatch).FormatValue((ushort)_compare.Value);
|
||||
case Watch.WatchSize.DWord:
|
||||
return (_watch as DWordWatch).FormatValue((uint)_compare.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
if (!IsSeparator)
|
||||
{
|
||||
_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
if (!IsSeparator)
|
||||
{
|
||||
_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
if (!IsSeparator)
|
||||
{
|
||||
_enabled ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Pulse()
|
||||
{
|
||||
if (!IsSeparator && _enabled)
|
||||
{
|
||||
if (_compare.HasValue)
|
||||
{
|
||||
if (_compare.Value == _watch.Value)
|
||||
{
|
||||
_watch.Poke(_val.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_watch.Poke(_val.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(int addr)
|
||||
{
|
||||
switch (_watch.Size)
|
||||
{
|
||||
default:
|
||||
case Watch.WatchSize.Separator:
|
||||
return false;
|
||||
case Watch.WatchSize.Byte:
|
||||
return (_watch.Address ?? 0) == addr;
|
||||
case Watch.WatchSize.Word:
|
||||
return (addr == (_watch.Address ?? 0)) || (addr == (_watch.Address ?? 0) + 1);
|
||||
case Watch.WatchSize.DWord:
|
||||
return (addr == (_watch.Address ?? 0)) || (addr == (_watch.Address ?? 0) + 1) ||
|
||||
(addr == (_watch.Address ?? 0) + 2) || (addr == (_watch.Address ?? 0) + 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void Increment()
|
||||
{
|
||||
if (!IsSeparator)
|
||||
{
|
||||
_val++;
|
||||
Pulse();
|
||||
}
|
||||
}
|
||||
|
||||
public void Decrement()
|
||||
{
|
||||
if (!IsSeparator)
|
||||
{
|
||||
_val--;
|
||||
Pulse();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetType(Watch.DisplayType type)
|
||||
{
|
||||
if (Watch.AvailableTypes(_watch.Size).Contains(type))
|
||||
{
|
||||
_watch.Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region private parts
|
||||
|
||||
private readonly Watch _watch;
|
||||
private int? _compare;
|
||||
private int _val;
|
||||
private bool _enabled;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,557 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class CheatList : IEnumerable<Cheat>
|
||||
{
|
||||
private List<Cheat> _cheatList = new List<Cheat>();
|
||||
private string _currentFileName = String.Empty;
|
||||
private bool _changes;
|
||||
private string _defaultFileName = String.Empty;
|
||||
|
||||
public IEnumerator<Cheat> GetEnumerator()
|
||||
{
|
||||
return _cheatList.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Cheat this[int index]
|
||||
{
|
||||
get { return _cheatList[index]; }
|
||||
}
|
||||
|
||||
public void Pulse()
|
||||
{
|
||||
foreach(var cheat in _cheatList)
|
||||
{
|
||||
cheat.Pulse();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks for a .cht file that matches the ROM loaded based on the default filename for a given ROM
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool AttemptToLoadCheatFile()
|
||||
{
|
||||
var file = new FileInfo(_defaultFileName);
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
return Load(file.FullName, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void FlagChanges()
|
||||
{
|
||||
_changes = true;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _cheatList.Count; }
|
||||
}
|
||||
|
||||
public int CheatCount
|
||||
{
|
||||
get { return _cheatList.Count(x => !x.IsSeparator); }
|
||||
}
|
||||
|
||||
public int ActiveCount
|
||||
{
|
||||
get { return _cheatList.Count(x => x.Enabled); }
|
||||
}
|
||||
|
||||
public void NewList(string defaultFileName)
|
||||
{
|
||||
_defaultFileName = defaultFileName;
|
||||
_cheatList.Clear();
|
||||
_currentFileName = String.Empty;
|
||||
_changes = false;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_cheatList.ForEach(x => x.Pulse());
|
||||
}
|
||||
|
||||
public void Add(Cheat c)
|
||||
{
|
||||
if (_cheatList.Any(x => x.Domain == c.Domain && x.Address == c.Address))
|
||||
{
|
||||
_cheatList.FirstOrDefault(x => x.Domain == c.Domain && x.Address == c.Address).Enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList.Add(c);
|
||||
}
|
||||
|
||||
_changes = true;
|
||||
}
|
||||
|
||||
public void Insert(int index, Cheat c)
|
||||
{
|
||||
if (_cheatList.Any(x => x.Domain == c.Domain && x.Address == c.Address))
|
||||
{
|
||||
_cheatList.FirstOrDefault(x => x.Domain == c.Domain && x.Address == c.Address).Enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList.Insert(index, c);
|
||||
}
|
||||
|
||||
_changes = true;
|
||||
}
|
||||
|
||||
public void Remove(Cheat c)
|
||||
{
|
||||
_changes = true;
|
||||
_cheatList.Remove(c);
|
||||
}
|
||||
|
||||
public void Remove(Watch w)
|
||||
{
|
||||
|
||||
var cheat = _cheatList.FirstOrDefault(x => x.Domain == w.Domain && x.Address == w.Address);
|
||||
if (cheat != null)
|
||||
{
|
||||
_changes = true;
|
||||
_cheatList.Remove(cheat);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveRange(IEnumerable<Cheat> cheats)
|
||||
{
|
||||
_changes = true;
|
||||
foreach (var cheat in cheats)
|
||||
{
|
||||
_cheatList.Remove(cheat);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Changes
|
||||
{
|
||||
get { return _changes; }
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_changes = true;
|
||||
_cheatList.Clear();
|
||||
}
|
||||
|
||||
public void DisableAll()
|
||||
{
|
||||
_changes = true;
|
||||
_cheatList.ForEach(x => x.Disable());
|
||||
}
|
||||
|
||||
public void EnableAll()
|
||||
{
|
||||
_changes = true;
|
||||
_cheatList.ForEach(x => x.Enable());
|
||||
}
|
||||
|
||||
public bool IsActive(MemoryDomain domain, int address)
|
||||
{
|
||||
foreach (var cheat in _cheatList)
|
||||
{
|
||||
if (cheat.IsSeparator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (cheat.Domain == domain && cheat.Contains(address) && cheat.Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SaveOnClose()
|
||||
{
|
||||
if (Global.Config.CheatsAutoSaveOnClose)
|
||||
{
|
||||
if (_changes && _cheatList.Any())
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(_currentFileName))
|
||||
{
|
||||
_currentFileName = _defaultFileName;
|
||||
}
|
||||
|
||||
SaveFile(_currentFileName);
|
||||
}
|
||||
else if (!_cheatList.Any() && !String.IsNullOrWhiteSpace(_currentFileName))
|
||||
{
|
||||
new FileInfo(_currentFileName).Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Save()
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(_currentFileName))
|
||||
{
|
||||
_currentFileName = _defaultFileName;
|
||||
}
|
||||
|
||||
return SaveFile(_currentFileName);
|
||||
}
|
||||
|
||||
public bool SaveFile(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo file = new FileInfo(path);
|
||||
if (file.Directory != null && !file.Directory.Exists)
|
||||
{
|
||||
file.Directory.Create();
|
||||
}
|
||||
|
||||
using (StreamWriter sw = new StreamWriter(path))
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var cheat in _cheatList)
|
||||
{
|
||||
if (cheat.IsSeparator)
|
||||
{
|
||||
sb.AppendLine("----");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set to hex for saving
|
||||
cheat.SetType(Watch.DisplayType.Hex);
|
||||
|
||||
sb
|
||||
.Append(cheat.AddressStr).Append('\t')
|
||||
.Append(cheat.ValueStr).Append('\t')
|
||||
.Append(cheat.Compare.HasValue ? cheat.Compare.Value.ToString() : "N").Append('\t')
|
||||
.Append(cheat.Domain != null ? cheat.Domain.Name : String.Empty).Append('\t')
|
||||
.Append(cheat.Enabled ? '1' : '0').Append('\t')
|
||||
.Append(cheat.Name).Append('\t')
|
||||
.Append(cheat.SizeAsChar).Append('\t')
|
||||
.Append(cheat.TypeAsChar).Append('\t')
|
||||
.Append((cheat.BigEndian ?? false) ? '1' : '0').Append('\t')
|
||||
.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sw.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
_changes = false;
|
||||
_currentFileName = path;
|
||||
Global.Config.RecentCheats.Add(_currentFileName);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Load(string path, bool append)
|
||||
{
|
||||
var file = new FileInfo(path);
|
||||
if (file.Exists == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!append)
|
||||
{
|
||||
_currentFileName = path;
|
||||
}
|
||||
|
||||
using (StreamReader sr = file.OpenText())
|
||||
{
|
||||
if (append)
|
||||
{
|
||||
_changes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
_changes = false;
|
||||
}
|
||||
|
||||
string s;
|
||||
while ((s = sr.ReadLine()) != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (s == "----")
|
||||
{
|
||||
_cheatList.Add(Cheat.Separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
int? compare;
|
||||
Watch.WatchSize size = Watch.WatchSize.Byte;
|
||||
Watch.DisplayType type = Watch.DisplayType.Hex;
|
||||
bool BIGENDIAN = false;
|
||||
|
||||
|
||||
if (s.Length < 6) continue;
|
||||
//NewCheat c = new NewCheat(
|
||||
string[] vals = s.Split('\t');
|
||||
int ADDR = Int32.Parse(vals[0], NumberStyles.HexNumber);
|
||||
int value = Int32.Parse(vals[1], NumberStyles.HexNumber);
|
||||
|
||||
if (vals[2] == "N")
|
||||
{
|
||||
compare = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
compare = Int32.Parse(vals[2], NumberStyles.HexNumber);
|
||||
}
|
||||
MemoryDomain domain = DomainByName(vals[3]);
|
||||
bool ENABLED = vals[4] == "1";
|
||||
string name = vals[5];
|
||||
|
||||
//For backwards compatibility, don't assume these values exist
|
||||
if (vals.Length > 6)
|
||||
{
|
||||
size = Watch.SizeFromChar(vals[6][0]);
|
||||
type = Watch.DisplayTypeFromChar(vals[7][0]);
|
||||
BIGENDIAN = vals[8] == "1";
|
||||
}
|
||||
|
||||
Watch w = Watch.GenerateWatch(
|
||||
domain,
|
||||
ADDR,
|
||||
size,
|
||||
type,
|
||||
name,
|
||||
BIGENDIAN
|
||||
);
|
||||
|
||||
Cheat c = new Cheat(w, value, compare, !Global.Config.DisableCheatsOnLoad && ENABLED);
|
||||
_cheatList.Add(c);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string CurrentFileName
|
||||
{
|
||||
get { return _currentFileName; }
|
||||
}
|
||||
|
||||
public void Sort(string column, bool reverse)
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
case NAME:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case ADDRESS:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Address ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Address ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case VALUE:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Value ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Value ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case COMPARE:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Compare ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Compare ?? 0)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case ON:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Enabled)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Enabled)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case DOMAIN:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Domain)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Domain)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case SIZE:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => ((int)x.Size))
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => ((int)x.Size))
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case ENDIAN:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.BigEndian)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.BigEndian)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
case TYPE:
|
||||
if (reverse)
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderByDescending(x => x.Type)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cheatList = _cheatList
|
||||
.OrderBy(x => x.Type)
|
||||
.ThenBy(x => x.Name)
|
||||
.ThenBy(x => x.Address ?? 0)
|
||||
.ToList();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region Privates
|
||||
|
||||
private static MemoryDomain DomainByName(string name)
|
||||
{
|
||||
//Attempts to find the memory domain by name, if it fails, it defaults to index 0
|
||||
foreach (MemoryDomain domain in Global.Emulator.MemoryDomains)
|
||||
{
|
||||
if (domain.Name == name)
|
||||
{
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
return Global.Emulator.MainMemory;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public const string NAME = "NamesColumn";
|
||||
public const string ADDRESS = "AddressColumn";
|
||||
public const string VALUE = "ValueColumn";
|
||||
public const string COMPARE = "CompareColumn";
|
||||
public const string ON = "OnColumn";
|
||||
public const string DOMAIN = "DomainColumn";
|
||||
public const string SIZE = "SizeColumn";
|
||||
public const string ENDIAN = "EndianColumn";
|
||||
public const string TYPE = "DisplayTypeColumn";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,930 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public abstract class Watch
|
||||
{
|
||||
public enum WatchSize { Byte = 1, Word = 2, DWord = 4, Separator = 0 };
|
||||
public enum DisplayType { Separator, Signed, Unsigned, Hex, Binary, FixedPoint_12_4, FixedPoint_20_12, Float };
|
||||
public enum PreviousType { Original = 0, LastSearch = 1, LastFrame = 2, LastChange = 3 };
|
||||
|
||||
public static string DisplayTypeToString(DisplayType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
return type.ToString();
|
||||
case DisplayType.FixedPoint_12_4:
|
||||
return "Fixed Point 12.4";
|
||||
case DisplayType.FixedPoint_20_12:
|
||||
return "Fixed Point 20.12";
|
||||
}
|
||||
}
|
||||
|
||||
public static DisplayType StringToDisplayType(string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
default:
|
||||
return (DisplayType)Enum.Parse(typeof(DisplayType), name);
|
||||
case "Fixed Point 12.4":
|
||||
return DisplayType.FixedPoint_12_4;
|
||||
case "Fixed Point 20.12":
|
||||
return DisplayType.FixedPoint_20_12;
|
||||
}
|
||||
}
|
||||
|
||||
protected int _address;
|
||||
protected MemoryDomain _domain;
|
||||
protected DisplayType _type;
|
||||
protected bool _bigEndian;
|
||||
protected int _changecount;
|
||||
protected string _notes = String.Empty;
|
||||
|
||||
public abstract int? Value { get; }
|
||||
public abstract string ValueString { get; }
|
||||
public abstract WatchSize Size { get; }
|
||||
|
||||
public abstract int? Previous { get; }
|
||||
public abstract string PreviousStr { get; }
|
||||
public abstract void ResetPrevious();
|
||||
|
||||
public abstract bool Poke(string value);
|
||||
|
||||
public virtual DisplayType Type { get { return _type; } set { _type = value; } }
|
||||
public virtual bool BigEndian { get { return _bigEndian; } set { _bigEndian = value; } }
|
||||
|
||||
public MemoryDomain Domain { get { return _domain; } }
|
||||
|
||||
public string DomainName { get { return _domain != null ? _domain.Name : String.Empty; } }
|
||||
|
||||
public virtual int? Address { get { return _address; } }
|
||||
|
||||
public virtual string AddressString { get { return _address.ToString(AddressFormatStr); } }
|
||||
|
||||
public virtual bool IsSeparator { get { return false; } }
|
||||
|
||||
public char SizeAsChar
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
default:
|
||||
case WatchSize.Separator:
|
||||
return 'S';
|
||||
case WatchSize.Byte:
|
||||
return 'b';
|
||||
case WatchSize.Word:
|
||||
return 'w';
|
||||
case WatchSize.DWord:
|
||||
return 'd';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static WatchSize SizeFromChar(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
default:
|
||||
case 'S':
|
||||
return WatchSize.Separator;
|
||||
case 'b':
|
||||
return WatchSize.Byte;
|
||||
case 'w':
|
||||
return WatchSize.Word;
|
||||
case 'd':
|
||||
return WatchSize.DWord;
|
||||
}
|
||||
}
|
||||
|
||||
public char TypeAsChar
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
default:
|
||||
case DisplayType.Separator:
|
||||
return '_';
|
||||
case DisplayType.Unsigned:
|
||||
return 's';
|
||||
case DisplayType.Signed:
|
||||
return 'u';
|
||||
case DisplayType.Hex:
|
||||
return 'h';
|
||||
case DisplayType.Binary:
|
||||
return 'b';
|
||||
case DisplayType.FixedPoint_12_4:
|
||||
return '1';
|
||||
case DisplayType.FixedPoint_20_12:
|
||||
return '2';
|
||||
case DisplayType.Float:
|
||||
return 'f';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DisplayType DisplayTypeFromChar(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
default:
|
||||
case '_':
|
||||
return DisplayType.Separator;
|
||||
case 'u':
|
||||
return DisplayType.Unsigned;
|
||||
case 's':
|
||||
return DisplayType.Signed;
|
||||
case 'h':
|
||||
return DisplayType.Hex;
|
||||
case 'b':
|
||||
return DisplayType.Binary;
|
||||
case '1':
|
||||
return DisplayType.FixedPoint_12_4;
|
||||
case '2':
|
||||
return DisplayType.FixedPoint_20_12;
|
||||
case 'f':
|
||||
return DisplayType.Float;
|
||||
}
|
||||
}
|
||||
|
||||
public string AddressFormatStr
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_domain != null)
|
||||
{
|
||||
return "X" + IntHelpers.GetNumDigits(_domain.Size - 1).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte GetByte()
|
||||
{
|
||||
return _domain.PeekByte(_address);
|
||||
}
|
||||
|
||||
protected ushort GetWord()
|
||||
{
|
||||
return _domain.PeekWord(_address, _bigEndian ? Endian.Big : Endian.Little);
|
||||
}
|
||||
|
||||
protected uint GetDWord()
|
||||
{
|
||||
return _domain.PeekDWord(_address, _bigEndian ? Endian.Big : Endian.Little);
|
||||
}
|
||||
|
||||
protected void PokeByte(byte val)
|
||||
{
|
||||
_domain.PokeByte(_address, val);
|
||||
}
|
||||
|
||||
protected void PokeWord(ushort val)
|
||||
{
|
||||
_domain.PokeWord(_address, val, _bigEndian ? Endian.Big : Endian.Little);
|
||||
}
|
||||
|
||||
protected void PokeDWord(uint val)
|
||||
{
|
||||
_domain.PokeDWord(_address, val, _bigEndian ? Endian.Big : Endian.Little);
|
||||
}
|
||||
|
||||
public void ClearChangeCount() { _changecount = 0; }
|
||||
|
||||
public string Notes { get { return _notes; } set { _notes = value; } }
|
||||
|
||||
public static Watch GenerateWatch(MemoryDomain domain, int address, WatchSize size, DisplayType type, string notes, bool bigEndian)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
default:
|
||||
case WatchSize.Separator:
|
||||
return SeparatorWatch.Instance;
|
||||
case WatchSize.Byte:
|
||||
return new ByteWatch(domain, address, type, bigEndian, notes);
|
||||
case WatchSize.Word:
|
||||
return new WordWatch(domain, address, type, bigEndian, notes);
|
||||
case WatchSize.DWord:
|
||||
return new DWordWatch(domain, address, type, bigEndian, notes);
|
||||
}
|
||||
}
|
||||
|
||||
public static Watch GenerateWatch(MemoryDomain domain, int address, WatchSize size, DisplayType type, bool bigendian, int prev, int changecount)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
default:
|
||||
case WatchSize.Separator:
|
||||
return SeparatorWatch.Instance;
|
||||
case WatchSize.Byte:
|
||||
return new ByteWatch(domain, address, type, bigendian, (byte)prev, changecount);
|
||||
case WatchSize.Word:
|
||||
return new WordWatch(domain, address, type, bigendian, (ushort)prev, changecount);
|
||||
case WatchSize.DWord:
|
||||
return new DWordWatch(domain, address, type, bigendian, (uint)prev, changecount);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<DisplayType> AvailableTypes(WatchSize size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
default:
|
||||
case WatchSize.Separator:
|
||||
return SeparatorWatch.ValidTypes;
|
||||
case WatchSize.Byte:
|
||||
return ByteWatch.ValidTypes;
|
||||
case WatchSize.Word:
|
||||
return WordWatch.ValidTypes;
|
||||
case WatchSize.DWord:
|
||||
return DWordWatch.ValidTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public int ChangeCount { get { return _changecount; } }
|
||||
|
||||
public abstract string Diff { get; }
|
||||
|
||||
public abstract void Update();
|
||||
}
|
||||
|
||||
public sealed class SeparatorWatch : Watch
|
||||
{
|
||||
public static SeparatorWatch Instance
|
||||
{
|
||||
get { return new SeparatorWatch(); }
|
||||
}
|
||||
|
||||
public override int? Address
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override int? Value
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override int? Previous
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override string AddressString
|
||||
{
|
||||
get { return String.Empty; }
|
||||
}
|
||||
|
||||
public override string ValueString
|
||||
{
|
||||
get { return String.Empty; }
|
||||
}
|
||||
|
||||
public override string PreviousStr
|
||||
{
|
||||
get { return String.Empty; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "----";
|
||||
}
|
||||
|
||||
public override bool IsSeparator
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override WatchSize Size
|
||||
{
|
||||
get { return WatchSize.Separator; }
|
||||
}
|
||||
|
||||
public static List<DisplayType> ValidTypes
|
||||
{
|
||||
get { return new List<DisplayType> { DisplayType.Separator }; }
|
||||
}
|
||||
|
||||
public override DisplayType Type
|
||||
{
|
||||
get { return DisplayType.Separator; }
|
||||
}
|
||||
|
||||
public override bool Poke(string value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void ResetPrevious()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public override string Diff { get { return String.Empty; } }
|
||||
|
||||
public override void Update() { return; }
|
||||
}
|
||||
|
||||
public sealed class ByteWatch : Watch
|
||||
{
|
||||
private byte _previous;
|
||||
private byte _value;
|
||||
|
||||
public ByteWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, string notes)
|
||||
{
|
||||
_address = address;
|
||||
_domain = domain;
|
||||
_value = _previous = GetByte();
|
||||
if (AvailableTypes(WatchSize.Byte).Contains(type))
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
_bigEndian = bigEndian;
|
||||
if (notes != null)
|
||||
{
|
||||
Notes = notes;
|
||||
}
|
||||
}
|
||||
|
||||
public ByteWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, byte prev, int changeCount, string notes = null)
|
||||
: this(domain, address, type, bigEndian, notes)
|
||||
{
|
||||
_previous = prev;
|
||||
_changecount = changeCount;
|
||||
}
|
||||
|
||||
public override int? Address
|
||||
{
|
||||
get { return _address; }
|
||||
}
|
||||
|
||||
public override int? Value
|
||||
{
|
||||
get { return GetByte(); }
|
||||
}
|
||||
|
||||
public override string ValueString
|
||||
{
|
||||
get { return FormatValue(GetByte()); }
|
||||
}
|
||||
|
||||
public override int? Previous
|
||||
{
|
||||
get { return _previous; }
|
||||
}
|
||||
|
||||
public override string PreviousStr
|
||||
{
|
||||
get { return FormatValue(_previous); }
|
||||
}
|
||||
|
||||
public override void ResetPrevious()
|
||||
{
|
||||
_previous = GetByte();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Notes + ": " + ValueString;
|
||||
}
|
||||
|
||||
public override bool IsSeparator
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override WatchSize Size
|
||||
{
|
||||
get { return WatchSize.Byte; }
|
||||
}
|
||||
|
||||
public static List<DisplayType> ValidTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<DisplayType>
|
||||
{
|
||||
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.Binary
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public string FormatValue(byte val)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
default:
|
||||
case DisplayType.Unsigned:
|
||||
return val.ToString();
|
||||
case DisplayType.Signed:
|
||||
return ((sbyte)val).ToString();
|
||||
case DisplayType.Hex:
|
||||
return String.Format("{0:X2}", val);
|
||||
case DisplayType.Binary:
|
||||
return Convert.ToString(val, 2).PadLeft(8, '0').Insert(4, " ");
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Poke(string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte val = 0;
|
||||
switch (Type)
|
||||
{
|
||||
case DisplayType.Unsigned:
|
||||
if (InputValidate.IsValidUnsignedNumber(value))
|
||||
{
|
||||
val = (byte)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Signed:
|
||||
if (InputValidate.IsValidSignedNumber(value))
|
||||
{
|
||||
val = (byte)(sbyte)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Hex:
|
||||
if (InputValidate.IsValidHexNumber(value))
|
||||
{
|
||||
val = (byte)int.Parse(value, NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Binary:
|
||||
if (InputValidate.IsValidBinaryNumber(value))
|
||||
{
|
||||
val = (byte)Convert.ToInt32(value, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
PokeByte(val);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Diff
|
||||
{
|
||||
get
|
||||
{
|
||||
string diff = String.Empty;
|
||||
int diffVal = _value - _previous;
|
||||
if (diffVal > 0)
|
||||
{
|
||||
diff = "+";
|
||||
}
|
||||
else if (diffVal < 0)
|
||||
{
|
||||
diff = "-";
|
||||
}
|
||||
return diff + FormatValue((byte)(_previous - _value));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
switch (Global.Config.RamWatchDefinePrevious)
|
||||
{
|
||||
case PreviousType.Original:
|
||||
return;
|
||||
case PreviousType.LastChange:
|
||||
var temp = _value;
|
||||
_value = GetByte();
|
||||
if (_value != temp)
|
||||
{
|
||||
_previous = _value;
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
case PreviousType.LastFrame:
|
||||
_previous = _value;
|
||||
_value = GetByte();
|
||||
if (_value != Previous)
|
||||
{
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WordWatch : Watch
|
||||
{
|
||||
private ushort _previous;
|
||||
private ushort _value;
|
||||
|
||||
public WordWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, string notes)
|
||||
{
|
||||
_domain = domain;
|
||||
_address = address;
|
||||
_value = _previous = GetWord();
|
||||
|
||||
if (AvailableTypes(WatchSize.Word).Contains(type))
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
_bigEndian = bigEndian;
|
||||
|
||||
if (notes != null)
|
||||
{
|
||||
Notes = notes;
|
||||
}
|
||||
}
|
||||
|
||||
public WordWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, ushort prev, int changeCount, string notes = null)
|
||||
: this(domain, address, type, bigEndian, notes)
|
||||
{
|
||||
_previous = prev;
|
||||
_changecount = changeCount;
|
||||
}
|
||||
|
||||
public override int? Value
|
||||
{
|
||||
get { return GetWord(); }
|
||||
}
|
||||
|
||||
public override int? Previous
|
||||
{
|
||||
get { return _previous; }
|
||||
}
|
||||
|
||||
public override string PreviousStr
|
||||
{
|
||||
get { return FormatValue(_previous); }
|
||||
}
|
||||
|
||||
public override void ResetPrevious()
|
||||
{
|
||||
_previous = GetWord();
|
||||
}
|
||||
|
||||
public override WatchSize Size
|
||||
{
|
||||
get { return WatchSize.Word; }
|
||||
}
|
||||
|
||||
public static List<DisplayType> ValidTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<DisplayType>
|
||||
{
|
||||
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_12_4, DisplayType.Binary
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ValueString
|
||||
{
|
||||
get { return FormatValue(GetWord()); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Notes + ": " + ValueString;
|
||||
}
|
||||
|
||||
public string FormatValue(ushort val)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
default:
|
||||
case DisplayType.Unsigned:
|
||||
return val.ToString();
|
||||
case DisplayType.Signed:
|
||||
return ((short)val).ToString();
|
||||
case DisplayType.Hex:
|
||||
return String.Format("{0:X4}", val);
|
||||
case DisplayType.FixedPoint_12_4:
|
||||
return String.Format("{0:F4}", (val / 16.0));
|
||||
case DisplayType.Binary:
|
||||
return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " ");
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Poke(string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
ushort val = 0;
|
||||
switch (Type)
|
||||
{
|
||||
case DisplayType.Unsigned:
|
||||
if (InputValidate.IsValidUnsignedNumber(value))
|
||||
{
|
||||
val = (ushort)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Signed:
|
||||
if (InputValidate.IsValidSignedNumber(value))
|
||||
{
|
||||
val = (ushort)(short)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Hex:
|
||||
if (InputValidate.IsValidHexNumber(value))
|
||||
{
|
||||
val = (ushort)int.Parse(value, NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Binary:
|
||||
if (InputValidate.IsValidBinaryNumber(value))
|
||||
{
|
||||
val = (ushort)Convert.ToInt32(value, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.FixedPoint_12_4:
|
||||
if (InputValidate.IsValidFixedPointNumber(value))
|
||||
{
|
||||
val = (ushort)(double.Parse(value) * 16.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
PokeWord(val);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Diff
|
||||
{
|
||||
get { return FormatValue((ushort)(_previous - _value)); }
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
switch (Global.Config.RamWatchDefinePrevious)
|
||||
{
|
||||
case PreviousType.Original:
|
||||
return;
|
||||
case PreviousType.LastChange:
|
||||
var temp = _value;
|
||||
_value = GetWord();
|
||||
|
||||
if (_value != temp)
|
||||
{
|
||||
_previous = temp;
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
case PreviousType.LastFrame:
|
||||
_previous = _value;
|
||||
_value = GetWord();
|
||||
if (_value != Previous)
|
||||
{
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DWordWatch : Watch
|
||||
{
|
||||
private uint _value;
|
||||
private uint _previous;
|
||||
|
||||
public DWordWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, string notes)
|
||||
{
|
||||
_domain = domain;
|
||||
_address = address;
|
||||
_value = _previous = GetDWord();
|
||||
|
||||
if (AvailableTypes(WatchSize.DWord).Contains(type))
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
_bigEndian = bigEndian;
|
||||
|
||||
if (notes != null)
|
||||
{
|
||||
Notes = notes;
|
||||
}
|
||||
}
|
||||
|
||||
public DWordWatch(MemoryDomain domain, int address, DisplayType type, bool bigEndian, uint prev, int changeCount, string notes = null)
|
||||
: this(domain, address, type, bigEndian, notes)
|
||||
{
|
||||
_previous = prev;
|
||||
_changecount = changeCount;
|
||||
_type = type;
|
||||
_bigEndian = bigEndian;
|
||||
}
|
||||
|
||||
public override int? Value
|
||||
{
|
||||
get { return (int)GetDWord(); }
|
||||
}
|
||||
|
||||
public override int? Previous
|
||||
{
|
||||
get { return (int)_previous; }
|
||||
}
|
||||
|
||||
public override string PreviousStr
|
||||
{
|
||||
get { return FormatValue(_previous); }
|
||||
}
|
||||
|
||||
public override void ResetPrevious()
|
||||
{
|
||||
_previous = GetWord();
|
||||
}
|
||||
|
||||
public override WatchSize Size
|
||||
{
|
||||
get { return WatchSize.DWord; }
|
||||
}
|
||||
|
||||
public static List<DisplayType> ValidTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<DisplayType>
|
||||
{
|
||||
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_20_12, DisplayType.Float
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ValueString
|
||||
{
|
||||
get { return FormatValue(GetDWord()); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Notes + ": " + ValueString;
|
||||
}
|
||||
|
||||
public string FormatValue(uint val)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
default:
|
||||
case DisplayType.Unsigned:
|
||||
return val.ToString();
|
||||
case DisplayType.Signed:
|
||||
return ((int)val).ToString();
|
||||
case DisplayType.Hex:
|
||||
return String.Format("{0:X8}", val);
|
||||
case DisplayType.FixedPoint_20_12:
|
||||
return String.Format("{0:0.######}", (val / 4096.0));
|
||||
case DisplayType.Float:
|
||||
byte[] bytes = BitConverter.GetBytes(val);
|
||||
float _float = BitConverter.ToSingle(bytes, 0);
|
||||
return String.Format("{0:0.######}", _float);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Poke(string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
uint val = 0;
|
||||
switch (Type)
|
||||
{
|
||||
case DisplayType.Unsigned:
|
||||
if (InputValidate.IsValidUnsignedNumber(value))
|
||||
{
|
||||
val = (uint)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Signed:
|
||||
if (InputValidate.IsValidSignedNumber(value))
|
||||
{
|
||||
val = (uint)int.Parse(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Hex:
|
||||
if (InputValidate.IsValidHexNumber(value))
|
||||
{
|
||||
val = (uint)int.Parse(value, NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.FixedPoint_20_12:
|
||||
if (InputValidate.IsValidFixedPointNumber(value))
|
||||
{
|
||||
val = (uint)(int)(double.Parse(value) * 4096.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DisplayType.Float:
|
||||
if (InputValidate.IsValidDecimalNumber(value))
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(float.Parse(value));
|
||||
val = BitConverter.ToUInt32(bytes, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
PokeDWord(val);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Diff
|
||||
{
|
||||
get { return FormatValue(_previous - _value); }
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
switch (Global.Config.RamWatchDefinePrevious)
|
||||
{
|
||||
case PreviousType.Original:
|
||||
return;
|
||||
case PreviousType.LastChange:
|
||||
var temp = _value;
|
||||
_value = GetDWord();
|
||||
if (_value != temp)
|
||||
{
|
||||
_previous = _value;
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
case PreviousType.LastFrame:
|
||||
_previous = _value;
|
||||
_value = GetDWord();
|
||||
if (_value != Previous)
|
||||
{
|
||||
_changecount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue