[FileTypes/] Cleanup tabs AND variables

This commit is contained in:
Matt Nadareski
2019-02-08 20:51:44 -08:00
parent f04842851a
commit b09198708e
15 changed files with 4986 additions and 5022 deletions

View File

@@ -12,123 +12,123 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
public abstract class BaseArchive : Folder
{
#region Protected instance variables
public abstract class BaseArchive : Folder
{
#region Protected instance variables
// Buffer size used by archives
protected const int _bufferSize = 4096 * 128;
// Buffer size used by archives
protected const int _bufferSize = 4096 * 128;
#endregion
#endregion
#region Construtors
#region Construtors
/// <summary>
/// Create a new Archive with no base file
/// </summary>
public BaseArchive()
{
}
/// <summary>
/// Create a new Archive with no base file
/// </summary>
public BaseArchive()
{
}
/// <summary>
/// Create a new Archive from the given file
/// </summary>
/// <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>
public BaseArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
}
/// <summary>
/// Create a new Archive from the given file
/// </summary>
/// <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>
public BaseArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override abstract bool CopyAll(string outDir);
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override abstract bool CopyAll(string outDir);
/// <summary>
/// Attempt to extract an entry from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override abstract string CopyToFile(string entryName, string outDir);
/// <summary>
/// Attempt to extract an entry from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override abstract string CopyToFile(string entryName, string outDir);
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override abstract (MemoryStream, string) CopyToStream(string entryName);
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override abstract (MemoryStream, string) CopyToStream(string entryName);
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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);
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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);
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override abstract List<string> GetEmptyFolders();
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override abstract List<string> GetEmptyFolders();
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public abstract bool IsTorrent();
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public abstract bool IsTorrent();
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to an archive
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false);
/// <summary>
/// Write an input file to an archive
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false);
/// <summary>
/// Write an input stream to an archive
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false);
/// <summary>
/// Write an input stream to an archive
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false);
/// <summary>
/// Write a set of input files to an archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false);
/// <summary>
/// Write a set of input files to an archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override abstract bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false);
#endregion
}
#endregion
}
}

View File

@@ -9,151 +9,115 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
public class BaseFile
{
#region Protected instance variables
public class BaseFile
{
#region Publicly facing variables
protected FileType _fileType;
protected string _filename;
protected string _parent;
protected string _date;
// TODO: Get all of these values automatically so there is no public "set"
public FileType Type { get; protected set; }
public string Filename { get; set; }
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
protected long? _size;
protected byte[] _crc;
protected byte[] _md5;
protected byte[] _sha1;
protected byte[] _sha256;
protected byte[] _sha384;
protected byte[] _sha512;
#endregion
#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"
public FileType Type
{
get { return _fileType; }
}
public string Filename
{
get { return _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; }
}
/// <summary>
/// Create a new BaseFile from the given file
/// </summary>
/// <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;
#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>
/// Create a new BaseFile with no base file
/// </summary>
public BaseFile()
{
}
/// <summary>
/// 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;
/// <summary>
/// Create a new BaseFile from the given file
/// </summary>
/// <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)
{
BaseFile temp = Utilities.GetStreamInfo(stream, stream.Length);
if (getHashes)
{
BaseFile temp = Utilities.GetFileInfo(_filename);
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;
}
}
}
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>
/// Create a new BaseFile from the given metadata
/// </summary>
/// <param name="filename">Name of the file to use</param>
/// <param name="parent">Parent folder or archive</param>
/// <param name="date">File date</param>
/// <param name="crc">CRC hash as a byte array</param>
/// <param name="md5">MD5 hash as a byte array</param>
/// <param name="sha1">SHA-1 hash as a byte array</param>
/// <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>
/// 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
}
#endregion
}
}

View File

@@ -11,491 +11,491 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// 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
/// </summary>
/// <remarks>
/// ----------------------------------------------
/// Common CHD Header:
/// 0x00-0x07 - CHD signature
/// 0x08-0x0B - Header size
/// 0x0C-0x0F - CHD version
/// ----------------------------------------------
/// CHD v1 header layout:
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - 512-byte sectors per hunk
/// 0x1C-0x1F - Hunk count
/// 0x20-0x23 - Hard disk cylinder count
/// 0x24-0x27 - Hard disk head count
/// 0x28-0x2B - Hard disk sector count
/// 0x2C-0x3B - MD5
/// 0x3C-0x4B - Parent MD5
/// ----------------------------------------------
/// CHD v2 header layout:
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - seclen-byte sectors per hunk
/// 0x1C-0x1F - Hunk count
/// 0x20-0x23 - Hard disk cylinder count
/// 0x24-0x27 - Hard disk head count
/// 0x28-0x2B - Hard disk sector count
/// 0x2C-0x3B - MD5
/// 0x3C-0x4B - Parent MD5
/// 0x4C-0x4F - Number of bytes per sector (seclen)
/// ----------------------------------------------
/// CHD v3 header layout:
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - Hunk count
/// 0x1C-0x23 - Logical Bytes
/// 0x24-0x2C - Metadata Offset
/// ...
/// 0x4C-0x4F - Hunk Bytes
/// 0x50-0x63 - SHA-1
/// 0x64-0x77 - Parent SHA-1
/// 0x78-0x87 - Map
/// ----------------------------------------------
/// CHD v4 header layout:
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - Hunk count
/// 0x1C-0x23 - Logical Bytes
/// 0x24-0x2C - Metadata Offset
/// ...
/// 0x2C-0x2F - Hunk Bytes
/// 0x30-0x43 - SHA-1
/// 0x44-0x57 - Parent SHA-1
/// 0x58-0x6b - Raw SHA-1
/// 0x6c-0x7b - Map
/// ----------------------------------------------
/// CHD v5 header layout:
/// 0x10-0x13 - Compression format 1
/// 0x14-0x17 - Compression format 2
/// 0x18-0x1B - Compression format 3
/// 0x1C-0x1F - Compression format 4
/// 0x20-0x27 - Logical Bytes
/// 0x28-0x2F - Map Offset
/// 0x30-0x37 - Metadata Offset
/// 0x38-0x3B - Hunk Bytes
/// 0x3C-0x3F - Unit Bytes
/// 0x40-0x53 - Raw SHA-1
/// 0x54-0x67 - SHA-1
/// 0x68-0x7b - Parent SHA-1
/// ----------------------------------------------
/// </remarks>
public class CHDFile : BaseFile
{
#region Private instance variables
// Core parameters from the header
private byte[] m_signature; // signature
private uint m_headersize; // size 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_mapoffset; // offset of map
private ulong m_metaoffset; // offset to first metadata bit
private uint m_sectorsperhunk; // number of sectors per hunk
private uint m_hunkbytes; // size of each raw hunk in bytes
private ulong m_hunkcount; // number of hunks represented
private uint m_unitbytes; // size of each unit in bytes
private ulong m_unitcount; // number of units represented
private CHD_CODEC[] m_compression = new CHD_CODEC[4]; // array of compression types used
// map information
private uint m_mapentrybytes; // length of each entry in a map
// additional required vars
private uint? _headerVersion;
private BinaryReader m_br; // Binary reader representing the CHD stream
#endregion
#region Pubically facing variables
public uint? Version
{
get
{
if (_headerVersion == null)
{
_headerVersion = ValidateHeaderVersion();
}
return _headerVersion;
}
}
#endregion
#region Constructors
/// <summary>
/// Create a new, blank CHDFile
/// </summary>
public CHDFile()
{
this._fileType = FileType.CHD;
}
/// <summary>
/// Create a new CHDFile from an input file
/// </summary>
/// <param name="filename"></param>
public CHDFile(string filename)
: this(Utilities.TryOpenRead(filename))
{
}
/// <summary>
/// Create a new CHDFile from an input stream
/// </summary>
/// <param name="chdstream">Stream representing the CHD file</param>
public CHDFile(Stream chdstream)
{
_fileType = FileType.CHD;
m_br = new BinaryReader(chdstream);
_headerVersion = ValidateHeaderVersion();
if (_headerVersion != null)
{
byte[] hash = GetHashFromHeader();
if (hash != null)
{
if (hash.Length == Constants.MD5Length)
{
_md5 = hash;
}
else if (hash.Length == Constants.SHA1Length)
{
_sha1 = hash;
}
}
}
}
#endregion
#region Header Parsing
/// <summary>
/// Validate the initial signature, version, and header size
/// </summary>
/// <returns>Unsigned int containing the version number, null if invalid</returns>
private uint? ValidateHeaderVersion()
{
try
{
// Seek to the beginning to make sure we're reading the correct bytes
m_br.BaseStream.Seek(0, SeekOrigin.Begin);
// Read and verify the CHD signature
m_signature = m_br.ReadBytes(8);
// If no signature could be read, return null
if (m_signature == null || m_signature.Length == 0)
{
return null;
}
if (!m_signature.StartsWith(Constants.CHDSignature, exact: true))
{
// throw CHDERR_INVALID_FILE;
return null;
}
// Get the header size and version
m_headersize = m_br.ReadUInt32Reverse();
m_version = m_br.ReadUInt32Reverse();
// If we have an invalid combination of size and version
if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE)
|| (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE)
|| (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE)
|| (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE)
|| (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE)
|| (m_version < 1 || m_version > 5))
{
// throw CHDERR_UNSUPPORTED_VERSION;
return null;
}
return m_version;
}
catch
{
return null;
}
}
/// <summary>
/// Get the internal MD5 (v1, v2) or SHA-1 (v3, v4, v5) from the CHD
/// </summary>
/// <returns>MD5 as a byte array, null on error</returns>
private byte[] GetHashFromHeader()
{
// Validate the header by default just in case
uint? version = ValidateHeaderVersion();
// Now get the hash, if possible
byte[] hash;
// Now parse the rest of the header according to the version
try
{
switch (version)
{
case 1:
hash = ParseCHDv1Header();
break;
case 2:
hash = ParseCHDv2Header();
break;
case 3:
hash = ParseCHDv3Header();
break;
case 4:
hash = ParseCHDv4Header();
break;
case 5:
hash = ParseCHDv5Header();
break;
case null:
default:
// throw CHDERR_INVALID_FILE;
return null;
}
}
catch
{
// throw CHDERR_INVALID_FILE;
return null;
}
return hash;
}
/// <summary>
/// Parse a CHD v1 header
/// </summary>
/// <returns>The extracted MD5 on success, null otherwise</returns>
private byte[] ParseCHDv1Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank MD5 hash
byte[] md5 = new byte[16];
// Set offsets and defaults
m_mapoffset = 0;
m_mapentrybytes = 0;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_sectorsperhunk = m_br.ReadUInt32Reverse();
m_hunkcount = m_br.ReadUInt32Reverse();
m_br.ReadUInt32Reverse(); // Cylinder count
m_br.ReadUInt32Reverse(); // Head count
m_br.ReadUInt32Reverse(); // Sector count
md5 = m_br.ReadBytes(16);
m_br.ReadBytes(16); // Parent MD5
return md5;
}
/// <summary>
/// Parse a CHD v2 header
/// </summary>
/// <returns>The extracted MD5 on success, null otherwise</returns>
private byte[] ParseCHDv2Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank MD5 hash
byte[] md5 = new byte[16];
// Set offsets and defaults
m_mapoffset = 0;
m_mapentrybytes = 0;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_sectorsperhunk = m_br.ReadUInt32Reverse();
m_hunkcount = m_br.ReadUInt32Reverse();
m_br.ReadUInt32Reverse(); // Cylinder count
m_br.ReadUInt32Reverse(); // Head count
m_br.ReadUInt32Reverse(); // Sector count
md5 = m_br.ReadBytes(16);
m_br.ReadBytes(16); // Parent MD5
m_br.ReadUInt32Reverse(); // Sector size
return md5;
}
/// <summary>
/// Parse a CHD v3 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv3Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Set offsets and defaults
m_mapoffset = 120;
m_mapentrybytes = 16;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_hunkcount = m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(76, SeekOrigin.Begin);
m_hunkbytes = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(Constants.CHDv3SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
// guess at the units based on snooping the metadata
// m_unitbytes = guess_unitbytes();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
return sha1;
}
/// <summary>
/// Parse a CHD v4 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv4Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Set offsets and defaults
m_mapoffset = 108;
m_mapentrybytes = 16;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_hunkcount = m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(44, SeekOrigin.Begin);
m_hunkbytes = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(Constants.CHDv4SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
// guess at the units based on snooping the metadata
// m_unitbytes = guess_unitbytes();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
return sha1;
}
/// <summary>
/// Parse a CHD v5 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv5Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Determine compression
m_compression[0] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[1] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[2] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[3] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_mapoffset = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt64Reverse();
m_hunkbytes = m_br.ReadUInt32Reverse();
m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
m_unitbytes = m_br.ReadUInt32Reverse();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
// m_allow_writes = !compressed();
// determine properties of map entries
// m_mapentrybytes = compressed() ? 12 : 4;
m_br.BaseStream.Seek(Constants.CHDv5SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
return sha1;
}
#endregion
}
/// <summary>
/// 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
/// </summary>
/// <remarks>
/// ----------------------------------------------
/// Common CHD Header:
/// 0x00-0x07 - CHD signature
/// 0x08-0x0B - Header size
/// 0x0C-0x0F - CHD version
/// ----------------------------------------------
/// CHD v1 header layout:
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - 512-byte sectors per hunk
/// 0x1C-0x1F - Hunk count
/// 0x20-0x23 - Hard disk cylinder count
/// 0x24-0x27 - Hard disk head count
/// 0x28-0x2B - Hard disk sector count
/// 0x2C-0x3B - MD5
/// 0x3C-0x4B - Parent MD5
/// ----------------------------------------------
/// CHD v2 header layout:
/// 0x10-0x13 - Flags (1: Has parent MD5, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - seclen-byte sectors per hunk
/// 0x1C-0x1F - Hunk count
/// 0x20-0x23 - Hard disk cylinder count
/// 0x24-0x27 - Hard disk head count
/// 0x28-0x2B - Hard disk sector count
/// 0x2C-0x3B - MD5
/// 0x3C-0x4B - Parent MD5
/// 0x4C-0x4F - Number of bytes per sector (seclen)
/// ----------------------------------------------
/// CHD v3 header layout:
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - Hunk count
/// 0x1C-0x23 - Logical Bytes
/// 0x24-0x2C - Metadata Offset
/// ...
/// 0x4C-0x4F - Hunk Bytes
/// 0x50-0x63 - SHA-1
/// 0x64-0x77 - Parent SHA-1
/// 0x78-0x87 - Map
/// ----------------------------------------------
/// CHD v4 header layout:
/// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes)
/// 0x14-0x17 - Compression
/// 0x18-0x1B - Hunk count
/// 0x1C-0x23 - Logical Bytes
/// 0x24-0x2C - Metadata Offset
/// ...
/// 0x2C-0x2F - Hunk Bytes
/// 0x30-0x43 - SHA-1
/// 0x44-0x57 - Parent SHA-1
/// 0x58-0x6b - Raw SHA-1
/// 0x6c-0x7b - Map
/// ----------------------------------------------
/// CHD v5 header layout:
/// 0x10-0x13 - Compression format 1
/// 0x14-0x17 - Compression format 2
/// 0x18-0x1B - Compression format 3
/// 0x1C-0x1F - Compression format 4
/// 0x20-0x27 - Logical Bytes
/// 0x28-0x2F - Map Offset
/// 0x30-0x37 - Metadata Offset
/// 0x38-0x3B - Hunk Bytes
/// 0x3C-0x3F - Unit Bytes
/// 0x40-0x53 - Raw SHA-1
/// 0x54-0x67 - SHA-1
/// 0x68-0x7b - Parent SHA-1
/// ----------------------------------------------
/// </remarks>
public class CHDFile : BaseFile
{
#region Private instance variables
// Core parameters from the header
private byte[] m_signature; // signature
private uint m_headersize; // size 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_mapoffset; // offset of map
private ulong m_metaoffset; // offset to first metadata bit
private uint m_sectorsperhunk; // number of sectors per hunk
private uint m_hunkbytes; // size of each raw hunk in bytes
private ulong m_hunkcount; // number of hunks represented
private uint m_unitbytes; // size of each unit in bytes
private ulong m_unitcount; // number of units represented
private CHD_CODEC[] m_compression = new CHD_CODEC[4]; // array of compression types used
// map information
private uint m_mapentrybytes; // length of each entry in a map
// additional required vars
private uint? _headerVersion;
private BinaryReader m_br; // Binary reader representing the CHD stream
#endregion
#region Pubically facing variables
public uint? Version
{
get
{
if (_headerVersion == null)
{
_headerVersion = ValidateHeaderVersion();
}
return _headerVersion;
}
}
#endregion
#region Constructors
/// <summary>
/// Create a new, blank CHDFile
/// </summary>
public CHDFile()
{
this.Type = FileType.CHD;
}
/// <summary>
/// Create a new CHDFile from an input file
/// </summary>
/// <param name="filename"></param>
public CHDFile(string filename)
: this(Utilities.TryOpenRead(filename))
{
}
/// <summary>
/// Create a new CHDFile from an input stream
/// </summary>
/// <param name="chdstream">Stream representing the CHD file</param>
public CHDFile(Stream chdstream)
{
this.Type = FileType.CHD;
m_br = new BinaryReader(chdstream);
_headerVersion = ValidateHeaderVersion();
if (_headerVersion != null)
{
byte[] hash = GetHashFromHeader();
if (hash != null)
{
if (hash.Length == Constants.MD5Length)
{
this.MD5 = hash;
}
else if (hash.Length == Constants.SHA1Length)
{
this.SHA1 = hash;
}
}
}
}
#endregion
#region Header Parsing
/// <summary>
/// Validate the initial signature, version, and header size
/// </summary>
/// <returns>Unsigned int containing the version number, null if invalid</returns>
private uint? ValidateHeaderVersion()
{
try
{
// Seek to the beginning to make sure we're reading the correct bytes
m_br.BaseStream.Seek(0, SeekOrigin.Begin);
// Read and verify the CHD signature
m_signature = m_br.ReadBytes(8);
// If no signature could be read, return null
if (m_signature == null || m_signature.Length == 0)
{
return null;
}
if (!m_signature.StartsWith(Constants.CHDSignature, exact: true))
{
// throw CHDERR_INVALID_FILE;
return null;
}
// Get the header size and version
m_headersize = m_br.ReadUInt32Reverse();
m_version = m_br.ReadUInt32Reverse();
// If we have an invalid combination of size and version
if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE)
|| (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE)
|| (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE)
|| (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE)
|| (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE)
|| (m_version < 1 || m_version > 5))
{
// throw CHDERR_UNSUPPORTED_VERSION;
return null;
}
return m_version;
}
catch
{
return null;
}
}
/// <summary>
/// Get the internal MD5 (v1, v2) or SHA-1 (v3, v4, v5) from the CHD
/// </summary>
/// <returns>MD5 as a byte array, null on error</returns>
private byte[] GetHashFromHeader()
{
// Validate the header by default just in case
uint? version = ValidateHeaderVersion();
// Now get the hash, if possible
byte[] hash;
// Now parse the rest of the header according to the version
try
{
switch (version)
{
case 1:
hash = ParseCHDv1Header();
break;
case 2:
hash = ParseCHDv2Header();
break;
case 3:
hash = ParseCHDv3Header();
break;
case 4:
hash = ParseCHDv4Header();
break;
case 5:
hash = ParseCHDv5Header();
break;
case null:
default:
// throw CHDERR_INVALID_FILE;
return null;
}
}
catch
{
// throw CHDERR_INVALID_FILE;
return null;
}
return hash;
}
/// <summary>
/// Parse a CHD v1 header
/// </summary>
/// <returns>The extracted MD5 on success, null otherwise</returns>
private byte[] ParseCHDv1Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank MD5 hash
byte[] md5 = new byte[16];
// Set offsets and defaults
m_mapoffset = 0;
m_mapentrybytes = 0;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_sectorsperhunk = m_br.ReadUInt32Reverse();
m_hunkcount = m_br.ReadUInt32Reverse();
m_br.ReadUInt32Reverse(); // Cylinder count
m_br.ReadUInt32Reverse(); // Head count
m_br.ReadUInt32Reverse(); // Sector count
md5 = m_br.ReadBytes(16);
m_br.ReadBytes(16); // Parent MD5
return md5;
}
/// <summary>
/// Parse a CHD v2 header
/// </summary>
/// <returns>The extracted MD5 on success, null otherwise</returns>
private byte[] ParseCHDv2Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank MD5 hash
byte[] md5 = new byte[16];
// Set offsets and defaults
m_mapoffset = 0;
m_mapentrybytes = 0;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_sectorsperhunk = m_br.ReadUInt32Reverse();
m_hunkcount = m_br.ReadUInt32Reverse();
m_br.ReadUInt32Reverse(); // Cylinder count
m_br.ReadUInt32Reverse(); // Head count
m_br.ReadUInt32Reverse(); // Sector count
md5 = m_br.ReadBytes(16);
m_br.ReadBytes(16); // Parent MD5
m_br.ReadUInt32Reverse(); // Sector size
return md5;
}
/// <summary>
/// Parse a CHD v3 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv3Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Set offsets and defaults
m_mapoffset = 120;
m_mapentrybytes = 16;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_hunkcount = m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(76, SeekOrigin.Begin);
m_hunkbytes = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(Constants.CHDv3SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
// guess at the units based on snooping the metadata
// m_unitbytes = guess_unitbytes();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
return sha1;
}
/// <summary>
/// Parse a CHD v4 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv4Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Set offsets and defaults
m_mapoffset = 108;
m_mapentrybytes = 16;
// Read the CHD flags
uint flags = m_br.ReadUInt32Reverse();
// Determine compression
switch (m_br.ReadUInt32())
{
case 0: m_compression[0] = CHD_CODEC.NONE; break;
case 1: 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;
default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return null;
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC.NONE;
m_hunkcount = m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(44, SeekOrigin.Begin);
m_hunkbytes = m_br.ReadUInt32Reverse();
m_br.BaseStream.Seek(Constants.CHDv4SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
// guess at the units based on snooping the metadata
// m_unitbytes = guess_unitbytes();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
return sha1;
}
/// <summary>
/// Parse a CHD v5 header
/// </summary>
/// <returns>The extracted SHA-1 on success, null otherwise</returns>
private byte[] ParseCHDv5Header()
{
// Seek to after the signature to make sure we're reading the correct bytes
m_br.BaseStream.Seek(16, SeekOrigin.Begin);
// Set the blank SHA-1 hash
byte[] sha1 = new byte[20];
// Determine compression
m_compression[0] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[1] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[2] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_compression[3] = (CHD_CODEC)m_br.ReadUInt32Reverse();
m_logicalbytes = m_br.ReadUInt64Reverse();
m_mapoffset = m_br.ReadUInt64Reverse();
m_metaoffset = m_br.ReadUInt64Reverse();
m_hunkbytes = m_br.ReadUInt32Reverse();
m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
m_unitbytes = m_br.ReadUInt32Reverse();
m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
// m_allow_writes = !compressed();
// determine properties of map entries
// m_mapentrybytes = compressed() ? 12 : 4;
m_br.BaseStream.Seek(Constants.CHDv5SHA1Offset, SeekOrigin.Begin);
sha1 = m_br.ReadBytes(20);
return sha1;
}
#endregion
}
}

View File

@@ -117,223 +117,223 @@ using SabreTools.Library.DatItems;
/// </remarks>
namespace SabreTools.Library.FileTypes
{
public class CoreRarArchive : BaseArchive
{
// SFX Module Information
public byte[] SFX;
public class CoreRarArchive : BaseArchive
{
// SFX Module Information
public byte[] SFX;
// Standard Header Information
public uint HeaderCRC32;
public uint HeaderSize; // vint
public RarHeaderFlags HeaderFlags; // vint
public uint ExtraAreaSize; // vint
public RarArchiveFlags ArchiveFlags; // vint
public uint VolumeNumber; // vint
public byte[] ExtraArea;
// Standard Header Information
public uint HeaderCRC32;
public uint HeaderSize; // vint
public RarHeaderFlags HeaderFlags; // vint
public uint ExtraAreaSize; // vint
public RarArchiveFlags ArchiveFlags; // vint
public uint VolumeNumber; // vint
public byte[] ExtraArea;
// Encryption Header Information
public uint EncryptionHeaderCRC32;
public uint EncryptionHeaderSize; // vint
public RarHeaderFlags EncryptionHeaderFlags; // vint
public uint EncryptionVersion; // vint
public uint EncryptionFlags; // vint
public byte KDFCount;
public byte[] Salt = new byte[16];
public byte[] CheckValue = new byte[12];
// Encryption Header Information
public uint EncryptionHeaderCRC32;
public uint EncryptionHeaderSize; // vint
public RarHeaderFlags EncryptionHeaderFlags; // vint
public uint EncryptionVersion; // vint
public uint EncryptionFlags; // vint
public byte KDFCount;
public byte[] Salt = new byte[16];
public byte[] CheckValue = new byte[12];
// Locator Information
public uint LocatorSize; // vint
public uint LocatorFlags; // vint
public uint QuickOpenOffset; // vint
public uint RecoveryRecordOffset; // vint
// Locator Information
public uint LocatorSize; // vint
public uint LocatorFlags; // vint
public uint QuickOpenOffset; // vint
public uint RecoveryRecordOffset; // vint
// Entry Information
public List<CoreRarArchiveEntry> Entries = new List<CoreRarArchiveEntry>();
// Entry Information
public List<CoreRarArchiveEntry> Entries = new List<CoreRarArchiveEntry>();
#region Unimplemented methods
#region Unimplemented methods
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
{
throw new NotImplementedException();
}
public override List<BaseFile> GetChildren(Hash omitFromScan = Hash.DeepHashes, bool date = false)
{
throw new NotImplementedException();
}
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
public override bool IsTorrent()
{
throw new NotImplementedException();
}
public override bool IsTorrent()
{
throw new NotImplementedException();
}
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
public override bool Write(string inputFile, string outDir, Rom rom, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
public class CoreRarArchiveEntry
{
// Standard Entry Information
public uint HeaderCRC32;
public uint HeaderSize; // vint
public RarHeaderType HeaderType; // vint
public RarHeaderFlags HeaderFlags; // vint
public uint ExtraAreaSize; // vint
public uint DataAreaSize; // vint
public RarFileFlags FileFlags; // vint
public uint UnpackedSize; // vint
public uint Attributes; // vint
public uint mtime;
public uint DataCRC32;
public uint CompressionInformation; // vint
public uint HostOS; // vint
public uint NameLength; // vint
public byte[] Name;
public byte[] DataArea;
public class CoreRarArchiveEntry
{
// Standard Entry Information
public uint HeaderCRC32;
public uint HeaderSize; // vint
public RarHeaderType HeaderType; // vint
public RarHeaderFlags HeaderFlags; // vint
public uint ExtraAreaSize; // vint
public uint DataAreaSize; // vint
public RarFileFlags FileFlags; // vint
public uint UnpackedSize; // vint
public uint Attributes; // vint
public uint mtime;
public uint DataCRC32;
public uint CompressionInformation; // vint
public uint HostOS; // vint
public uint NameLength; // vint
public byte[] Name;
public byte[] DataArea;
// File Encryption Information
public uint EncryptionSize; // vint
public RarEncryptionFlags EncryptionFlags; // vint
public byte KDFCount;
public byte[] Salt = new byte[16];
public byte[] IV = new byte[16];
public byte[] CheckValue = new byte[12];
// File Encryption Information
public uint EncryptionSize; // vint
public RarEncryptionFlags EncryptionFlags; // vint
public byte KDFCount;
public byte[] Salt = new byte[16];
public byte[] IV = new byte[16];
public byte[] CheckValue = new byte[12];
// File Hash Information
public uint HashSize; // vint
public uint HashType; // vint
public byte[] HashData = new byte[32];
// File Hash Information
public uint HashSize; // vint
public uint HashType; // vint
public byte[] HashData = new byte[32];
// File Time Information
public uint TimeSize; // vint
public RarTimeFlags TimeFlags; // vint
public uint TimeMtime;
public ulong TimeMtime64;
public uint TimeCtime;
public ulong TimeCtime64;
public uint TimeLtime;
public ulong TimeLtime64;
// File Time Information
public uint TimeSize; // vint
public RarTimeFlags TimeFlags; // vint
public uint TimeMtime;
public ulong TimeMtime64;
public uint TimeCtime;
public ulong TimeCtime64;
public uint TimeLtime;
public ulong TimeLtime64;
// File Version Information
public uint VersionSize; // vint
public const uint VersionFlags = 0; // vint
public uint VersionNumber; // vint
// File Version Information
public uint VersionSize; // vint
public const uint VersionFlags = 0; // vint
public uint VersionNumber; // vint
// File System Redirection Record
public uint RedirectionSize; // vint
public RarRedirectionType RedirectionType; // vint
public uint RedirectionFlags; // vint
public uint RedirectionNameLength; // vint
public byte[] RedirectionName;
// File System Redirection Record
public uint RedirectionSize; // vint
public RarRedirectionType RedirectionType; // vint
public uint RedirectionFlags; // vint
public uint RedirectionNameLength; // vint
public byte[] RedirectionName;
// Unix Owner Record
public uint UnixOwnerSize; // vint
public RarUnixOwnerRecordFlags UnixOwnerFlags; // vint
public uint UnixOwnerUserNameLength; // vint
public byte[] UnixOwnerUserName;
public uint UnixOwnerGroupNameLength; // vint
public byte[] UnixOwnerGroupName;
public uint UnixOwnerUserId; // vint
public uint UnixOwnerGroupId; // vint
// Unix Owner Record
public uint UnixOwnerSize; // vint
public RarUnixOwnerRecordFlags UnixOwnerFlags; // vint
public uint UnixOwnerUserNameLength; // vint
public byte[] UnixOwnerUserName;
public uint UnixOwnerGroupNameLength; // vint
public byte[] UnixOwnerGroupName;
public uint UnixOwnerUserId; // vint
public uint UnixOwnerGroupId; // vint
// Service Data Information
public uint ServiceSize; // vint
public byte[] ServiceData;
}
// Service Data Information
public uint ServiceSize; // vint
public byte[] ServiceData;
}
// BELOW ARE CONCRETE IMPLEMENTATIONS OF HEADER DETAILS
// BELOW ARE CONCRETE IMPLEMENTATIONS OF HEADER DETAILS
/// <summary>
/// General archive block format used by all RAR block types
/// </summary>
public class GeneralArchiveBlockFormat
{
public uint HeaderCRC32;
public uint HeaderSize; // vint
public HeaderType HeaderType;
public HeaderFlags HeaderFlags;
public ulong ExtraAreaSize; // vint
public ulong DataAreaSize; // vint
public byte[] ExtraArea;
public byte[] DataArea;
}
/// <summary>
/// General archive block format used by all RAR block types
/// </summary>
public class GeneralArchiveBlockFormat
{
public uint HeaderCRC32;
public uint HeaderSize; // vint
public HeaderType HeaderType;
public HeaderFlags HeaderFlags;
public ulong ExtraAreaSize; // vint
public ulong DataAreaSize; // vint
public byte[] ExtraArea;
public byte[] DataArea;
}
/// <summary>
/// General extra area format used by all RAR extra area records
/// </summary>
public class GeneralExtraAreaFormat
{
public ulong Size; // vint
public ulong Type; // vint
public byte[] Data;
}
/// <summary>
/// General extra area format used by all RAR extra area records
/// </summary>
public class GeneralExtraAreaFormat
{
public ulong Size; // vint
public ulong Type; // vint
public byte[] Data;
}
/// <summary>
/// Encryption header only present in encrypted archives
///
/// Every proceeding header is started from 16 byte AES-256
/// initialization vectors followed by encrypted header data
/// </summary>
public class ArchiveEncryptionHeader : GeneralArchiveBlockFormat
{
public new HeaderType HeaderType = HeaderType.ArchiveEncryptionHeader;
public ulong EncryptionVersion; // vint
public ulong EncryptionFlags; // vint
}
/// <summary>
/// Encryption header only present in encrypted archives
///
/// Every proceeding header is started from 16 byte AES-256
/// initialization vectors followed by encrypted header data
/// </summary>
public class ArchiveEncryptionHeader : GeneralArchiveBlockFormat
{
public new HeaderType HeaderType = HeaderType.ArchiveEncryptionHeader;
public ulong EncryptionVersion; // vint
public ulong EncryptionFlags; // vint
}
/// <summary>
/// Types of archive header
/// </summary>
public enum HeaderType : ulong // vint
{
MainArchiveHeader = 1,
FileHeader = 2,
ServiceHeader = 3,
ArchiveEncryptionHeader = 4,
EndOfArchiveHeader = 5,
}
/// <summary>
/// Types of archive header
/// </summary>
public enum HeaderType : ulong // vint
{
MainArchiveHeader = 1,
FileHeader = 2,
ServiceHeader = 3,
ArchiveEncryptionHeader = 4,
EndOfArchiveHeader = 5,
}
/// <summary>
/// Flags common for all headers
/// </summary>
[Flags]
public enum HeaderFlags : ulong // vint
{
ExtraAreaIsPresentInEndOfHeader = 0x0001,
DataAreaIsPresentInEndOfHeader = 0x0002,
BlocksWithUnknownType = 0x0004, // this flag must be skipped when updating an archive
DataAreaIsContinuingFromPreviousVolume = 0x0008,
DataAreaIsContinuingInNextVolume = 0x0010,
BlockDependsOnPrecedingFileBlock = 0x0020,
PreserveChildBlockIfHostBlockIsModified = 0x0040,
}
/// <summary>
/// Flags common for all headers
/// </summary>
[Flags]
public enum HeaderFlags : ulong // vint
{
ExtraAreaIsPresentInEndOfHeader = 0x0001,
DataAreaIsPresentInEndOfHeader = 0x0002,
BlocksWithUnknownType = 0x0004, // this flag must be skipped when updating an archive
DataAreaIsContinuingFromPreviousVolume = 0x0008,
DataAreaIsContinuingInNextVolume = 0x0010,
BlockDependsOnPrecedingFileBlock = 0x0020,
PreserveChildBlockIfHostBlockIsModified = 0x0040,
}
}

View File

@@ -23,305 +23,305 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// Represents a folder for reading and writing
/// </summary>
public class Folder : BaseFile
{
#region Protected instance variables
/// <summary>
/// Represents a folder for reading and writing
/// </summary>
public class Folder : BaseFile
{
#region Protected instance variables
protected List<BaseFile> _children;
protected List<BaseFile> _children;
#endregion
#endregion
#region Constructors
#region Constructors
/// <summary>
/// Create a new folder with no base file
/// </summary>
public Folder()
: base()
{
_fileType = FileType.Folder;
}
/// <summary>
/// Create a new folder with no base file
/// </summary>
public Folder()
: base()
{
this.Type = FileType.Folder;
}
/// <summary>
/// Create a new folder from the given file
/// </summary>
/// <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="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
public Folder(string filename, bool getHashes = false)
: base(filename, getHashes)
{
_fileType = FileType.Folder;
}
/// <summary>
/// Create a new folder from the given file
/// </summary>
/// <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="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
public Folder(string filename, bool getHashes = false)
: base(filename, getHashes)
{
this.Type = FileType.Folder;
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public virtual bool CopyAll(string outDir)
{
// Copy all files from the current folder to the output directory recursively
try
{
// Make sure the folders exist
Directory.CreateDirectory(_filename);
Directory.CreateDirectory(outDir);
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public virtual bool CopyAll(string outDir)
{
// Copy all files from the current folder to the output directory recursively
try
{
// Make sure the folders exist
Directory.CreateDirectory(this.Filename);
Directory.CreateDirectory(outDir);
Directory.Copy(_filename, outDir, true, PathFormat.FullPath);
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return false;
}
Directory.Copy(this.Filename, outDir, true, PathFormat.FullPath);
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return false;
}
return true;
}
return true;
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public virtual string CopyToFile(string entryName, string outDir)
{
string realentry = null;
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public virtual string CopyToFile(string entryName, string outDir)
{
string realentry = null;
// Copy single file from the current folder to the output directory, if exists
try
{
// Make sure the folders exist
Directory.CreateDirectory(_filename);
Directory.CreateDirectory(outDir);
// Copy single file from the current folder to the output directory, if exists
try
{
// Make sure the folders exist
Directory.CreateDirectory(this.Filename);
Directory.CreateDirectory(outDir);
// Get all files from the input directory
List<string> files = Utilities.RetrieveFiles(_filename, new List<string>());
// Get all files from the input directory
List<string> files = Utilities.RetrieveFiles(this.Filename, new List<string>());
// Now sort through to find the first file that matches
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
// Now sort through to find the first file that matches
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
// If we had a file, copy that over to the new name
if (!String.IsNullOrWhiteSpace(match))
{
realentry = match;
File.Copy(match, Path.Combine(outDir, entryName));
}
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return realentry;
}
// If we had a file, copy that over to the new name
if (!String.IsNullOrWhiteSpace(match))
{
realentry = match;
File.Copy(match, Path.Combine(outDir, entryName));
}
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return realentry;
}
return realentry;
}
return realentry;
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public virtual (MemoryStream, string) CopyToStream(string entryName)
{
MemoryStream ms = new MemoryStream();
string realentry = null;
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public virtual (MemoryStream, string) CopyToStream(string entryName)
{
MemoryStream ms = new MemoryStream();
string realentry = null;
// Copy single file from the current folder to the output directory, if exists
try
{
// Make sure the folders exist
Directory.CreateDirectory(_filename);
// Copy single file from the current folder to the output directory, if exists
try
{
// Make sure the folders exist
Directory.CreateDirectory(this.Filename);
// Get all files from the input directory
List<string> files = Utilities.RetrieveFiles(_filename, new List<string>());
// Get all files from the input directory
List<string> files = Utilities.RetrieveFiles(this.Filename, new List<string>());
// Now sort through to find the first file that matches
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
// Now sort through to find the first file that matches
string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
// If we had a file, copy that over to the new name
if (!String.IsNullOrWhiteSpace(match))
{
Utilities.TryOpenRead(match).CopyTo(ms);
realentry = match;
}
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return (ms, realentry);
}
// If we had a file, copy that over to the new name
if (!String.IsNullOrWhiteSpace(match))
{
Utilities.TryOpenRead(match).CopyTo(ms);
realentry = match;
}
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return (ms, realentry);
}
return (ms, realentry);
}
return (ms, realentry);
}
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of immediate children from the current folder
/// </summary>
/// <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>
/// <returns>List of BaseFile objects representing the found data</returns>
/// <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)
{
if (_children == null || _children.Count == 0)
{
_children = new List<BaseFile>();
foreach (string file in Directory.EnumerateFiles(_filename, "*", SearchOption.TopDirectoryOnly))
{
BaseFile nf = Utilities.GetFileInfo(file, omitFromScan: omitFromScan, date: date);
_children.Add(nf);
}
foreach (string dir in Directory.EnumerateDirectories(_filename, "*", SearchOption.TopDirectoryOnly))
{
Folder fl = new Folder(dir);
_children.Add(fl);
}
}
/// <summary>
/// Generate a list of immediate children from the current folder
/// </summary>
/// <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>
/// <returns>List of BaseFile objects representing the found data</returns>
/// <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)
{
if (_children == null || _children.Count == 0)
{
_children = new List<BaseFile>();
foreach (string file in Directory.EnumerateFiles(this.Filename, "*", SearchOption.TopDirectoryOnly))
{
BaseFile nf = Utilities.GetFileInfo(file, omitFromScan: omitFromScan, date: date);
_children.Add(nf);
}
foreach (string dir in Directory.EnumerateDirectories(this.Filename, "*", SearchOption.TopDirectoryOnly))
{
Folder fl = new Folder(dir);
_children.Add(fl);
}
}
return _children;
}
return _children;
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the folder</returns>
public virtual List<string> GetEmptyFolders()
{
return Utilities.GetEmptyDirectories(_filename).ToList();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the folder</returns>
public virtual List<string> GetEmptyFolders()
{
return Utilities.GetEmptyDirectories(this.Filename).ToList();
}
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to an output folder
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
FileStream fs = Utilities.TryOpenRead(inputFile);
return Write(fs, outDir, rom, date, romba);
}
/// <summary>
/// Write an input file to an output folder
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
FileStream fs = Utilities.TryOpenRead(inputFile);
return Write(fs, outDir, rom, date, romba);
}
/// <summary>
/// Write an input stream to an output folder
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
bool success = false;
/// <summary>
/// Write an input stream to an output folder
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
bool success = false;
// If either input is null or empty, return
if (inputStream == null || rom == null || rom.Name == null)
{
return success;
}
// If either input is null or empty, return
if (inputStream == null || rom == null || rom.Name == null)
{
return success;
}
// If the stream is not readable, return
if (!inputStream.CanRead)
{
return success;
}
// If the stream is not readable, return
if (!inputStream.CanRead)
{
return success;
}
// Set internal variables
FileStream outputStream = null;
// Set internal variables
FileStream outputStream = null;
// Get the output folder name from the first rebuild rom
string fileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName), Utilities.RemovePathUnsafeCharacters(rom.Name));
// Get the output folder name from the first rebuild rom
string fileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName), Utilities.RemovePathUnsafeCharacters(rom.Name));
try
{
// If the full output path doesn't exist, create it
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
}
try
{
// If the full output path doesn't exist, create it
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
}
// Overwrite output files by default
outputStream = Utilities.TryCreate(fileName);
// Overwrite output files by default
outputStream = Utilities.TryCreate(fileName);
// If the output stream isn't null
if (outputStream != null)
{
// Copy the input stream to the output
inputStream.Seek(0, SeekOrigin.Begin);
int bufferSize = 4096 * 128;
byte[] ibuffer = new byte[bufferSize];
int ilen;
while ((ilen = inputStream.Read(ibuffer, 0, bufferSize)) > 0)
{
outputStream.Write(ibuffer, 0, ilen);
outputStream.Flush();
}
outputStream.Dispose();
// If the output stream isn't null
if (outputStream != null)
{
// Copy the input stream to the output
inputStream.Seek(0, SeekOrigin.Begin);
int bufferSize = 4096 * 128;
byte[] ibuffer = new byte[bufferSize];
int ilen;
while ((ilen = inputStream.Read(ibuffer, 0, bufferSize)) > 0)
{
outputStream.Write(ibuffer, 0, ilen);
outputStream.Flush();
}
outputStream.Dispose();
if (rom.ItemType == ItemType.Rom)
{
if (date && !String.IsNullOrWhiteSpace(((Rom)rom).Date))
{
File.SetCreationTime(fileName, DateTime.Parse(((Rom)rom).Date));
}
}
if (rom.ItemType == ItemType.Rom)
{
if (date && !String.IsNullOrWhiteSpace(((Rom)rom).Date))
{
File.SetCreationTime(fileName, DateTime.Parse(((Rom)rom).Date));
}
}
success = true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
success = false;
}
finally
{
inputStream.Dispose();
outputStream?.Dispose();
}
success = true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
success = false;
}
finally
{
inputStream.Dispose();
outputStream?.Dispose();
}
return success;
}
return success;
}
/// <summary>
/// Write a set of input files to an output folder (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public virtual bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to an output folder (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public virtual bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// Represents a TorrentLRZip archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/ckolivas/lrzip
public class LRZipArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Represents a TorrentLRZip archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/ckolivas/lrzip
public class LRZipArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Create a new LRZipArchive with no base file
/// </summary>
public LRZipArchive()
: base()
{
_fileType = FileType.LRZipArchive;
}
/// <summary>
/// Create a new LRZipArchive with no base file
/// </summary>
public LRZipArchive()
: base()
{
this.Type = FileType.LRZipArchive;
}
/// <summary>
/// Create a new LRZipArchive from the given file
/// </summary>
/// <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>
public LRZipArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
_fileType = FileType.LRZipArchive;
}
/// <summary>
/// Create a new LRZipArchive from the given file
/// </summary>
/// <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>
public LRZipArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
this.Type = FileType.LRZipArchive;
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to a torrent LRZip file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input file to a torrent LRZip file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent LRZip file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent LRZip file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent LRZip archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent LRZip archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
}

View File

@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// Represents a TorrentLRZip archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/lz4/lz4
public class LZ4Archive : BaseArchive
{
#region Constructors
/// <summary>
/// Represents a TorrentLRZip archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/lz4/lz4
public class LZ4Archive : BaseArchive
{
#region Constructors
/// <summary>
/// Create a new LZ4Archive with no base file
/// </summary>
public LZ4Archive()
: base()
{
_fileType = FileType.LZ4Archive;
}
/// <summary>
/// Create a new LZ4Archive with no base file
/// </summary>
public LZ4Archive()
: base()
{
this.Type = FileType.LZ4Archive;
}
/// <summary>
/// Create a new LZ4Archive from the given file
/// </summary>
/// <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>
public LZ4Archive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
_fileType = FileType.LZ4Archive;
}
/// <summary>
/// Create a new LZ4Archive from the given file
/// </summary>
/// <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>
public LZ4Archive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
this.Type = FileType.LZ4Archive;
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to a torrent LZ4 file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input file to a torrent LZ4 file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent LZ4 file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent LZ4 file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent LZ4 archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent LZ4 archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
}

View File

@@ -37,7 +37,7 @@ namespace SabreTools.Library.FileTypes
public RarArchive()
: base()
{
_fileType = FileType.RarArchive;
this.Type = FileType.RarArchive;
}
/// <summary>
@@ -49,7 +49,7 @@ namespace SabreTools.Library.FileTypes
public RarArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
_fileType = FileType.RarArchive;
this.Type = FileType.RarArchive;
}
#endregion
@@ -71,7 +71,7 @@ namespace SabreTools.Library.FileTypes
Directory.CreateDirectory(outDir);
// 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)
{
entry.WriteToDirectory(outDir, new ExtractionOptions { PreserveFileTime = true, ExtractFullPath = true, Overwrite = true });
@@ -155,7 +155,7 @@ namespace SabreTools.Library.FileTypes
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)
{
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)
{
List<BaseFile> found = new List<BaseFile>();
string gamename = Path.GetFileNameWithoutExtension(_filename);
string gamename = Path.GetFileNameWithoutExtension(this.Filename);
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))
{
// 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
public void GetRarFileInfo()
{
if (!File.Exists(_filename))
if (!File.Exists(this.Filename))
{
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)
byte[] signature = br.ReadBytes(8);
@@ -464,7 +464,7 @@ namespace SabreTools.Library.FileTypes
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();
string lastRarEntry = null;
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

View File

@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// Represents a ZPAQArchive archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/zpaq/zpaq - In progress as external DLL
public class ZPAQArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Represents a ZPAQArchive archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/zpaq/zpaq - In progress as external DLL
public class ZPAQArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Create a new ZPAQArchive with no base file
/// </summary>
public ZPAQArchive()
: base()
{
_fileType = FileType.ZPAQArchive;
}
/// <summary>
/// Create a new ZPAQArchive with no base file
/// </summary>
public ZPAQArchive()
: base()
{
this.Type = FileType.ZPAQArchive;
}
/// <summary>
/// Create a new ZPAQArchive from the given file
/// </summary>
/// <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>
public ZPAQArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
_fileType = FileType.ZPAQArchive;
}
/// <summary>
/// Create a new ZPAQArchive from the given file
/// </summary>
/// <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>
public ZPAQArchive(string filename, bool getHashes = false)
: base(filename, getHashes)
{
this.Type = FileType.ZPAQArchive;
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to a torrent ZPAQ file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input file to a torrent ZPAQ file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent ZPAQ file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent ZPAQ file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent ZPAQ archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent ZPAQ archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,152 +13,152 @@ using Stream = System.IO.Stream;
namespace SabreTools.Library.FileTypes
{
/// <summary>
/// Represents a ZstdArchive archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/skbkontur/ZstdNet
public class ZstdArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Represents a ZstdArchive archive for reading and writing
/// </summary>
/// TODO: Implement from source at https://github.com/skbkontur/ZstdNet
public class ZstdArchive : BaseArchive
{
#region Constructors
/// <summary>
/// Create a new ZstdArchive with no base file
/// </summary>
public ZstdArchive()
: base()
{
_fileType = FileType.ZstdArchive;
}
/// <summary>
/// Create a new ZstdArchive with no base file
/// </summary>
public ZstdArchive()
: base()
{
this.Type = FileType.ZstdArchive;
}
/// <summary>
/// Create a new ZstdArchive from the given file
/// </summary>
/// <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>
public ZstdArchive(string filename, bool getHashes)
: base(filename, getHashes)
{
_fileType = FileType.ZstdArchive;
}
/// <summary>
/// Create a new ZstdArchive from the given file
/// </summary>
/// <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>
public ZstdArchive(string filename, bool getHashes)
: base(filename, getHashes)
{
this.Type = FileType.ZstdArchive;
}
#endregion
#endregion
#region Extraction
#region Extraction
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file as an archive
/// </summary>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>True if the extraction was a success, false otherwise</returns>
public override bool CopyAll(string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a file from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="outDir">Output directory for archive extraction</param>
/// <returns>Name of the extracted file, null on error</returns>
public override string CopyToFile(string entryName, string outDir)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="realEntry">Output representing the entry name that was found</param>
/// <returns>MemoryStream representing the entry, null on error</returns>
public override (MemoryStream, string) CopyToStream(string entryName)
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Information
#region Information
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of DatItem objects from the header values in an archive
/// </summary>
/// <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>
/// <returns>List of DatItem objects representing the found data</returns>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Generate a list of empty folders in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <returns>List of empty folders in the archive</returns>
public override List<string> GetEmptyFolders()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
/// <summary>
/// Check whether the input file is a standardized format
/// </summary>
public override bool IsTorrent()
{
throw new NotImplementedException();
}
#endregion
#endregion
#region Writing
#region Writing
/// <summary>
/// Write an input file to a torrent Zstd file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input file to a torrent Zstd file
/// </summary>
/// <param name="inputFile">Input filename to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent Zstd file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write an input stream to a torrent Zstd file
/// </summary>
/// <param name="inputStream">Input stream to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
/// <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)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent Zstd archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
/// <summary>
/// Write a set of input files to a torrent Zstd archive (assuming the same output archive name)
/// </summary>
/// <param name="inputFiles">Input files to be moved</param>
/// <param name="outDir">Output directory to build to</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="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>
public override bool Write(List<string> inputFiles, string outDir, List<Rom> roms, bool date = false, bool romba = false)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
}
}