This commit is contained in:
zeromus 2013-10-25 00:59:34 +00:00
parent 1a2b2c3dc5
commit 6616a75cfb
73 changed files with 24657 additions and 0 deletions

View File

@ -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();
}
}
}

View File

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

View File

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

View File

@ -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&lt;file stream, name of the archive entry&gt;</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&lt;file stream, name of the archive entry&gt;</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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}
}

View File

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

View File

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

View File

@ -0,0 +1 @@
Test

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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);
}
}
}

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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];
}
}
}

View File

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

View File

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

View File

@ -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(); }
}
}

View File

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

View File

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

View File

@ -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 &lt;= x &lt;= 4).
/// </summary>
PosStateBits,
/// <summary>
/// Specifies number of literal context bits for LZMA (0 &lt;= x &lt;= 8).
/// </summary>
LitContextBits,
/// <summary>
/// Specifies number of literal position bits for LZMA (0 &lt;= x &lt;= 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);
}
}

View File

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

View File

@ -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);
}
}
}

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

@ -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")]

View File

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

View File

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

View File

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

View File

@ -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);
}
}
}
}

View File

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

View File

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

View File

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

View File

@ -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();
}
}
}

View File

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

View File

@ -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);
}
}
}

View File

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

View File

@ -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();
}
}
}

View File

@ -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());
}
}
}
}

View File

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

View File

@ -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";
}
}

View File

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