mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
[FileTypes/] Cleanup tabs AND variables
This commit is contained in:
@@ -12,123 +12,123 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
public abstract class BaseArchive : Folder
|
public abstract class BaseArchive : Folder
|
||||||
{
|
{
|
||||||
#region Protected instance variables
|
#region Protected instance variables
|
||||||
|
|
||||||
// Buffer size used by archives
|
// Buffer size used by archives
|
||||||
protected const int _bufferSize = 4096 * 128;
|
protected const int _bufferSize = 4096 * 128;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Construtors
|
#region Construtors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new Archive with no base file
|
/// Create a new Archive with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BaseArchive()
|
public BaseArchive()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new Archive from the given file
|
/// Create a new Archive from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public BaseArchive(string filename, bool getHashes = false)
|
public BaseArchive(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public override abstract bool CopyAll(string outDir);
|
public override abstract bool CopyAll(string outDir);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract an entry from an archive
|
/// Attempt to extract an entry from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public override abstract string CopyToFile(string entryName, string outDir);
|
public override abstract string CopyToFile(string entryName, string outDir);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public override abstract (MemoryStream, string) CopyToStream(string entryName);
|
public override abstract (MemoryStream, string) CopyToStream(string entryName);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of DatItem objects from the header values in an archive
|
/// Generate a list of DatItem objects from the header values in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of DatItem objects representing the found data</returns>
|
/// <returns>List of DatItem objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public override abstract List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false);
|
public override abstract List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the archive</returns>
|
/// <returns>List of empty folders in the archive</returns>
|
||||||
public override abstract List<string> GetEmptyFolders();
|
public override abstract List<string> GetEmptyFolders();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the input file is a standardized format
|
/// Check whether the input file is a standardized format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool IsTorrent();
|
public abstract bool IsTorrent();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to an archive
|
/// Write an input file to an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override abstract bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false);
|
public override abstract bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to an archive
|
/// Write an input stream to an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override abstract bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false);
|
public override abstract bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to an archive (assuming the same output archive name)
|
/// Write a set of input files to an archive (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override abstract bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false);
|
public override abstract bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,151 +9,115 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
public class BaseFile
|
public class BaseFile
|
||||||
{
|
{
|
||||||
#region Protected instance variables
|
#region Publicly facing variables
|
||||||
|
|
||||||
protected FileType _fileType;
|
// TODO: Get all of these values automatically so there is no public "set"
|
||||||
protected string _filename;
|
public FileType Type { get; protected set; }
|
||||||
protected string _parent;
|
public string Filename { get; set; }
|
||||||
protected string _date;
|
public string Parent { get; set; }
|
||||||
|
public string Date { get; set; }
|
||||||
|
public long? Size { get; set; }
|
||||||
|
public byte[] CRC { get; set; }
|
||||||
|
public byte[] MD5 { get; set; }
|
||||||
|
public byte[] SHA1 { get; set; }
|
||||||
|
public byte[] SHA256 { get; set; }
|
||||||
|
public byte[] SHA384 { get; set; }
|
||||||
|
public byte[] SHA512 { get; set; }
|
||||||
|
|
||||||
// External hash values for the file
|
#endregion
|
||||||
protected long? _size;
|
|
||||||
protected byte[] _crc;
|
|
||||||
protected byte[] _md5;
|
|
||||||
protected byte[] _sha1;
|
|
||||||
protected byte[] _sha256;
|
|
||||||
protected byte[] _sha384;
|
|
||||||
protected byte[] _sha512;
|
|
||||||
|
|
||||||
#endregion
|
#region Construtors
|
||||||
|
|
||||||
#region Publicly facing variables
|
/// <summary>
|
||||||
|
/// Create a new BaseFile with no base file
|
||||||
|
/// </summary>
|
||||||
|
public BaseFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get all of these values automatically so there is no public "set"
|
/// <summary>
|
||||||
public FileType Type
|
/// Create a new BaseFile from the given file
|
||||||
{
|
/// </summary>
|
||||||
get { return _fileType; }
|
/// <param name="filename">Name of the file to use</param>
|
||||||
}
|
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
||||||
public string Filename
|
public BaseFile(string filename, bool getHashes = true)
|
||||||
{
|
{
|
||||||
get { return _filename; }
|
this.Filename = filename;
|
||||||
set { _filename = value; }
|
|
||||||
}
|
|
||||||
public string Parent
|
|
||||||
{
|
|
||||||
get { return _parent; }
|
|
||||||
set { _parent = value; }
|
|
||||||
}
|
|
||||||
public string Date
|
|
||||||
{
|
|
||||||
get { return _date; }
|
|
||||||
set { _date = value; }
|
|
||||||
}
|
|
||||||
public long? Size
|
|
||||||
{
|
|
||||||
get { return _size; }
|
|
||||||
set { _size = value; }
|
|
||||||
}
|
|
||||||
public byte[] CRC
|
|
||||||
{
|
|
||||||
get { return _crc; }
|
|
||||||
set { _crc = value; }
|
|
||||||
}
|
|
||||||
public byte[] MD5
|
|
||||||
{
|
|
||||||
get { return _md5; }
|
|
||||||
set { _md5 = value; }
|
|
||||||
}
|
|
||||||
public byte[] SHA1
|
|
||||||
{
|
|
||||||
get { return _sha1; }
|
|
||||||
set { _sha1 = value; }
|
|
||||||
}
|
|
||||||
public byte[] SHA256
|
|
||||||
{
|
|
||||||
get { return _sha256; }
|
|
||||||
set { _sha256 = value; }
|
|
||||||
}
|
|
||||||
public byte[] SHA384
|
|
||||||
{
|
|
||||||
get { return _sha384; }
|
|
||||||
set { _sha384 = value; }
|
|
||||||
}
|
|
||||||
public byte[] SHA512
|
|
||||||
{
|
|
||||||
get { return _sha512; }
|
|
||||||
set { _sha512 = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
if (getHashes)
|
||||||
|
{
|
||||||
|
BaseFile temp = Utilities.GetFileInfo(this.Filename);
|
||||||
|
|
||||||
#region Construtors
|
if (temp != null)
|
||||||
|
{
|
||||||
|
this.Parent = temp.Parent;
|
||||||
|
this.Date = temp.Date;
|
||||||
|
this.CRC = temp.CRC;
|
||||||
|
this.MD5 = temp.MD5;
|
||||||
|
this.SHA1 = temp.SHA1;
|
||||||
|
this.SHA256 = temp.SHA256;
|
||||||
|
this.SHA384 = temp.SHA384;
|
||||||
|
this.SHA512 = temp.SHA512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new BaseFile with no base file
|
/// Create a new BaseFile from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BaseFile()
|
/// <param name="filename">Name of the file to use</param>
|
||||||
{
|
/// <param name="stream">Stream to populate information from</param>
|
||||||
}
|
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
||||||
|
public BaseFile(string filename, Stream stream, bool getHashes = true)
|
||||||
|
{
|
||||||
|
this.Filename = filename;
|
||||||
|
|
||||||
/// <summary>
|
if (getHashes)
|
||||||
/// Create a new BaseFile from the given file
|
{
|
||||||
/// </summary>
|
BaseFile temp = Utilities.GetStreamInfo(stream, stream.Length);
|
||||||
/// <param name="filename">Name of the file to use</param>
|
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
|
||||||
public BaseFile(string filename, bool getHashes = true)
|
|
||||||
{
|
|
||||||
this._filename = filename;
|
|
||||||
|
|
||||||
if (getHashes)
|
if(temp != null)
|
||||||
{
|
{
|
||||||
BaseFile temp = Utilities.GetFileInfo(_filename);
|
this.Parent = temp.Parent;
|
||||||
|
this.Date = temp.Date;
|
||||||
|
this.CRC = temp.CRC;
|
||||||
|
this.MD5 = temp.MD5;
|
||||||
|
this.SHA1 = temp.SHA1;
|
||||||
|
this.SHA256 = temp.SHA256;
|
||||||
|
this.SHA384 = temp.SHA384;
|
||||||
|
this.SHA512 = temp.SHA512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (temp != null)
|
/// <summary>
|
||||||
{
|
/// Create a new BaseFile from the given metadata
|
||||||
this._parent = temp.Parent;
|
/// </summary>
|
||||||
this._date = temp.Date;
|
/// <param name="filename">Name of the file to use</param>
|
||||||
this._crc = temp.CRC;
|
/// <param name="parent">Parent folder or archive</param>
|
||||||
this._md5 = temp.MD5;
|
/// <param name="date">File date</param>
|
||||||
this._sha1 = temp.SHA1;
|
/// <param name="crc">CRC hash as a byte array</param>
|
||||||
this._sha256 = temp.SHA256;
|
/// <param name="md5">MD5 hash as a byte array</param>
|
||||||
this._sha384 = temp.SHA384;
|
/// <param name="sha1">SHA-1 hash as a byte array</param>
|
||||||
this._sha512 = temp.SHA512;
|
/// <param name="sha256">SHA-256 hash as a byte array</param>
|
||||||
}
|
/// <param name="sha384">SHA-384 hash as a byte array</param>
|
||||||
}
|
/// <param name="sha512">SHA-512 hash as a byte array</param>
|
||||||
}
|
public BaseFile(string filename, string parent, string date, byte[] crc, byte[] md5, byte[] sha1, byte[] sha256, byte[] sha384, byte[] sha512)
|
||||||
|
{
|
||||||
|
this.Filename = filename;
|
||||||
|
this.Parent = parent;
|
||||||
|
this.Date = date;
|
||||||
|
this.CRC = crc;
|
||||||
|
this.MD5 = md5;
|
||||||
|
this.SHA1 = sha1;
|
||||||
|
this.SHA256 = sha256;
|
||||||
|
this.SHA384 = sha384;
|
||||||
|
this.SHA512 = sha512;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
#endregion
|
||||||
/// Create a new BaseFile from the given file
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">Name of the file to use</param>
|
|
||||||
/// <param name="stream">Stream to populate information from</param>
|
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
|
||||||
public BaseFile(string filename, Stream stream, bool getHashes = true)
|
|
||||||
{
|
|
||||||
this._filename = filename;
|
|
||||||
|
|
||||||
if (getHashes)
|
|
||||||
{
|
|
||||||
BaseFile temp = Utilities.GetStreamInfo(stream, stream.Length);
|
|
||||||
|
|
||||||
if(temp != null)
|
|
||||||
{
|
|
||||||
this._parent = temp.Parent;
|
|
||||||
this._date = temp.Date;
|
|
||||||
this._crc = temp.CRC;
|
|
||||||
this._md5 = temp.MD5;
|
|
||||||
this._sha1 = temp.SHA1;
|
|
||||||
this._sha256 = temp.SHA256;
|
|
||||||
this._sha384 = temp.SHA384;
|
|
||||||
this._sha512 = temp.SHA512;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,491 +11,491 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is code adapted from chd.h and chd.cpp in MAME
|
/// This is code adapted from chd.h and chd.cpp in MAME
|
||||||
/// Additional archival code from https://github.com/rtissera/libchdr/blob/master/src/chd.h
|
/// Additional archival code from https://github.com/rtissera/libchdr/blob/master/src/chd.h
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// Common CHD Header:
|
/// Common CHD Header:
|
||||||
/// 0x00-0x07 - CHD signature
|
/// 0x00-0x07 - CHD signature
|
||||||
/// 0x08-0x0B - Header size
|
/// 0x08-0x0B - Header size
|
||||||
/// 0x0C-0x0F - CHD version
|
/// 0x0C-0x0F - CHD version
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// CHD v1 header layout:
|
/// CHD v1 header layout:
|
||||||
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
|
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
|
||||||
/// 0x14-0x17 - Compression
|
/// 0x14-0x17 - Compression
|
||||||
/// 0x18-0x1B - 512-byte sectors per hunk
|
/// 0x18-0x1B - 512-byte sectors per hunk
|
||||||
/// 0x1C-0x1F - Hunk count
|
/// 0x1C-0x1F - Hunk count
|
||||||
/// 0x20-0x23 - Hard disk cylinder count
|
/// 0x20-0x23 - Hard disk cylinder count
|
||||||
/// 0x24-0x27 - Hard disk head count
|
/// 0x24-0x27 - Hard disk head count
|
||||||
/// 0x28-0x2B - Hard disk sector count
|
/// 0x28-0x2B - Hard disk sector count
|
||||||
/// 0x2C-0x3B - MD5
|
/// 0x2C-0x3B - MD5
|
||||||
/// 0x3C-0x4B - Parent MD5
|
/// 0x3C-0x4B - Parent MD5
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// CHD v2 header layout:
|
/// CHD v2 header layout:
|
||||||
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
|
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
|
||||||
/// 0x14-0x17 - Compression
|
/// 0x14-0x17 - Compression
|
||||||
/// 0x18-0x1B - seclen-byte sectors per hunk
|
/// 0x18-0x1B - seclen-byte sectors per hunk
|
||||||
/// 0x1C-0x1F - Hunk count
|
/// 0x1C-0x1F - Hunk count
|
||||||
/// 0x20-0x23 - Hard disk cylinder count
|
/// 0x20-0x23 - Hard disk cylinder count
|
||||||
/// 0x24-0x27 - Hard disk head count
|
/// 0x24-0x27 - Hard disk head count
|
||||||
/// 0x28-0x2B - Hard disk sector count
|
/// 0x28-0x2B - Hard disk sector count
|
||||||
/// 0x2C-0x3B - MD5
|
/// 0x2C-0x3B - MD5
|
||||||
/// 0x3C-0x4B - Parent MD5
|
/// 0x3C-0x4B - Parent MD5
|
||||||
/// 0x4C-0x4F - Number of bytes per sector (seclen)
|
/// 0x4C-0x4F - Number of bytes per sector (seclen)
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// CHD v3 header layout:
|
/// CHD v3 header layout:
|
||||||
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
|
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
|
||||||
/// 0x14-0x17 - Compression
|
/// 0x14-0x17 - Compression
|
||||||
/// 0x18-0x1B - Hunk count
|
/// 0x18-0x1B - Hunk count
|
||||||
/// 0x1C-0x23 - Logical Bytes
|
/// 0x1C-0x23 - Logical Bytes
|
||||||
/// 0x24-0x2C - Metadata Offset
|
/// 0x24-0x2C - Metadata Offset
|
||||||
/// ...
|
/// ...
|
||||||
/// 0x4C-0x4F - Hunk Bytes
|
/// 0x4C-0x4F - Hunk Bytes
|
||||||
/// 0x50-0x63 - SHA-1
|
/// 0x50-0x63 - SHA-1
|
||||||
/// 0x64-0x77 - Parent SHA-1
|
/// 0x64-0x77 - Parent SHA-1
|
||||||
/// 0x78-0x87 - Map
|
/// 0x78-0x87 - Map
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// CHD v4 header layout:
|
/// CHD v4 header layout:
|
||||||
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
|
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
|
||||||
/// 0x14-0x17 - Compression
|
/// 0x14-0x17 - Compression
|
||||||
/// 0x18-0x1B - Hunk count
|
/// 0x18-0x1B - Hunk count
|
||||||
/// 0x1C-0x23 - Logical Bytes
|
/// 0x1C-0x23 - Logical Bytes
|
||||||
/// 0x24-0x2C - Metadata Offset
|
/// 0x24-0x2C - Metadata Offset
|
||||||
/// ...
|
/// ...
|
||||||
/// 0x2C-0x2F - Hunk Bytes
|
/// 0x2C-0x2F - Hunk Bytes
|
||||||
/// 0x30-0x43 - SHA-1
|
/// 0x30-0x43 - SHA-1
|
||||||
/// 0x44-0x57 - Parent SHA-1
|
/// 0x44-0x57 - Parent SHA-1
|
||||||
/// 0x58-0x6b - Raw SHA-1
|
/// 0x58-0x6b - Raw SHA-1
|
||||||
/// 0x6c-0x7b - Map
|
/// 0x6c-0x7b - Map
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// CHD v5 header layout:
|
/// CHD v5 header layout:
|
||||||
/// 0x10-0x13 - Compression format 1
|
/// 0x10-0x13 - Compression format 1
|
||||||
/// 0x14-0x17 - Compression format 2
|
/// 0x14-0x17 - Compression format 2
|
||||||
/// 0x18-0x1B - Compression format 3
|
/// 0x18-0x1B - Compression format 3
|
||||||
/// 0x1C-0x1F - Compression format 4
|
/// 0x1C-0x1F - Compression format 4
|
||||||
/// 0x20-0x27 - Logical Bytes
|
/// 0x20-0x27 - Logical Bytes
|
||||||
/// 0x28-0x2F - Map Offset
|
/// 0x28-0x2F - Map Offset
|
||||||
/// 0x30-0x37 - Metadata Offset
|
/// 0x30-0x37 - Metadata Offset
|
||||||
/// 0x38-0x3B - Hunk Bytes
|
/// 0x38-0x3B - Hunk Bytes
|
||||||
/// 0x3C-0x3F - Unit Bytes
|
/// 0x3C-0x3F - Unit Bytes
|
||||||
/// 0x40-0x53 - Raw SHA-1
|
/// 0x40-0x53 - Raw SHA-1
|
||||||
/// 0x54-0x67 - SHA-1
|
/// 0x54-0x67 - SHA-1
|
||||||
/// 0x68-0x7b - Parent SHA-1
|
/// 0x68-0x7b - Parent SHA-1
|
||||||
/// ----------------------------------------------
|
/// ----------------------------------------------
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class CHDFile : BaseFile
|
public class CHDFile : BaseFile
|
||||||
{
|
{
|
||||||
#region Private instance variables
|
#region Private instance variables
|
||||||
|
|
||||||
// Core parameters from the header
|
// Core parameters from the header
|
||||||
private byte[] m_signature; // signature
|
private byte[] m_signature; // signature
|
||||||
private uint m_headersize; // size of the header
|
private uint m_headersize; // size of the header
|
||||||
private uint m_version; // version of the header
|
private uint m_version; // version of the header
|
||||||
private ulong m_logicalbytes; // logical size of the raw CHD data in bytes
|
private ulong m_logicalbytes; // logical size of the raw CHD data in bytes
|
||||||
private ulong m_mapoffset; // offset of map
|
private ulong m_mapoffset; // offset of map
|
||||||
private ulong m_metaoffset; // offset to first metadata bit
|
private ulong m_metaoffset; // offset to first metadata bit
|
||||||
private uint m_sectorsperhunk; // number of sectors per hunk
|
private uint m_sectorsperhunk; // number of sectors per hunk
|
||||||
private uint m_hunkbytes; // size of each raw hunk in bytes
|
private uint m_hunkbytes; // size of each raw hunk in bytes
|
||||||
private ulong m_hunkcount; // number of hunks represented
|
private ulong m_hunkcount; // number of hunks represented
|
||||||
private uint m_unitbytes; // size of each unit in bytes
|
private uint m_unitbytes; // size of each unit in bytes
|
||||||
private ulong m_unitcount; // number of units represented
|
private ulong m_unitcount; // number of units represented
|
||||||
private CHD_CODEC[] m_compression = new CHD_CODEC[4]; // array of compression types used
|
private CHD_CODEC[] m_compression = new CHD_CODEC[4]; // array of compression types used
|
||||||
|
|
||||||
// map information
|
// map information
|
||||||
private uint m_mapentrybytes; // length of each entry in a map
|
private uint m_mapentrybytes; // length of each entry in a map
|
||||||
|
|
||||||
// additional required vars
|
// additional required vars
|
||||||
private uint? _headerVersion;
|
private uint? _headerVersion;
|
||||||
private BinaryReader m_br; // Binary reader representing the CHD stream
|
private BinaryReader m_br; // Binary reader representing the CHD stream
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Pubically facing variables
|
#region Pubically facing variables
|
||||||
|
|
||||||
public uint? Version
|
public uint? Version
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_headerVersion == null)
|
if (_headerVersion == null)
|
||||||
{
|
{
|
||||||
_headerVersion = ValidateHeaderVersion();
|
_headerVersion = ValidateHeaderVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _headerVersion;
|
return _headerVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new, blank CHDFile
|
/// Create a new, blank CHDFile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CHDFile()
|
public CHDFile()
|
||||||
{
|
{
|
||||||
this._fileType = FileType.CHD;
|
this.Type = FileType.CHD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new CHDFile from an input file
|
/// Create a new CHDFile from an input file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename"></param>
|
/// <param name="filename"></param>
|
||||||
public CHDFile(string filename)
|
public CHDFile(string filename)
|
||||||
: this(Utilities.TryOpenRead(filename))
|
: this(Utilities.TryOpenRead(filename))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new CHDFile from an input stream
|
/// Create a new CHDFile from an input stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="chdstream">Stream representing the CHD file</param>
|
/// <param name="chdstream">Stream representing the CHD file</param>
|
||||||
public CHDFile(Stream chdstream)
|
public CHDFile(Stream chdstream)
|
||||||
{
|
{
|
||||||
_fileType = FileType.CHD;
|
this.Type = FileType.CHD;
|
||||||
m_br = new BinaryReader(chdstream);
|
m_br = new BinaryReader(chdstream);
|
||||||
|
|
||||||
_headerVersion = ValidateHeaderVersion();
|
_headerVersion = ValidateHeaderVersion();
|
||||||
|
|
||||||
if (_headerVersion != null)
|
if (_headerVersion != null)
|
||||||
{
|
{
|
||||||
byte[] hash = GetHashFromHeader();
|
byte[] hash = GetHashFromHeader();
|
||||||
|
|
||||||
if (hash != null)
|
if (hash != null)
|
||||||
{
|
{
|
||||||
if (hash.Length == Constants.MD5Length)
|
if (hash.Length == Constants.MD5Length)
|
||||||
{
|
{
|
||||||
_md5 = hash;
|
this.MD5 = hash;
|
||||||
}
|
}
|
||||||
else if (hash.Length == Constants.SHA1Length)
|
else if (hash.Length == Constants.SHA1Length)
|
||||||
{
|
{
|
||||||
_sha1 = hash;
|
this.SHA1 = hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Header Parsing
|
#region Header Parsing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validate the initial signature, version, and header size
|
/// Validate the initial signature, version, and header size
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Unsigned int containing the version number, null if invalid</returns>
|
/// <returns>Unsigned int containing the version number, null if invalid</returns>
|
||||||
private uint? ValidateHeaderVersion()
|
private uint? ValidateHeaderVersion()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Seek to the beginning to make sure we're reading the correct bytes
|
// Seek to the beginning to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(0, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Read and verify the CHD signature
|
// Read and verify the CHD signature
|
||||||
m_signature = m_br.ReadBytes(8);
|
m_signature = m_br.ReadBytes(8);
|
||||||
|
|
||||||
// If no signature could be read, return null
|
// If no signature could be read, return null
|
||||||
if (m_signature == null || m_signature.Length == 0)
|
if (m_signature == null || m_signature.Length == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_signature.StartsWith(Constants.CHDSignature, exact: true))
|
if (!m_signature.StartsWith(Constants.CHDSignature, exact: true))
|
||||||
{
|
{
|
||||||
// throw CHDERR_INVALID_FILE;
|
// throw CHDERR_INVALID_FILE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the header size and version
|
// Get the header size and version
|
||||||
m_headersize = m_br.ReadUInt32Reverse();
|
m_headersize = m_br.ReadUInt32Reverse();
|
||||||
m_version = m_br.ReadUInt32Reverse();
|
m_version = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
// If we have an invalid combination of size and version
|
// If we have an invalid combination of size and version
|
||||||
if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE)
|
if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE)
|
||||||
|| (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE)
|
|| (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE)
|
||||||
|| (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE)
|
|| (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE)
|
||||||
|| (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE)
|
|| (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE)
|
||||||
|| (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE)
|
|| (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE)
|
||||||
|| (m_version < 1 || m_version > 5))
|
|| (m_version < 1 || m_version > 5))
|
||||||
{
|
{
|
||||||
// throw CHDERR_UNSUPPORTED_VERSION;
|
// throw CHDERR_UNSUPPORTED_VERSION;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_version;
|
return m_version;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the internal MD5 (v1, v2) or SHA-1 (v3, v4, v5) from the CHD
|
/// Get the internal MD5 (v1, v2) or SHA-1 (v3, v4, v5) from the CHD
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>MD5 as a byte array, null on error</returns>
|
/// <returns>MD5 as a byte array, null on error</returns>
|
||||||
private byte[] GetHashFromHeader()
|
private byte[] GetHashFromHeader()
|
||||||
{
|
{
|
||||||
// Validate the header by default just in case
|
// Validate the header by default just in case
|
||||||
uint? version = ValidateHeaderVersion();
|
uint? version = ValidateHeaderVersion();
|
||||||
|
|
||||||
// Now get the hash, if possible
|
// Now get the hash, if possible
|
||||||
byte[] hash;
|
byte[] hash;
|
||||||
|
|
||||||
// Now parse the rest of the header according to the version
|
// Now parse the rest of the header according to the version
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (version)
|
switch (version)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
hash = ParseCHDv1Header();
|
hash = ParseCHDv1Header();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
hash = ParseCHDv2Header();
|
hash = ParseCHDv2Header();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
hash = ParseCHDv3Header();
|
hash = ParseCHDv3Header();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
hash = ParseCHDv4Header();
|
hash = ParseCHDv4Header();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
hash = ParseCHDv5Header();
|
hash = ParseCHDv5Header();
|
||||||
break;
|
break;
|
||||||
case null:
|
case null:
|
||||||
default:
|
default:
|
||||||
// throw CHDERR_INVALID_FILE;
|
// throw CHDERR_INVALID_FILE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// throw CHDERR_INVALID_FILE;
|
// throw CHDERR_INVALID_FILE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a CHD v1 header
|
/// Parse a CHD v1 header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The extracted MD5 on success, null otherwise</returns>
|
/// <returns>The extracted MD5 on success, null otherwise</returns>
|
||||||
private byte[] ParseCHDv1Header()
|
private byte[] ParseCHDv1Header()
|
||||||
{
|
{
|
||||||
// Seek to after the signature to make sure we're reading the correct bytes
|
// Seek to after the signature to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Set the blank MD5 hash
|
// Set the blank MD5 hash
|
||||||
byte[] md5 = new byte[16];
|
byte[] md5 = new byte[16];
|
||||||
|
|
||||||
// Set offsets and defaults
|
// Set offsets and defaults
|
||||||
m_mapoffset = 0;
|
m_mapoffset = 0;
|
||||||
m_mapentrybytes = 0;
|
m_mapentrybytes = 0;
|
||||||
|
|
||||||
// Read the CHD flags
|
// Read the CHD flags
|
||||||
uint flags = m_br.ReadUInt32Reverse();
|
uint flags = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
// Determine compression
|
// Determine compression
|
||||||
switch (m_br.ReadUInt32())
|
switch (m_br.ReadUInt32())
|
||||||
{
|
{
|
||||||
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
||||||
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
||||||
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
||||||
|
|
||||||
m_sectorsperhunk = m_br.ReadUInt32Reverse();
|
m_sectorsperhunk = m_br.ReadUInt32Reverse();
|
||||||
m_hunkcount = m_br.ReadUInt32Reverse();
|
m_hunkcount = m_br.ReadUInt32Reverse();
|
||||||
m_br.ReadUInt32Reverse(); // Cylinder count
|
m_br.ReadUInt32Reverse(); // Cylinder count
|
||||||
m_br.ReadUInt32Reverse(); // Head count
|
m_br.ReadUInt32Reverse(); // Head count
|
||||||
m_br.ReadUInt32Reverse(); // Sector count
|
m_br.ReadUInt32Reverse(); // Sector count
|
||||||
|
|
||||||
md5 = m_br.ReadBytes(16);
|
md5 = m_br.ReadBytes(16);
|
||||||
m_br.ReadBytes(16); // Parent MD5
|
m_br.ReadBytes(16); // Parent MD5
|
||||||
|
|
||||||
return md5;
|
return md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a CHD v2 header
|
/// Parse a CHD v2 header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The extracted MD5 on success, null otherwise</returns>
|
/// <returns>The extracted MD5 on success, null otherwise</returns>
|
||||||
private byte[] ParseCHDv2Header()
|
private byte[] ParseCHDv2Header()
|
||||||
{
|
{
|
||||||
// Seek to after the signature to make sure we're reading the correct bytes
|
// Seek to after the signature to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Set the blank MD5 hash
|
// Set the blank MD5 hash
|
||||||
byte[] md5 = new byte[16];
|
byte[] md5 = new byte[16];
|
||||||
|
|
||||||
// Set offsets and defaults
|
// Set offsets and defaults
|
||||||
m_mapoffset = 0;
|
m_mapoffset = 0;
|
||||||
m_mapentrybytes = 0;
|
m_mapentrybytes = 0;
|
||||||
|
|
||||||
// Read the CHD flags
|
// Read the CHD flags
|
||||||
uint flags = m_br.ReadUInt32Reverse();
|
uint flags = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
// Determine compression
|
// Determine compression
|
||||||
switch (m_br.ReadUInt32())
|
switch (m_br.ReadUInt32())
|
||||||
{
|
{
|
||||||
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
||||||
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
||||||
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
||||||
|
|
||||||
m_sectorsperhunk = m_br.ReadUInt32Reverse();
|
m_sectorsperhunk = m_br.ReadUInt32Reverse();
|
||||||
m_hunkcount = m_br.ReadUInt32Reverse();
|
m_hunkcount = m_br.ReadUInt32Reverse();
|
||||||
m_br.ReadUInt32Reverse(); // Cylinder count
|
m_br.ReadUInt32Reverse(); // Cylinder count
|
||||||
m_br.ReadUInt32Reverse(); // Head count
|
m_br.ReadUInt32Reverse(); // Head count
|
||||||
m_br.ReadUInt32Reverse(); // Sector count
|
m_br.ReadUInt32Reverse(); // Sector count
|
||||||
|
|
||||||
md5 = m_br.ReadBytes(16);
|
md5 = m_br.ReadBytes(16);
|
||||||
m_br.ReadBytes(16); // Parent MD5
|
m_br.ReadBytes(16); // Parent MD5
|
||||||
m_br.ReadUInt32Reverse(); // Sector size
|
m_br.ReadUInt32Reverse(); // Sector size
|
||||||
|
|
||||||
return md5;
|
return md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a CHD v3 header
|
/// Parse a CHD v3 header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
||||||
private byte[] ParseCHDv3Header()
|
private byte[] ParseCHDv3Header()
|
||||||
{
|
{
|
||||||
// Seek to after the signature to make sure we're reading the correct bytes
|
// Seek to after the signature to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Set the blank SHA-1 hash
|
// Set the blank SHA-1 hash
|
||||||
byte[] sha1 = new byte[20];
|
byte[] sha1 = new byte[20];
|
||||||
|
|
||||||
// Set offsets and defaults
|
// Set offsets and defaults
|
||||||
m_mapoffset = 120;
|
m_mapoffset = 120;
|
||||||
m_mapentrybytes = 16;
|
m_mapentrybytes = 16;
|
||||||
|
|
||||||
// Read the CHD flags
|
// Read the CHD flags
|
||||||
uint flags = m_br.ReadUInt32Reverse();
|
uint flags = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
// Determine compression
|
// Determine compression
|
||||||
switch (m_br.ReadUInt32())
|
switch (m_br.ReadUInt32())
|
||||||
{
|
{
|
||||||
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
||||||
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
||||||
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
||||||
|
|
||||||
m_hunkcount = m_br.ReadUInt32Reverse();
|
m_hunkcount = m_br.ReadUInt32Reverse();
|
||||||
m_logicalbytes = m_br.ReadUInt64Reverse();
|
m_logicalbytes = m_br.ReadUInt64Reverse();
|
||||||
m_metaoffset = m_br.ReadUInt32Reverse();
|
m_metaoffset = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
m_br.BaseStream.Seek(76, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(76, SeekOrigin.Begin);
|
||||||
m_hunkbytes = m_br.ReadUInt32Reverse();
|
m_hunkbytes = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
m_br.BaseStream.Seek(Constants.CHDv3SHA1Offset, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(Constants.CHDv3SHA1Offset, SeekOrigin.Begin);
|
||||||
sha1 = m_br.ReadBytes(20);
|
sha1 = m_br.ReadBytes(20);
|
||||||
|
|
||||||
// guess at the units based on snooping the metadata
|
// guess at the units based on snooping the metadata
|
||||||
// m_unitbytes = guess_unitbytes();
|
// m_unitbytes = guess_unitbytes();
|
||||||
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
||||||
|
|
||||||
return sha1;
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a CHD v4 header
|
/// Parse a CHD v4 header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
||||||
private byte[] ParseCHDv4Header()
|
private byte[] ParseCHDv4Header()
|
||||||
{
|
{
|
||||||
// Seek to after the signature to make sure we're reading the correct bytes
|
// Seek to after the signature to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Set the blank SHA-1 hash
|
// Set the blank SHA-1 hash
|
||||||
byte[] sha1 = new byte[20];
|
byte[] sha1 = new byte[20];
|
||||||
|
|
||||||
// Set offsets and defaults
|
// Set offsets and defaults
|
||||||
m_mapoffset = 108;
|
m_mapoffset = 108;
|
||||||
m_mapentrybytes = 16;
|
m_mapentrybytes = 16;
|
||||||
|
|
||||||
// Read the CHD flags
|
// Read the CHD flags
|
||||||
uint flags = m_br.ReadUInt32Reverse();
|
uint flags = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
// Determine compression
|
// Determine compression
|
||||||
switch (m_br.ReadUInt32())
|
switch (m_br.ReadUInt32())
|
||||||
{
|
{
|
||||||
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
case 0: m_compression[0] = CHD_CODEC.NONE; break;
|
||||||
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 1: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
case 2: m_compression[0] = CHD_CODEC.ZLIB; break;
|
||||||
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
case 3: m_compression[0] = CHD_CODEC.AVHUFF; break;
|
||||||
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
|
||||||
|
|
||||||
m_hunkcount = m_br.ReadUInt32Reverse();
|
m_hunkcount = m_br.ReadUInt32Reverse();
|
||||||
m_logicalbytes = m_br.ReadUInt64Reverse();
|
m_logicalbytes = m_br.ReadUInt64Reverse();
|
||||||
m_metaoffset = m_br.ReadUInt32Reverse();
|
m_metaoffset = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
m_br.BaseStream.Seek(44, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(44, SeekOrigin.Begin);
|
||||||
m_hunkbytes = m_br.ReadUInt32Reverse();
|
m_hunkbytes = m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
m_br.BaseStream.Seek(Constants.CHDv4SHA1Offset, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(Constants.CHDv4SHA1Offset, SeekOrigin.Begin);
|
||||||
sha1 = m_br.ReadBytes(20);
|
sha1 = m_br.ReadBytes(20);
|
||||||
|
|
||||||
// guess at the units based on snooping the metadata
|
// guess at the units based on snooping the metadata
|
||||||
// m_unitbytes = guess_unitbytes();
|
// m_unitbytes = guess_unitbytes();
|
||||||
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
||||||
return sha1;
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a CHD v5 header
|
/// Parse a CHD v5 header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
|
||||||
private byte[] ParseCHDv5Header()
|
private byte[] ParseCHDv5Header()
|
||||||
{
|
{
|
||||||
// Seek to after the signature to make sure we're reading the correct bytes
|
// Seek to after the signature to make sure we're reading the correct bytes
|
||||||
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
|
||||||
|
|
||||||
// Set the blank SHA-1 hash
|
// Set the blank SHA-1 hash
|
||||||
byte[] sha1 = new byte[20];
|
byte[] sha1 = new byte[20];
|
||||||
|
|
||||||
// Determine compression
|
// Determine compression
|
||||||
m_compression[0] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
m_compression[0] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
||||||
m_compression[1] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
m_compression[1] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
||||||
m_compression[2] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
m_compression[2] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
||||||
m_compression[3] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
m_compression[3] = (CHD_CODEC)m_br.ReadUInt32Reverse();
|
||||||
|
|
||||||
m_logicalbytes = m_br.ReadUInt64Reverse();
|
m_logicalbytes = m_br.ReadUInt64Reverse();
|
||||||
m_mapoffset = m_br.ReadUInt64Reverse();
|
m_mapoffset = m_br.ReadUInt64Reverse();
|
||||||
m_metaoffset = m_br.ReadUInt64Reverse();
|
m_metaoffset = m_br.ReadUInt64Reverse();
|
||||||
m_hunkbytes = m_br.ReadUInt32Reverse();
|
m_hunkbytes = m_br.ReadUInt32Reverse();
|
||||||
m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
|
m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
|
||||||
m_unitbytes = m_br.ReadUInt32Reverse();
|
m_unitbytes = m_br.ReadUInt32Reverse();
|
||||||
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
|
||||||
|
|
||||||
// m_allow_writes = !compressed();
|
// m_allow_writes = !compressed();
|
||||||
|
|
||||||
// determine properties of map entries
|
// determine properties of map entries
|
||||||
// m_mapentrybytes = compressed() ? 12 : 4;
|
// m_mapentrybytes = compressed() ? 12 : 4;
|
||||||
|
|
||||||
m_br.BaseStream.Seek(Constants.CHDv5SHA1Offset, SeekOrigin.Begin);
|
m_br.BaseStream.Seek(Constants.CHDv5SHA1Offset, SeekOrigin.Begin);
|
||||||
sha1 = m_br.ReadBytes(20);
|
sha1 = m_br.ReadBytes(20);
|
||||||
return sha1;
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,223 +117,223 @@ using SabreTools.Library.DatItems;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
public class CoreRarArchive : BaseArchive
|
public class CoreRarArchive : BaseArchive
|
||||||
{
|
{
|
||||||
// SFX Module Information
|
// SFX Module Information
|
||||||
public byte[] SFX;
|
public byte[] SFX;
|
||||||
|
|
||||||
// Standard Header Information
|
// Standard Header Information
|
||||||
public uint HeaderCRC32;
|
public uint HeaderCRC32;
|
||||||
public uint HeaderSize; // vint
|
public uint HeaderSize; // vint
|
||||||
public RarHeaderFlags HeaderFlags; // vint
|
public RarHeaderFlags HeaderFlags; // vint
|
||||||
public uint ExtraAreaSize; // vint
|
public uint ExtraAreaSize; // vint
|
||||||
public RarArchiveFlags ArchiveFlags; // vint
|
public RarArchiveFlags ArchiveFlags; // vint
|
||||||
public uint VolumeNumber; // vint
|
public uint VolumeNumber; // vint
|
||||||
public byte[] ExtraArea;
|
public byte[] ExtraArea;
|
||||||
|
|
||||||
// Encryption Header Information
|
// Encryption Header Information
|
||||||
public uint EncryptionHeaderCRC32;
|
public uint EncryptionHeaderCRC32;
|
||||||
public uint EncryptionHeaderSize; // vint
|
public uint EncryptionHeaderSize; // vint
|
||||||
public RarHeaderFlags EncryptionHeaderFlags; // vint
|
public RarHeaderFlags EncryptionHeaderFlags; // vint
|
||||||
public uint EncryptionVersion; // vint
|
public uint EncryptionVersion; // vint
|
||||||
public uint EncryptionFlags; // vint
|
public uint EncryptionFlags; // vint
|
||||||
public byte KDFCount;
|
public byte KDFCount;
|
||||||
public byte[] Salt = new byte[16];
|
public byte[] Salt = new byte[16];
|
||||||
public byte[] CheckValue = new byte[12];
|
public byte[] CheckValue = new byte[12];
|
||||||
|
|
||||||
// Locator Information
|
// Locator Information
|
||||||
public uint LocatorSize; // vint
|
public uint LocatorSize; // vint
|
||||||
public uint LocatorFlags; // vint
|
public uint LocatorFlags; // vint
|
||||||
public uint QuickOpenOffset; // vint
|
public uint QuickOpenOffset; // vint
|
||||||
public uint RecoveryRecordOffset; // vint
|
public uint RecoveryRecordOffset; // vint
|
||||||
|
|
||||||
// Entry Information
|
// Entry Information
|
||||||
public List<CoreRarArchiveEntry> Entries = new List<CoreRarArchiveEntry>();
|
public List<CoreRarArchiveEntry> Entries = new List<CoreRarArchiveEntry>();
|
||||||
|
|
||||||
#region Unimplemented methods
|
#region Unimplemented methods
|
||||||
|
|
||||||
public override bool CopyAll(string outDir)
|
public override bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CopyToFile(string entryName, string outDir)
|
public override string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (MemoryStream, string) CopyToStream(string entryName)
|
public override (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<string> GetEmptyFolders()
|
public override List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsTorrent()
|
public override bool IsTorrent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CoreRarArchiveEntry
|
public class CoreRarArchiveEntry
|
||||||
{
|
{
|
||||||
// Standard Entry Information
|
// Standard Entry Information
|
||||||
public uint HeaderCRC32;
|
public uint HeaderCRC32;
|
||||||
public uint HeaderSize; // vint
|
public uint HeaderSize; // vint
|
||||||
public RarHeaderType HeaderType; // vint
|
public RarHeaderType HeaderType; // vint
|
||||||
public RarHeaderFlags HeaderFlags; // vint
|
public RarHeaderFlags HeaderFlags; // vint
|
||||||
public uint ExtraAreaSize; // vint
|
public uint ExtraAreaSize; // vint
|
||||||
public uint DataAreaSize; // vint
|
public uint DataAreaSize; // vint
|
||||||
public RarFileFlags FileFlags; // vint
|
public RarFileFlags FileFlags; // vint
|
||||||
public uint UnpackedSize; // vint
|
public uint UnpackedSize; // vint
|
||||||
public uint Attributes; // vint
|
public uint Attributes; // vint
|
||||||
public uint mtime;
|
public uint mtime;
|
||||||
public uint DataCRC32;
|
public uint DataCRC32;
|
||||||
public uint CompressionInformation; // vint
|
public uint CompressionInformation; // vint
|
||||||
public uint HostOS; // vint
|
public uint HostOS; // vint
|
||||||
public uint NameLength; // vint
|
public uint NameLength; // vint
|
||||||
public byte[] Name;
|
public byte[] Name;
|
||||||
public byte[] DataArea;
|
public byte[] DataArea;
|
||||||
|
|
||||||
// File Encryption Information
|
// File Encryption Information
|
||||||
public uint EncryptionSize; // vint
|
public uint EncryptionSize; // vint
|
||||||
public RarEncryptionFlags EncryptionFlags; // vint
|
public RarEncryptionFlags EncryptionFlags; // vint
|
||||||
public byte KDFCount;
|
public byte KDFCount;
|
||||||
public byte[] Salt = new byte[16];
|
public byte[] Salt = new byte[16];
|
||||||
public byte[] IV = new byte[16];
|
public byte[] IV = new byte[16];
|
||||||
public byte[] CheckValue = new byte[12];
|
public byte[] CheckValue = new byte[12];
|
||||||
|
|
||||||
// File Hash Information
|
// File Hash Information
|
||||||
public uint HashSize; // vint
|
public uint HashSize; // vint
|
||||||
public uint HashType; // vint
|
public uint HashType; // vint
|
||||||
public byte[] HashData = new byte[32];
|
public byte[] HashData = new byte[32];
|
||||||
|
|
||||||
// File Time Information
|
// File Time Information
|
||||||
public uint TimeSize; // vint
|
public uint TimeSize; // vint
|
||||||
public RarTimeFlags TimeFlags; // vint
|
public RarTimeFlags TimeFlags; // vint
|
||||||
public uint TimeMtime;
|
public uint TimeMtime;
|
||||||
public ulong TimeMtime64;
|
public ulong TimeMtime64;
|
||||||
public uint TimeCtime;
|
public uint TimeCtime;
|
||||||
public ulong TimeCtime64;
|
public ulong TimeCtime64;
|
||||||
public uint TimeLtime;
|
public uint TimeLtime;
|
||||||
public ulong TimeLtime64;
|
public ulong TimeLtime64;
|
||||||
|
|
||||||
// File Version Information
|
// File Version Information
|
||||||
public uint VersionSize; // vint
|
public uint VersionSize; // vint
|
||||||
public const uint VersionFlags = 0; // vint
|
public const uint VersionFlags = 0; // vint
|
||||||
public uint VersionNumber; // vint
|
public uint VersionNumber; // vint
|
||||||
|
|
||||||
// File System Redirection Record
|
// File System Redirection Record
|
||||||
public uint RedirectionSize; // vint
|
public uint RedirectionSize; // vint
|
||||||
public RarRedirectionType RedirectionType; // vint
|
public RarRedirectionType RedirectionType; // vint
|
||||||
public uint RedirectionFlags; // vint
|
public uint RedirectionFlags; // vint
|
||||||
public uint RedirectionNameLength; // vint
|
public uint RedirectionNameLength; // vint
|
||||||
public byte[] RedirectionName;
|
public byte[] RedirectionName;
|
||||||
|
|
||||||
// Unix Owner Record
|
// Unix Owner Record
|
||||||
public uint UnixOwnerSize; // vint
|
public uint UnixOwnerSize; // vint
|
||||||
public RarUnixOwnerRecordFlags UnixOwnerFlags; // vint
|
public RarUnixOwnerRecordFlags UnixOwnerFlags; // vint
|
||||||
public uint UnixOwnerUserNameLength; // vint
|
public uint UnixOwnerUserNameLength; // vint
|
||||||
public byte[] UnixOwnerUserName;
|
public byte[] UnixOwnerUserName;
|
||||||
public uint UnixOwnerGroupNameLength; // vint
|
public uint UnixOwnerGroupNameLength; // vint
|
||||||
public byte[] UnixOwnerGroupName;
|
public byte[] UnixOwnerGroupName;
|
||||||
public uint UnixOwnerUserId; // vint
|
public uint UnixOwnerUserId; // vint
|
||||||
public uint UnixOwnerGroupId; // vint
|
public uint UnixOwnerGroupId; // vint
|
||||||
|
|
||||||
// Service Data Information
|
// Service Data Information
|
||||||
public uint ServiceSize; // vint
|
public uint ServiceSize; // vint
|
||||||
public byte[] ServiceData;
|
public byte[] ServiceData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BELOW ARE CONCRETE IMPLEMENTATIONS OF HEADER DETAILS
|
// BELOW ARE CONCRETE IMPLEMENTATIONS OF HEADER DETAILS
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// General archive block format used by all RAR block types
|
/// General archive block format used by all RAR block types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GeneralArchiveBlockFormat
|
public class GeneralArchiveBlockFormat
|
||||||
{
|
{
|
||||||
public uint HeaderCRC32;
|
public uint HeaderCRC32;
|
||||||
public uint HeaderSize; // vint
|
public uint HeaderSize; // vint
|
||||||
public HeaderType HeaderType;
|
public HeaderType HeaderType;
|
||||||
public HeaderFlags HeaderFlags;
|
public HeaderFlags HeaderFlags;
|
||||||
public ulong ExtraAreaSize; // vint
|
public ulong ExtraAreaSize; // vint
|
||||||
public ulong DataAreaSize; // vint
|
public ulong DataAreaSize; // vint
|
||||||
public byte[] ExtraArea;
|
public byte[] ExtraArea;
|
||||||
public byte[] DataArea;
|
public byte[] DataArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// General extra area format used by all RAR extra area records
|
/// General extra area format used by all RAR extra area records
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GeneralExtraAreaFormat
|
public class GeneralExtraAreaFormat
|
||||||
{
|
{
|
||||||
public ulong Size; // vint
|
public ulong Size; // vint
|
||||||
public ulong Type; // vint
|
public ulong Type; // vint
|
||||||
public byte[] Data;
|
public byte[] Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encryption header only present in encrypted archives
|
/// Encryption header only present in encrypted archives
|
||||||
///
|
///
|
||||||
/// Every proceeding header is started from 16 byte AES-256
|
/// Every proceeding header is started from 16 byte AES-256
|
||||||
/// initialization vectors followed by encrypted header data
|
/// initialization vectors followed by encrypted header data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArchiveEncryptionHeader : GeneralArchiveBlockFormat
|
public class ArchiveEncryptionHeader : GeneralArchiveBlockFormat
|
||||||
{
|
{
|
||||||
public new HeaderType HeaderType = HeaderType.ArchiveEncryptionHeader;
|
public new HeaderType HeaderType = HeaderType.ArchiveEncryptionHeader;
|
||||||
public ulong EncryptionVersion; // vint
|
public ulong EncryptionVersion; // vint
|
||||||
public ulong EncryptionFlags; // vint
|
public ulong EncryptionFlags; // vint
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Types of archive header
|
/// Types of archive header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum HeaderType : ulong // vint
|
public enum HeaderType : ulong // vint
|
||||||
{
|
{
|
||||||
MainArchiveHeader = 1,
|
MainArchiveHeader = 1,
|
||||||
FileHeader = 2,
|
FileHeader = 2,
|
||||||
ServiceHeader = 3,
|
ServiceHeader = 3,
|
||||||
ArchiveEncryptionHeader = 4,
|
ArchiveEncryptionHeader = 4,
|
||||||
EndOfArchiveHeader = 5,
|
EndOfArchiveHeader = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flags common for all headers
|
/// Flags common for all headers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum HeaderFlags : ulong // vint
|
public enum HeaderFlags : ulong // vint
|
||||||
{
|
{
|
||||||
ExtraAreaIsPresentInEndOfHeader = 0x0001,
|
ExtraAreaIsPresentInEndOfHeader = 0x0001,
|
||||||
DataAreaIsPresentInEndOfHeader = 0x0002,
|
DataAreaIsPresentInEndOfHeader = 0x0002,
|
||||||
BlocksWithUnknownType = 0x0004, // this flag must be skipped when updating an archive
|
BlocksWithUnknownType = 0x0004, // this flag must be skipped when updating an archive
|
||||||
DataAreaIsContinuingFromPreviousVolume = 0x0008,
|
DataAreaIsContinuingFromPreviousVolume = 0x0008,
|
||||||
DataAreaIsContinuingInNextVolume = 0x0010,
|
DataAreaIsContinuingInNextVolume = 0x0010,
|
||||||
BlockDependsOnPrecedingFileBlock = 0x0020,
|
BlockDependsOnPrecedingFileBlock = 0x0020,
|
||||||
PreserveChildBlockIfHostBlockIsModified = 0x0040,
|
PreserveChildBlockIfHostBlockIsModified = 0x0040,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,305 +23,305 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a folder for reading and writing
|
/// Represents a folder for reading and writing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Folder : BaseFile
|
public class Folder : BaseFile
|
||||||
{
|
{
|
||||||
#region Protected instance variables
|
#region Protected instance variables
|
||||||
|
|
||||||
protected List<BaseFile> _children;
|
protected List<BaseFile> _children;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new folder with no base file
|
/// Create a new folder with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Folder()
|
public Folder()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.Folder;
|
this.Type = FileType.Folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new folder from the given file
|
/// Create a new folder from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="read">True for opening file as read, false for opening file as write</param>
|
/// <param name="read">True for opening file as read, false for opening file as write</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public Folder(string filename, bool getHashes = false)
|
public Folder(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.Folder;
|
this.Type = FileType.Folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public virtual bool CopyAll(string outDir)
|
public virtual bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
// Copy all files from the current folder to the output directory recursively
|
// Copy all files from the current folder to the output directory recursively
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Make sure the folders exist
|
// Make sure the folders exist
|
||||||
Directory.CreateDirectory(_filename);
|
Directory.CreateDirectory(this.Filename);
|
||||||
Directory.CreateDirectory(outDir);
|
Directory.CreateDirectory(outDir);
|
||||||
|
|
||||||
Directory.Copy(_filename, outDir, true, PathFormat.FullPath);
|
Directory.Copy(this.Filename, outDir, true, PathFormat.FullPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Globals.Logger.Error(ex.ToString());
|
Globals.Logger.Error(ex.ToString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file from an archive
|
/// Attempt to extract a file from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public virtual string CopyToFile(string entryName, string outDir)
|
public virtual string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
string realentry = null;
|
string realentry = null;
|
||||||
|
|
||||||
// Copy single file from the current folder to the output directory, if exists
|
// Copy single file from the current folder to the output directory, if exists
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Make sure the folders exist
|
// Make sure the folders exist
|
||||||
Directory.CreateDirectory(_filename);
|
Directory.CreateDirectory(this.Filename);
|
||||||
Directory.CreateDirectory(outDir);
|
Directory.CreateDirectory(outDir);
|
||||||
|
|
||||||
// Get all files from the input directory
|
// Get all files from the input directory
|
||||||
List<string> files = Utilities.RetrieveFiles(_filename, new List<string>());
|
List<string> files = Utilities.RetrieveFiles(this.Filename, new List<string>());
|
||||||
|
|
||||||
// Now sort through to find the first file that matches
|
// Now sort through to find the first file that matches
|
||||||
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
|
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
|
||||||
|
|
||||||
// If we had a file, copy that over to the new name
|
// If we had a file, copy that over to the new name
|
||||||
if (!String.IsNullOrWhiteSpace(match))
|
if (!String.IsNullOrWhiteSpace(match))
|
||||||
{
|
{
|
||||||
realentry = match;
|
realentry = match;
|
||||||
File.Copy(match, Path.Combine(outDir, entryName));
|
File.Copy(match, Path.Combine(outDir, entryName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Globals.Logger.Error(ex.ToString());
|
Globals.Logger.Error(ex.ToString());
|
||||||
return realentry;
|
return realentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return realentry;
|
return realentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public virtual (MemoryStream, string) CopyToStream(string entryName)
|
public virtual (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
MemoryStream ms = new MemoryStream();
|
MemoryStream ms = new MemoryStream();
|
||||||
string realentry = null;
|
string realentry = null;
|
||||||
|
|
||||||
// Copy single file from the current folder to the output directory, if exists
|
// Copy single file from the current folder to the output directory, if exists
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Make sure the folders exist
|
// Make sure the folders exist
|
||||||
Directory.CreateDirectory(_filename);
|
Directory.CreateDirectory(this.Filename);
|
||||||
|
|
||||||
// Get all files from the input directory
|
// Get all files from the input directory
|
||||||
List<string> files = Utilities.RetrieveFiles(_filename, new List<string>());
|
List<string> files = Utilities.RetrieveFiles(this.Filename, new List<string>());
|
||||||
|
|
||||||
// Now sort through to find the first file that matches
|
// Now sort through to find the first file that matches
|
||||||
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
|
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
|
||||||
|
|
||||||
// If we had a file, copy that over to the new name
|
// If we had a file, copy that over to the new name
|
||||||
if (!String.IsNullOrWhiteSpace(match))
|
if (!String.IsNullOrWhiteSpace(match))
|
||||||
{
|
{
|
||||||
Utilities.TryOpenRead(match).CopyTo(ms);
|
Utilities.TryOpenRead(match).CopyTo(ms);
|
||||||
realentry = match;
|
realentry = match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Globals.Logger.Error(ex.ToString());
|
Globals.Logger.Error(ex.ToString());
|
||||||
return (ms, realentry);
|
return (ms, realentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ms, realentry);
|
return (ms, realentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of immediate children from the current folder
|
/// Generate a list of immediate children from the current folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of BaseFile objects representing the found data</returns>
|
/// <returns>List of BaseFile objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public virtual List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public virtual List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
if (_children == null || _children.Count == 0)
|
if (_children == null || _children.Count == 0)
|
||||||
{
|
{
|
||||||
_children = new List<BaseFile>();
|
_children = new List<BaseFile>();
|
||||||
foreach (string file in Directory.EnumerateFiles(_filename, "*", SearchOption.TopDirectoryOnly))
|
foreach (string file in Directory.EnumerateFiles(this.Filename, "*", SearchOption.TopDirectoryOnly))
|
||||||
{
|
{
|
||||||
BaseFile nf = Utilities.GetFileInfo(file, omitFromScan: omitFromScan, date: date);
|
BaseFile nf = Utilities.GetFileInfo(file, omitFromScan: omitFromScan, date: date);
|
||||||
_children.Add(nf);
|
_children.Add(nf);
|
||||||
}
|
}
|
||||||
foreach (string dir in Directory.EnumerateDirectories(_filename, "*", SearchOption.TopDirectoryOnly))
|
foreach (string dir in Directory.EnumerateDirectories(this.Filename, "*", SearchOption.TopDirectoryOnly))
|
||||||
{
|
{
|
||||||
Folder fl = new Folder(dir);
|
Folder fl = new Folder(dir);
|
||||||
_children.Add(fl);
|
_children.Add(fl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _children;
|
return _children;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the folder</returns>
|
/// <returns>List of empty folders in the folder</returns>
|
||||||
public virtual List<string> GetEmptyFolders()
|
public virtual List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
return Utilities.GetEmptyDirectories(_filename).ToList();
|
return Utilities.GetEmptyDirectories(this.Filename).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to an output folder
|
/// Write an input file to an output folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public virtual bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public virtual bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
FileStream fs = Utilities.TryOpenRead(inputFile);
|
FileStream fs = Utilities.TryOpenRead(inputFile);
|
||||||
return Write(fs, outDir, rom, date, romba);
|
return Write(fs, outDir, rom, date, romba);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to an output folder
|
/// Write an input stream to an output folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public virtual bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public virtual bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
// If either input is null or empty, return
|
// If either input is null or empty, return
|
||||||
if (inputStream == null || rom == null || rom.Name == null)
|
if (inputStream == null || rom == null || rom.Name == null)
|
||||||
{
|
{
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the stream is not readable, return
|
// If the stream is not readable, return
|
||||||
if (!inputStream.CanRead)
|
if (!inputStream.CanRead)
|
||||||
{
|
{
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set internal variables
|
// Set internal variables
|
||||||
FileStream outputStream = null;
|
FileStream outputStream = null;
|
||||||
|
|
||||||
// Get the output folder name from the first rebuild rom
|
// Get the output folder name from the first rebuild rom
|
||||||
string fileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName), Utilities.RemovePathUnsafeCharacters(rom.Name));
|
string fileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName), Utilities.RemovePathUnsafeCharacters(rom.Name));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// If the full output path doesn't exist, create it
|
// If the full output path doesn't exist, create it
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
|
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
|
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overwrite output files by default
|
// Overwrite output files by default
|
||||||
outputStream = Utilities.TryCreate(fileName);
|
outputStream = Utilities.TryCreate(fileName);
|
||||||
|
|
||||||
// If the output stream isn't null
|
// If the output stream isn't null
|
||||||
if (outputStream != null)
|
if (outputStream != null)
|
||||||
{
|
{
|
||||||
// Copy the input stream to the output
|
// Copy the input stream to the output
|
||||||
inputStream.Seek(0, SeekOrigin.Begin);
|
inputStream.Seek(0, SeekOrigin.Begin);
|
||||||
int bufferSize = 4096 * 128;
|
int bufferSize = 4096 * 128;
|
||||||
byte[] ibuffer = new byte[bufferSize];
|
byte[] ibuffer = new byte[bufferSize];
|
||||||
int ilen;
|
int ilen;
|
||||||
while ((ilen = inputStream.Read(ibuffer, 0, bufferSize)) > 0)
|
while ((ilen = inputStream.Read(ibuffer, 0, bufferSize)) > 0)
|
||||||
{
|
{
|
||||||
outputStream.Write(ibuffer, 0, ilen);
|
outputStream.Write(ibuffer, 0, ilen);
|
||||||
outputStream.Flush();
|
outputStream.Flush();
|
||||||
}
|
}
|
||||||
outputStream.Dispose();
|
outputStream.Dispose();
|
||||||
|
|
||||||
if (rom.ItemType == ItemType.Rom)
|
if (rom.ItemType == ItemType.Rom)
|
||||||
{
|
{
|
||||||
if (date && !String.IsNullOrWhiteSpace(((Rom)rom).Date))
|
if (date && !String.IsNullOrWhiteSpace(((Rom)rom).Date))
|
||||||
{
|
{
|
||||||
File.SetCreationTime(fileName, DateTime.Parse(((Rom)rom).Date));
|
File.SetCreationTime(fileName, DateTime.Parse(((Rom)rom).Date));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
Console.WriteLine(ex);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
inputStream.Dispose();
|
inputStream.Dispose();
|
||||||
outputStream?.Dispose();
|
outputStream?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to an output folder (assuming the same output archive name)
|
/// Write a set of input files to an output folder (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public virtual bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public virtual bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a TorrentLRZip archive for reading and writing
|
/// Represents a TorrentLRZip archive for reading and writing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// TODO: Implement from source at https://github.com/ckolivas/lrzip
|
/// TODO: Implement from source at https://github.com/ckolivas/lrzip
|
||||||
public class LRZipArchive : BaseArchive
|
public class LRZipArchive : BaseArchive
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new LRZipArchive with no base file
|
/// Create a new LRZipArchive with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LRZipArchive()
|
public LRZipArchive()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.LRZipArchive;
|
this.Type = FileType.LRZipArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new LRZipArchive from the given file
|
/// Create a new LRZipArchive from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public LRZipArchive(string filename, bool getHashes = false)
|
public LRZipArchive(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.LRZipArchive;
|
this.Type = FileType.LRZipArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public override bool CopyAll(string outDir)
|
public override bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file from an archive
|
/// Attempt to extract a file from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public override string CopyToFile(string entryName, string outDir)
|
public override string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public override (MemoryStream, string) CopyToStream(string entryName)
|
public override (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of DatItem objects from the header values in an archive
|
/// Generate a list of DatItem objects from the header values in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of DatItem objects representing the found data</returns>
|
/// <returns>List of DatItem objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the archive</returns>
|
/// <returns>List of empty folders in the archive</returns>
|
||||||
public override List<string> GetEmptyFolders()
|
public override List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the input file is a standardized format
|
/// Check whether the input file is a standardized format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsTorrent()
|
public override bool IsTorrent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to a torrent LRZip file
|
/// Write an input file to a torrent LRZip file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to a torrent LRZip file
|
/// Write an input stream to a torrent LRZip file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to a torrent LRZip archive (assuming the same output archive name)
|
/// Write a set of input files to a torrent LRZip archive (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a TorrentLRZip archive for reading and writing
|
/// Represents a TorrentLRZip archive for reading and writing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// TODO: Implement from source at https://github.com/lz4/lz4
|
/// TODO: Implement from source at https://github.com/lz4/lz4
|
||||||
public class LZ4Archive : BaseArchive
|
public class LZ4Archive : BaseArchive
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new LZ4Archive with no base file
|
/// Create a new LZ4Archive with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LZ4Archive()
|
public LZ4Archive()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.LZ4Archive;
|
this.Type = FileType.LZ4Archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new LZ4Archive from the given file
|
/// Create a new LZ4Archive from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public LZ4Archive(string filename, bool getHashes = false)
|
public LZ4Archive(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.LZ4Archive;
|
this.Type = FileType.LZ4Archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public override bool CopyAll(string outDir)
|
public override bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file from an archive
|
/// Attempt to extract a file from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public override string CopyToFile(string entryName, string outDir)
|
public override string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public override (MemoryStream, string) CopyToStream(string entryName)
|
public override (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of DatItem objects from the header values in an archive
|
/// Generate a list of DatItem objects from the header values in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of DatItem objects representing the found data</returns>
|
/// <returns>List of DatItem objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the archive</returns>
|
/// <returns>List of empty folders in the archive</returns>
|
||||||
public override List<string> GetEmptyFolders()
|
public override List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the input file is a standardized format
|
/// Check whether the input file is a standardized format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsTorrent()
|
public override bool IsTorrent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to a torrent LZ4 file
|
/// Write an input file to a torrent LZ4 file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to a torrent LZ4 file
|
/// Write an input stream to a torrent LZ4 file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to a torrent LZ4 archive (assuming the same output archive name)
|
/// Write a set of input files to a torrent LZ4 archive (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace SabreTools.Library.FileTypes
|
|||||||
public RarArchive()
|
public RarArchive()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.RarArchive;
|
this.Type = FileType.RarArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -49,7 +49,7 @@ namespace SabreTools.Library.FileTypes
|
|||||||
public RarArchive(string filename, bool getHashes = false)
|
public RarArchive(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.RarArchive;
|
this.Type = FileType.RarArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -71,7 +71,7 @@ namespace SabreTools.Library.FileTypes
|
|||||||
Directory.CreateDirectory(outDir);
|
Directory.CreateDirectory(outDir);
|
||||||
|
|
||||||
// Extract all files to the temp directory
|
// Extract all files to the temp directory
|
||||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(_filename);
|
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(this.Filename);
|
||||||
foreach (RarArchiveEntry entry in ra.Entries)
|
foreach (RarArchiveEntry entry in ra.Entries)
|
||||||
{
|
{
|
||||||
entry.WriteToDirectory(outDir, new ExtractionOptions { PreserveFileTime = true, ExtractFullPath = true, Overwrite = true });
|
entry.WriteToDirectory(outDir, new ExtractionOptions { PreserveFileTime = true, ExtractFullPath = true, Overwrite = true });
|
||||||
@@ -155,7 +155,7 @@ namespace SabreTools.Library.FileTypes
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(_filename, new ReaderOptions { LeaveStreamOpen = false, });
|
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false, });
|
||||||
foreach (RarArchiveEntry entry in ra.Entries)
|
foreach (RarArchiveEntry entry in ra.Entries)
|
||||||
{
|
{
|
||||||
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
|
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
|
||||||
@@ -191,11 +191,11 @@ namespace SabreTools.Library.FileTypes
|
|||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
List<BaseFile> found = new List<BaseFile>();
|
List<BaseFile> found = new List<BaseFile>();
|
||||||
string gamename = Path.GetFileNameWithoutExtension(_filename);
|
string gamename = Path.GetFileNameWithoutExtension(this.Filename);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(Utilities.TryOpenRead(_filename));
|
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(Utilities.TryOpenRead(this.Filename));
|
||||||
foreach (RarArchiveEntry entry in ra.Entries.Where(e => e != null && !e.IsDirectory))
|
foreach (RarArchiveEntry entry in ra.Entries.Where(e => e != null && !e.IsDirectory))
|
||||||
{
|
{
|
||||||
// If secure hashes are disabled, do a quickscan
|
// If secure hashes are disabled, do a quickscan
|
||||||
@@ -242,12 +242,12 @@ namespace SabreTools.Library.FileTypes
|
|||||||
/// TODO: Write the rest of this RAR file handling
|
/// TODO: Write the rest of this RAR file handling
|
||||||
public void GetRarFileInfo()
|
public void GetRarFileInfo()
|
||||||
{
|
{
|
||||||
if (!File.Exists(_filename))
|
if (!File.Exists(this.Filename))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryReader br = new BinaryReader(Utilities.TryOpenRead(_filename));
|
BinaryReader br = new BinaryReader(Utilities.TryOpenRead(this.Filename));
|
||||||
|
|
||||||
// Check for the signature first (Skipping the SFX Module)
|
// Check for the signature first (Skipping the SFX Module)
|
||||||
byte[] signature = br.ReadBytes(8);
|
byte[] signature = br.ReadBytes(8);
|
||||||
@@ -464,7 +464,7 @@ namespace SabreTools.Library.FileTypes
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(_filename, new ReaderOptions { LeaveStreamOpen = false });
|
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false });
|
||||||
List<RarArchiveEntry> rarEntries = ra.Entries.OrderBy(e => e.Key, new NaturalSort.NaturalReversedComparer()).ToList();
|
List<RarArchiveEntry> rarEntries = ra.Entries.OrderBy(e => e.Key, new NaturalSort.NaturalReversedComparer()).ToList();
|
||||||
string lastRarEntry = null;
|
string lastRarEntry = null;
|
||||||
foreach (RarArchiveEntry entry in rarEntries)
|
foreach (RarArchiveEntry entry in rarEntries)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ZPAQArchive archive for reading and writing
|
/// Represents a ZPAQArchive archive for reading and writing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// TODO: Implement from source at https://github.com/zpaq/zpaq - In progress as external DLL
|
/// TODO: Implement from source at https://github.com/zpaq/zpaq - In progress as external DLL
|
||||||
public class ZPAQArchive : BaseArchive
|
public class ZPAQArchive : BaseArchive
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new ZPAQArchive with no base file
|
/// Create a new ZPAQArchive with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ZPAQArchive()
|
public ZPAQArchive()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.ZPAQArchive;
|
this.Type = FileType.ZPAQArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new ZPAQArchive from the given file
|
/// Create a new ZPAQArchive from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public ZPAQArchive(string filename, bool getHashes = false)
|
public ZPAQArchive(string filename, bool getHashes = false)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.ZPAQArchive;
|
this.Type = FileType.ZPAQArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public override bool CopyAll(string outDir)
|
public override bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file from an archive
|
/// Attempt to extract a file from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public override string CopyToFile(string entryName, string outDir)
|
public override string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public override (MemoryStream, string) CopyToStream(string entryName)
|
public override (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of DatItem objects from the header values in an archive
|
/// Generate a list of DatItem objects from the header values in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of DatItem objects representing the found data</returns>
|
/// <returns>List of DatItem objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the archive</returns>
|
/// <returns>List of empty folders in the archive</returns>
|
||||||
public override List<string> GetEmptyFolders()
|
public override List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the input file is a standardized format
|
/// Check whether the input file is a standardized format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsTorrent()
|
public override bool IsTorrent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to a torrent ZPAQ file
|
/// Write an input file to a torrent ZPAQ file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to a torrent ZPAQ file
|
/// Write an input stream to a torrent ZPAQ file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to a torrent ZPAQ archive (assuming the same output archive name)
|
/// Write a set of input files to a torrent ZPAQ archive (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
|
|||||||
|
|
||||||
namespace SabreTools.Library.FileTypes
|
namespace SabreTools.Library.FileTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ZstdArchive archive for reading and writing
|
/// Represents a ZstdArchive archive for reading and writing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// TODO: Implement from source at https://github.com/skbkontur/ZstdNet
|
/// TODO: Implement from source at https://github.com/skbkontur/ZstdNet
|
||||||
public class ZstdArchive : BaseArchive
|
public class ZstdArchive : BaseArchive
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new ZstdArchive with no base file
|
/// Create a new ZstdArchive with no base file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ZstdArchive()
|
public ZstdArchive()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_fileType = FileType.ZstdArchive;
|
this.Type = FileType.ZstdArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new ZstdArchive from the given file
|
/// Create a new ZstdArchive from the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the file to use as an archive</param>
|
/// <param name="filename">Name of the file to use as an archive</param>
|
||||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||||
public ZstdArchive(string filename, bool getHashes)
|
public ZstdArchive(string filename, bool getHashes)
|
||||||
: base(filename, getHashes)
|
: base(filename, getHashes)
|
||||||
{
|
{
|
||||||
_fileType = FileType.ZstdArchive;
|
this.Type = FileType.ZstdArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Extraction
|
#region Extraction
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file as an archive
|
/// Attempt to extract a file as an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>True if the extraction was a success, false otherwise</returns>
|
/// <returns>True if the extraction was a success, false otherwise</returns>
|
||||||
public override bool CopyAll(string outDir)
|
public override bool CopyAll(string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a file from an archive
|
/// Attempt to extract a file from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="outDir">Output directory for archive extraction</param>
|
/// <param name="outDir">Output directory for archive extraction</param>
|
||||||
/// <returns>Name of the extracted file, null on error</returns>
|
/// <returns>Name of the extracted file, null on error</returns>
|
||||||
public override string CopyToFile(string entryName, string outDir)
|
public override string CopyToFile(string entryName, string outDir)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to extract a stream from an archive
|
/// Attempt to extract a stream from an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryName">Name of the entry to be extracted</param>
|
/// <param name="entryName">Name of the entry to be extracted</param>
|
||||||
/// <param name="realEntry">Output representing the entry name that was found</param>
|
/// <param name="realEntry">Output representing the entry name that was found</param>
|
||||||
/// <returns>MemoryStream representing the entry, null on error</returns>
|
/// <returns>MemoryStream representing the entry, null on error</returns>
|
||||||
public override (MemoryStream, string) CopyToStream(string entryName)
|
public override (MemoryStream, string) CopyToStream(string entryName)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Information
|
#region Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of DatItem objects from the header values in an archive
|
/// Generate a list of DatItem objects from the header values in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
/// <param name="omitFromScan">Hash representing the hashes that should be skipped</param>
|
||||||
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
/// <param name="date">True if entry dates should be included, false otherwise (default)</param>
|
||||||
/// <returns>List of DatItem objects representing the found data</returns>
|
/// <returns>List of DatItem objects representing the found data</returns>
|
||||||
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
/// <remarks>TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually</remarks>
|
||||||
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a list of empty folders in an archive
|
/// Generate a list of empty folders in an archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">Input file to get data from</param>
|
/// <param name="input">Input file to get data from</param>
|
||||||
/// <returns>List of empty folders in the archive</returns>
|
/// <returns>List of empty folders in the archive</returns>
|
||||||
public override List<string> GetEmptyFolders()
|
public override List<string> GetEmptyFolders()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the input file is a standardized format
|
/// Check whether the input file is a standardized format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsTorrent()
|
public override bool IsTorrent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Writing
|
#region Writing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input file to a torrent Zstd file
|
/// Write an input file to a torrent Zstd file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFile">Input filename to be moved</param>
|
/// <param name="inputFile">Input filename to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an input stream to a torrent Zstd file
|
/// Write an input stream to a torrent Zstd file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputStream">Input stream to be moved</param>
|
/// <param name="inputStream">Input stream to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the write was a success, false otherwise</returns>
|
/// <returns>True if the write was a success, false otherwise</returns>
|
||||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||||
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a set of input files to a torrent Zstd archive (assuming the same output archive name)
|
/// Write a set of input files to a torrent Zstd archive (assuming the same output archive name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">Input files to be moved</param>
|
/// <param name="inputFiles">Input files to be moved</param>
|
||||||
/// <param name="outDir">Output directory to build to</param>
|
/// <param name="outDir">Output directory to build to</param>
|
||||||
/// <param name="rom">DatItem representing the new information</param>
|
/// <param name="rom">DatItem representing the new information</param>
|
||||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
/// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
|
||||||
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
/// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
|
||||||
/// <returns>True if the archive was written properly, false otherwise</returns>
|
/// <returns>True if the archive was written properly, false otherwise</returns>
|
||||||
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user