2016-09-19 20:52:55 -07:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2017-02-27 20:09:47 -08:00
|
|
|
|
using System.Linq;
|
2016-10-24 13:51:39 -07:00
|
|
|
|
|
2017-05-04 02:41:11 -07:00
|
|
|
|
using SabreTools.Library.Data;
|
|
|
|
|
|
using SabreTools.Library.Tools;
|
2016-10-24 13:51:39 -07:00
|
|
|
|
|
2016-10-28 21:49:29 -07:00
|
|
|
|
#if MONO
|
2016-10-27 11:35:17 -07:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
#else
|
2016-10-26 22:10:47 -07:00
|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
2016-10-27 11:35:17 -07:00
|
|
|
|
#endif
|
2016-10-24 12:58:57 -07:00
|
|
|
|
using NaturalSort;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
2017-05-04 02:41:11 -07:00
|
|
|
|
namespace SabreTools.Library.Dats
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2017-05-14 23:53:03 -07:00
|
|
|
|
public abstract class DatItem : IEquatable<DatItem>, IComparable<DatItem>, ICloneable
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
#region Protected instance variables
|
|
|
|
|
|
|
|
|
|
|
|
// Standard item information
|
|
|
|
|
|
protected string _name;
|
2017-02-04 21:40:25 -08:00
|
|
|
|
private string _merge;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
protected ItemType _itemType;
|
|
|
|
|
|
protected DupeType _dupeType;
|
|
|
|
|
|
|
|
|
|
|
|
// Machine information
|
2016-10-24 12:58:57 -07:00
|
|
|
|
protected Machine _machine;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
2016-09-30 16:25:58 -07:00
|
|
|
|
// Software list information
|
|
|
|
|
|
protected bool? _supported;
|
|
|
|
|
|
protected string _publisher;
|
2016-10-03 10:00:20 -07:00
|
|
|
|
protected List<Tuple<string, string>> _infos;
|
2016-09-30 16:25:58 -07:00
|
|
|
|
protected string _partName;
|
|
|
|
|
|
protected string _partInterface;
|
2016-10-03 10:00:20 -07:00
|
|
|
|
protected List<Tuple<string, string>> _features;
|
2016-09-30 16:25:58 -07:00
|
|
|
|
protected string _areaName;
|
|
|
|
|
|
protected long? _areaSize;
|
|
|
|
|
|
|
2016-09-19 20:52:55 -07:00
|
|
|
|
// Source metadata information
|
|
|
|
|
|
protected int _systemId;
|
|
|
|
|
|
protected string _systemName;
|
|
|
|
|
|
protected int _sourceId;
|
|
|
|
|
|
protected string _sourceName;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Publicly facing variables
|
|
|
|
|
|
|
|
|
|
|
|
// Standard item information
|
|
|
|
|
|
public string Name
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _name; }
|
|
|
|
|
|
set { _name = value; }
|
|
|
|
|
|
}
|
2017-02-04 21:40:25 -08:00
|
|
|
|
public string MergeTag
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _merge; }
|
|
|
|
|
|
set { _merge = value; }
|
|
|
|
|
|
}
|
2016-09-19 20:52:55 -07:00
|
|
|
|
public ItemType Type
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _itemType; }
|
|
|
|
|
|
set { _itemType = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public DupeType Dupe
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _dupeType; }
|
|
|
|
|
|
set { _dupeType = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Machine information
|
2016-10-24 12:58:57 -07:00
|
|
|
|
public Machine Machine
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-24 12:58:57 -07:00
|
|
|
|
get { return _machine; }
|
|
|
|
|
|
set { _machine = value; }
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-30 16:25:58 -07:00
|
|
|
|
// Software list information
|
|
|
|
|
|
public bool? Supported
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _supported; }
|
|
|
|
|
|
set { _supported = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string Publisher
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _publisher; }
|
|
|
|
|
|
set { _publisher = value; }
|
|
|
|
|
|
}
|
2016-10-03 10:00:20 -07:00
|
|
|
|
public List<Tuple<string, string>> Infos
|
2016-09-30 16:25:58 -07:00
|
|
|
|
{
|
|
|
|
|
|
get { return _infos; }
|
|
|
|
|
|
set { _infos = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string PartName
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _partName; }
|
|
|
|
|
|
set { _partName = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string PartInterface
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _partInterface; }
|
|
|
|
|
|
set { _partInterface = value; }
|
|
|
|
|
|
}
|
2016-10-03 10:00:20 -07:00
|
|
|
|
public List<Tuple<string, string>> Features
|
2016-09-30 16:25:58 -07:00
|
|
|
|
{
|
|
|
|
|
|
get { return _features; }
|
|
|
|
|
|
set { _features = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string AreaName
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _areaName; }
|
|
|
|
|
|
set { _areaName = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public long? AreaSize
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _areaSize; }
|
|
|
|
|
|
set { _areaSize = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-19 20:52:55 -07:00
|
|
|
|
// Source metadata information
|
|
|
|
|
|
public int SystemID
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _systemId; }
|
|
|
|
|
|
set { _systemId = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string System
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _systemName; }
|
|
|
|
|
|
set { _systemName = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public int SourceID
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _sourceId; }
|
|
|
|
|
|
set { _sourceId = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public string Source
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _sourceName; }
|
|
|
|
|
|
set { _sourceName = value; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2016-10-31 14:02:02 -07:00
|
|
|
|
#region Instance Methods
|
|
|
|
|
|
|
2017-05-14 23:53:03 -07:00
|
|
|
|
#region Cloning Methods
|
|
|
|
|
|
|
|
|
|
|
|
public object Clone()
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (_itemType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ItemType.Archive:
|
|
|
|
|
|
return ((Archive)this).Clone();
|
|
|
|
|
|
case ItemType.BiosSet:
|
|
|
|
|
|
return ((BiosSet)this).Clone();
|
|
|
|
|
|
case ItemType.Disk:
|
|
|
|
|
|
return ((Disk)this).Clone();
|
|
|
|
|
|
case ItemType.Release:
|
|
|
|
|
|
return ((Release)this).Clone();
|
|
|
|
|
|
case ItemType.Rom:
|
|
|
|
|
|
return ((Rom)this).Clone();
|
|
|
|
|
|
case ItemType.Sample:
|
|
|
|
|
|
return ((Sample)this).Clone();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2017-03-18 00:04:59 -07:00
|
|
|
|
#region Comparision Methods
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
|
|
|
|
|
public int CompareTo(DatItem other)
|
|
|
|
|
|
{
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_name == other.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
ret = (this.Equals(other) ? 0 : 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
ret = String.Compare(_name, other.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Determine if an item is a duplicate using partial matching logic
|
|
|
|
|
|
/// </summary>
|
2017-03-18 21:57:58 -07:00
|
|
|
|
/// <param name="other">DatItem to use as a baseline</param>
|
2016-09-19 20:52:55 -07:00
|
|
|
|
/// <returns>True if the roms are duplicates, false otherwise</returns>
|
2017-03-18 21:57:58 -07:00
|
|
|
|
public abstract bool Equals(DatItem other);
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Return the duplicate status of two items
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="lastItem">DatItem to check against</param>
|
|
|
|
|
|
/// <returns>The DupeType corresponding to the relationship between the two</returns>
|
2017-03-01 21:26:27 -08:00
|
|
|
|
public DupeType GetDuplicateStatus(DatItem lastItem)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-05 20:33:02 -07:00
|
|
|
|
DupeType output = 0x00;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
|
|
|
|
|
// If we don't have a duplicate at all, return none
|
2017-03-18 21:57:58 -07:00
|
|
|
|
if (!this.Equals(lastItem))
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the duplicate is external already or should be, set it
|
2016-10-05 20:33:02 -07:00
|
|
|
|
if ((lastItem.Dupe & DupeType.External) != 0 || lastItem.SystemID != this.SystemID || lastItem.SourceID != this.SourceID)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-24 12:58:57 -07:00
|
|
|
|
if (lastItem.Machine.Name == this.Machine.Name && lastItem.Name == this.Name)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-05 20:33:02 -07:00
|
|
|
|
output = DupeType.External | DupeType.All;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-10-05 20:33:02 -07:00
|
|
|
|
output = DupeType.External | DupeType.Hash;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise, it's considered an internal dupe
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-10-24 12:58:57 -07:00
|
|
|
|
if (lastItem.Machine.Name == this.Machine.Name && lastItem.Name == this.Name)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-05 20:33:02 -07:00
|
|
|
|
output = DupeType.Internal | DupeType.All;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-10-05 20:33:02 -07:00
|
|
|
|
output = DupeType.Internal | DupeType.Hash;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2017-03-18 00:04:59 -07:00
|
|
|
|
#region Sorting and Merging
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
2016-10-06 16:19:09 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a DAT contains the given rom
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="datdata">Dat to match against</param>
|
2017-06-01 11:19:54 -07:00
|
|
|
|
/// <param name="sorted">True if the DAT is already sorted accordingly, false otherwise (default)</param>
|
2016-10-06 16:19:09 -07:00
|
|
|
|
/// <returns>True if it contains the rom, false otherwise</returns>
|
2017-06-01 11:19:54 -07:00
|
|
|
|
public bool HasDuplicates(DatFile datdata, bool sorted = false)
|
2016-10-06 16:19:09 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Check for an empty rom list first
|
2016-11-08 15:29:52 -08:00
|
|
|
|
if (datdata.Count == 0)
|
2016-10-06 16:19:09 -07:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-27 22:03:26 -08:00
|
|
|
|
// We want to get the proper key for the DatItem
|
2017-06-01 11:19:54 -07:00
|
|
|
|
string key = SortAndGetKey(datdata, sorted);
|
2016-10-06 16:19:09 -07:00
|
|
|
|
|
|
|
|
|
|
// If the key doesn't exist, return the empty list
|
2017-09-25 12:56:45 -07:00
|
|
|
|
if (!datdata.Contains(key))
|
2016-10-06 16:19:09 -07:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Try to find duplicates
|
2016-11-08 15:29:52 -08:00
|
|
|
|
List<DatItem> roms = datdata[key];
|
2016-10-06 16:19:09 -07:00
|
|
|
|
|
|
|
|
|
|
foreach (DatItem rom in roms)
|
|
|
|
|
|
{
|
2017-03-18 21:57:58 -07:00
|
|
|
|
if (this.Equals(rom))
|
2016-10-06 16:19:09 -07:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-22 20:30:04 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List all duplicates found in a DAT based on a rom
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="datdata">Dat to match against</param>
|
|
|
|
|
|
/// <param name="remove">True to remove matched roms from the input, false otherwise (default)</param>
|
|
|
|
|
|
/// <returns>List of matched DatItem objects</returns>
|
2017-03-01 21:26:27 -08:00
|
|
|
|
public List<DatItem> GetDuplicates(DatFile datdata, bool remove = false)
|
2016-09-22 20:30:04 -07:00
|
|
|
|
{
|
|
|
|
|
|
List<DatItem> output = new List<DatItem>();
|
|
|
|
|
|
|
|
|
|
|
|
// Check for an empty rom list first
|
2016-11-08 15:29:52 -08:00
|
|
|
|
if (datdata.Count == 0)
|
2016-09-22 20:30:04 -07:00
|
|
|
|
{
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-27 22:03:26 -08:00
|
|
|
|
// We want to get the proper key for the DatItem
|
2017-03-01 21:26:27 -08:00
|
|
|
|
string key = SortAndGetKey(datdata);
|
2017-02-27 22:10:24 -08:00
|
|
|
|
|
|
|
|
|
|
// If the key doesn't exist, return the empty list
|
2017-09-25 12:56:45 -07:00
|
|
|
|
if (!datdata.Contains(key))
|
2017-02-27 22:10:24 -08:00
|
|
|
|
{
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Try to find duplicates
|
|
|
|
|
|
List<DatItem> roms = datdata[key];
|
|
|
|
|
|
List<DatItem> left = new List<DatItem>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (DatItem rom in roms)
|
|
|
|
|
|
{
|
2017-03-18 21:57:58 -07:00
|
|
|
|
if (this.Equals(rom))
|
2017-02-27 22:10:24 -08:00
|
|
|
|
{
|
|
|
|
|
|
output.Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
left.Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we're in removal mode, replace the list with the new one
|
|
|
|
|
|
if (remove)
|
|
|
|
|
|
{
|
2017-09-25 12:21:52 -07:00
|
|
|
|
datdata.Remove(key);
|
|
|
|
|
|
datdata.AddRange(key, left);
|
2017-02-27 22:10:24 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Sort the input DAT and get the key to be used by the item
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="datdata">Dat to match against</param>
|
2017-06-01 11:19:54 -07:00
|
|
|
|
/// <param name="sorted">True if the DAT is already sorted accordingly, false otherwise (default)</param>
|
2017-02-27 22:10:24 -08:00
|
|
|
|
/// <returns>Key to try to use</returns>
|
2017-06-01 11:19:54 -07:00
|
|
|
|
private string SortAndGetKey(DatFile datdata, bool sorted = false)
|
2017-02-27 22:10:24 -08:00
|
|
|
|
{
|
|
|
|
|
|
string key = null;
|
2017-02-27 20:09:47 -08:00
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If we're not already sorted, take care of it
|
|
|
|
|
|
if (!sorted)
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If all items are supposed to have a SHA-512, we sort by that
|
|
|
|
|
|
if (datdata.RomCount + datdata.DiskCount - datdata.NodumpCount == datdata.SHA512Count
|
|
|
|
|
|
&& ((_itemType == ItemType.Rom && !String.IsNullOrEmpty(((Rom)this).SHA512))
|
|
|
|
|
|
|| (_itemType == ItemType.Disk && !String.IsNullOrEmpty(((Disk)this).SHA512))))
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA512, DedupeType.None);
|
2017-02-27 22:16:52 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If all items are supposed to have a SHA-384, we sort by that
|
|
|
|
|
|
else if (datdata.RomCount + datdata.DiskCount - datdata.NodumpCount == datdata.SHA384Count
|
|
|
|
|
|
&& ((_itemType == ItemType.Rom && !String.IsNullOrEmpty(((Rom)this).SHA384))
|
|
|
|
|
|
|| (_itemType == ItemType.Disk && !String.IsNullOrEmpty(((Disk)this).SHA384))))
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA384, DedupeType.None);
|
2017-02-27 22:16:52 -08:00
|
|
|
|
}
|
2017-06-01 11:19:54 -07:00
|
|
|
|
|
|
|
|
|
|
// If all items are supposed to have a SHA-256, we sort by that
|
|
|
|
|
|
else if (datdata.RomCount + datdata.DiskCount - datdata.NodumpCount == datdata.SHA256Count
|
|
|
|
|
|
&& ((_itemType == ItemType.Rom && !String.IsNullOrEmpty(((Rom)this).SHA256))
|
|
|
|
|
|
|| (_itemType == ItemType.Disk && !String.IsNullOrEmpty(((Disk)this).SHA256))))
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA256;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA256, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA256;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA256, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2017-02-27 22:16:52 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If all items are supposed to have a SHA-1, we sort by that
|
|
|
|
|
|
else if (datdata.RomCount + datdata.DiskCount - datdata.NodumpCount == datdata.SHA1Count
|
|
|
|
|
|
&& ((_itemType == ItemType.Rom && !String.IsNullOrEmpty(((Rom)this).SHA1))
|
|
|
|
|
|
|| (_itemType == ItemType.Disk && !String.IsNullOrEmpty(((Disk)this).SHA1))))
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA1;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA1, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA1;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.SHA1, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2017-02-27 22:16:52 -08:00
|
|
|
|
}
|
2017-06-01 11:19:54 -07:00
|
|
|
|
|
|
|
|
|
|
// If all items are supposed to have an MD5, we sort by that
|
|
|
|
|
|
else if (datdata.RomCount + datdata.DiskCount - datdata.NodumpCount == datdata.MD5Count
|
|
|
|
|
|
&& ((_itemType == ItemType.Rom && !String.IsNullOrEmpty(((Rom)this).MD5))
|
|
|
|
|
|
|| (_itemType == ItemType.Disk && !String.IsNullOrEmpty(((Disk)this).MD5))))
|
2017-02-27 22:16:52 -08:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).MD5;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.MD5, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).MD5;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.MD5, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2017-02-27 22:16:52 -08:00
|
|
|
|
}
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2017-02-27 22:16:52 -08:00
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// Now that we have the sorted type, we get the proper key
|
|
|
|
|
|
switch (datdata.SortedBy)
|
2016-10-06 11:42:55 -07:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
case SortedBy.SHA512:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA512;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_itemType == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA512;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.SHA384:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA384;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_itemType == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA384;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.SHA256:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA256;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_itemType == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA256;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.SHA1:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).SHA1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_itemType == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).SHA1;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.MD5:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).MD5;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_itemType == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).MD5;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.CRC:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).CRC;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.Game:
|
|
|
|
|
|
key = this.Machine.Name;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SortedBy.Size:
|
|
|
|
|
|
if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).Size.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2016-10-06 11:42:55 -07:00
|
|
|
|
}
|
2017-02-27 20:09:47 -08:00
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If we got here and the key is still null...
|
|
|
|
|
|
if (key == null)
|
2017-02-27 22:03:26 -08:00
|
|
|
|
{
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If we've gotten here and we have a Disk, sort by MD5
|
|
|
|
|
|
if (_itemType == ItemType.Disk)
|
2017-02-27 22:03:26 -08:00
|
|
|
|
{
|
|
|
|
|
|
key = ((Disk)this).MD5;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.MD5, DedupeType.None);
|
2017-02-27 22:03:26 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// If we've gotten here and we have a Rom, sort by CRC
|
|
|
|
|
|
else if (_itemType == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = ((Rom)this).CRC;
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.CRC, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2017-02-27 22:03:26 -08:00
|
|
|
|
|
2017-06-01 11:19:54 -07:00
|
|
|
|
// Otherwise, we use -1 as the key
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
key = "-1";
|
2017-08-29 11:46:01 -07:00
|
|
|
|
datdata.BucketBy(SortedBy.Size, DedupeType.None);
|
2017-06-01 11:19:54 -07:00
|
|
|
|
}
|
2016-10-06 11:42:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-27 22:10:24 -08:00
|
|
|
|
return key;
|
2016-09-22 20:30:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#endregion // Instance Methods
|
|
|
|
|
|
|
|
|
|
|
|
#region Static Methods
|
|
|
|
|
|
|
2017-03-18 00:04:59 -07:00
|
|
|
|
#region Sorting and Merging
|
2016-09-22 20:30:04 -07:00
|
|
|
|
|
2016-09-19 20:52:55 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Merge an arbitrary set of ROMs based on the supplied information
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="infiles">List of File objects representing the roms to be merged</param>
|
|
|
|
|
|
/// <returns>A List of RomData objects representing the merged roms</returns>
|
2017-03-01 21:26:27 -08:00
|
|
|
|
public static List<DatItem> Merge(List<DatItem> infiles)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Check for null or blank roms first
|
|
|
|
|
|
if (infiles == null || infiles.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new List<DatItem>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create output list
|
|
|
|
|
|
List<DatItem> outfiles = new List<DatItem>();
|
|
|
|
|
|
|
|
|
|
|
|
// Then deduplicate them by checking to see if data matches previous saved roms
|
|
|
|
|
|
foreach (DatItem file in infiles)
|
|
|
|
|
|
{
|
|
|
|
|
|
// If it's a nodump, add and skip
|
2016-09-21 15:45:40 -07:00
|
|
|
|
if (file.Type == ItemType.Rom && ((Rom)file).ItemStatus == ItemStatus.Nodump)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
outfiles.Add(file);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2016-09-21 15:45:40 -07:00
|
|
|
|
else if (file.Type == ItemType.Disk && ((Disk)file).ItemStatus == ItemStatus.Nodump)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
outfiles.Add(file);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If it's the first rom in the list, don't touch it
|
|
|
|
|
|
if (outfiles.Count != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Check if the rom is a duplicate
|
2016-10-05 20:33:02 -07:00
|
|
|
|
DupeType dupetype = 0x00;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
DatItem saveditem = new Rom();
|
|
|
|
|
|
int pos = -1;
|
|
|
|
|
|
for (int i = 0; i < outfiles.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
DatItem lastrom = outfiles[i];
|
|
|
|
|
|
|
|
|
|
|
|
// Get the duplicate status
|
2017-03-01 21:26:27 -08:00
|
|
|
|
dupetype = file.GetDuplicateStatus(lastrom);
|
2016-09-19 20:52:55 -07:00
|
|
|
|
|
|
|
|
|
|
// If it's a duplicate, skip adding it to the output but add any missing information
|
2016-10-05 20:33:02 -07:00
|
|
|
|
if (dupetype != 0x00)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
// If we don't have a rom or disk, then just skip adding
|
|
|
|
|
|
if (file.Type != ItemType.Rom && file.Type != ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
saveditem = lastrom;
|
|
|
|
|
|
pos = i;
|
|
|
|
|
|
|
|
|
|
|
|
// Roms have more infomration to save
|
|
|
|
|
|
if (file.Type == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
((Rom)saveditem).Size = ((Rom)saveditem).Size;
|
|
|
|
|
|
((Rom)saveditem).CRC = (String.IsNullOrEmpty(((Rom)saveditem).CRC) && !String.IsNullOrEmpty(((Rom)file).CRC)
|
|
|
|
|
|
? ((Rom)file).CRC
|
|
|
|
|
|
: ((Rom)saveditem).CRC);
|
|
|
|
|
|
((Rom)saveditem).MD5 = (String.IsNullOrEmpty(((Rom)saveditem).MD5) && !String.IsNullOrEmpty(((Rom)file).MD5)
|
|
|
|
|
|
? ((Rom)file).MD5
|
|
|
|
|
|
: ((Rom)saveditem).MD5);
|
|
|
|
|
|
((Rom)saveditem).SHA1 = (String.IsNullOrEmpty(((Rom)saveditem).SHA1) && !String.IsNullOrEmpty(((Rom)file).SHA1)
|
|
|
|
|
|
? ((Rom)file).SHA1
|
|
|
|
|
|
: ((Rom)saveditem).SHA1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
((Disk)saveditem).MD5 = (String.IsNullOrEmpty(((Disk)saveditem).MD5) && !String.IsNullOrEmpty(((Disk)file).MD5)
|
|
|
|
|
|
? ((Disk)file).MD5
|
|
|
|
|
|
: ((Disk)saveditem).MD5);
|
|
|
|
|
|
((Disk)saveditem).SHA1 = (String.IsNullOrEmpty(((Disk)saveditem).SHA1) && !String.IsNullOrEmpty(((Disk)file).SHA1)
|
|
|
|
|
|
? ((Disk)file).SHA1
|
|
|
|
|
|
: ((Disk)saveditem).SHA1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
saveditem.Dupe = dupetype;
|
|
|
|
|
|
|
|
|
|
|
|
// If the current system has a lower ID than the previous, set the system accordingly
|
|
|
|
|
|
if (file.SystemID < saveditem.SystemID)
|
|
|
|
|
|
{
|
|
|
|
|
|
saveditem.SystemID = file.SystemID;
|
|
|
|
|
|
saveditem.System = file.System;
|
2017-06-16 16:24:26 -07:00
|
|
|
|
saveditem.Machine = file.Machine;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
saveditem.Name = file.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the current source has a lower ID than the previous, set the source accordingly
|
|
|
|
|
|
if (file.SourceID < saveditem.SourceID)
|
|
|
|
|
|
{
|
|
|
|
|
|
saveditem.SourceID = file.SourceID;
|
|
|
|
|
|
saveditem.Source = file.Source;
|
2017-06-16 16:24:26 -07:00
|
|
|
|
saveditem.Machine = file.Machine;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
saveditem.Name = file.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If no duplicate is found, add it to the list
|
2016-10-05 20:33:02 -07:00
|
|
|
|
if (dupetype == 0x00)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
outfiles.Add(file);
|
|
|
|
|
|
}
|
|
|
|
|
|
// Otherwise, if a new rom information is found, add that
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
outfiles.RemoveAt(pos);
|
|
|
|
|
|
outfiles.Insert(pos, saveditem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
outfiles.Add(file);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Then return the result
|
|
|
|
|
|
return outfiles;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-02 17:27:29 -08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Resolve name duplicates in an arbitrary set of ROMs based on the supplied information
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="infiles">List of File objects representing the roms to be merged</param>
|
|
|
|
|
|
/// <returns>A List of RomData objects representing the renamed roms</returns>
|
2017-03-01 21:26:27 -08:00
|
|
|
|
public static List<DatItem> ResolveNames(List<DatItem> infiles)
|
2017-02-02 17:27:29 -08:00
|
|
|
|
{
|
|
|
|
|
|
// Create the output list
|
|
|
|
|
|
List<DatItem> output = new List<DatItem>();
|
|
|
|
|
|
|
|
|
|
|
|
// First we want to make sure the list is in alphabetical order
|
|
|
|
|
|
Sort(ref infiles, true);
|
|
|
|
|
|
|
|
|
|
|
|
// Now we want to loop through and check names
|
2017-02-02 23:20:42 -08:00
|
|
|
|
DatItem lastItem = null;
|
2017-02-02 17:47:55 -08:00
|
|
|
|
string lastrenamed = null;
|
|
|
|
|
|
int lastid = 0;
|
2017-02-02 17:27:29 -08:00
|
|
|
|
for (int i = 0; i < infiles.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
DatItem datItem = infiles[i];
|
|
|
|
|
|
|
2017-02-02 23:20:42 -08:00
|
|
|
|
// If we have the first item, we automatically add it
|
|
|
|
|
|
if (lastItem == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
output.Add(datItem);
|
|
|
|
|
|
lastItem = datItem;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the current item exactly matches the last item, then we don't add it
|
2017-03-01 21:26:27 -08:00
|
|
|
|
if ((datItem.GetDuplicateStatus(lastItem) & DupeType.All) != 0)
|
2017-02-02 23:20:42 -08:00
|
|
|
|
{
|
2017-08-26 14:11:10 -07:00
|
|
|
|
Globals.Logger.Verbose("Exact duplicate found for '{0}'", datItem.Name);
|
2017-02-02 23:20:42 -08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-02 17:27:29 -08:00
|
|
|
|
// If the current name matches the previous name, rename the current item
|
2017-02-02 23:20:42 -08:00
|
|
|
|
else if (datItem.Name == lastItem.Name)
|
2017-02-02 17:27:29 -08:00
|
|
|
|
{
|
2017-08-26 14:11:10 -07:00
|
|
|
|
Globals.Logger.Verbose("Name duplicate found for '{0}'", datItem.Name);
|
2017-02-02 23:20:42 -08:00
|
|
|
|
|
2017-02-02 17:27:29 -08:00
|
|
|
|
if (datItem.Type == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
Disk disk = (Disk)datItem;
|
2017-03-16 23:55:08 -07:00
|
|
|
|
disk.Name += "_" + (!String.IsNullOrEmpty(disk.MD5)
|
|
|
|
|
|
? disk.MD5
|
|
|
|
|
|
: !String.IsNullOrEmpty(disk.SHA1)
|
|
|
|
|
|
? disk.SHA1
|
|
|
|
|
|
: "1");
|
2017-02-02 17:27:29 -08:00
|
|
|
|
datItem = disk;
|
2017-02-27 21:54:34 -08:00
|
|
|
|
lastrenamed = lastrenamed ?? datItem.Name;
|
2017-02-02 17:27:29 -08:00
|
|
|
|
}
|
|
|
|
|
|
else if (datItem.Type == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
Rom rom = (Rom)datItem;
|
2017-03-16 23:55:08 -07:00
|
|
|
|
rom.Name += "_" + (!String.IsNullOrEmpty(rom.CRC)
|
|
|
|
|
|
? rom.CRC
|
|
|
|
|
|
: !String.IsNullOrEmpty(rom.MD5)
|
|
|
|
|
|
? rom.MD5
|
|
|
|
|
|
: !String.IsNullOrEmpty(rom.SHA1)
|
|
|
|
|
|
? rom.SHA1
|
|
|
|
|
|
: "1");
|
2017-02-02 17:27:29 -08:00
|
|
|
|
datItem = rom;
|
2017-02-27 21:54:34 -08:00
|
|
|
|
lastrenamed = lastrenamed ?? datItem.Name;
|
2017-02-02 17:27:29 -08:00
|
|
|
|
}
|
2017-02-02 17:47:55 -08:00
|
|
|
|
|
|
|
|
|
|
// If we have a conflict with the last renamed item, do the right thing
|
|
|
|
|
|
if (datItem.Name == lastrenamed)
|
2017-02-02 17:27:29 -08:00
|
|
|
|
{
|
2017-02-02 17:47:55 -08:00
|
|
|
|
lastrenamed = datItem.Name;
|
|
|
|
|
|
datItem.Name += (lastid == 0 ? "" : "_" + lastid);
|
2017-02-02 17:27:29 -08:00
|
|
|
|
lastid++;
|
|
|
|
|
|
}
|
2017-02-02 17:47:55 -08:00
|
|
|
|
// If we have no conflict, then we want to reset the lastrenamed and id
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
lastrenamed = null;
|
|
|
|
|
|
lastid = 0;
|
|
|
|
|
|
}
|
2017-02-02 17:27:29 -08:00
|
|
|
|
|
|
|
|
|
|
output.Add(datItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise, we say that we have a valid named file
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
output.Add(datItem);
|
2017-02-02 23:20:42 -08:00
|
|
|
|
lastItem = datItem;
|
2017-02-02 17:47:55 -08:00
|
|
|
|
lastrenamed = null;
|
|
|
|
|
|
lastid = 0;
|
2017-02-02 17:27:29 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-02 17:34:26 -07:00
|
|
|
|
// One last sort to make sure this is ordered
|
|
|
|
|
|
Sort(ref output, true);
|
|
|
|
|
|
|
2017-02-02 17:27:29 -08:00
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-19 20:52:55 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Sort a list of File objects by SystemID, SourceID, Game, and Name (in order)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="roms">List of File objects representing the roms to be sorted</param>
|
|
|
|
|
|
/// <param name="norename">True if files are not renamed, false otherwise</param>
|
|
|
|
|
|
/// <returns>True if it sorted correctly, false otherwise</returns>
|
|
|
|
|
|
public static bool Sort(ref List<DatItem> roms, bool norename)
|
|
|
|
|
|
{
|
2016-10-24 21:32:26 -07:00
|
|
|
|
roms.Sort(delegate (DatItem x, DatItem y)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-24 21:32:26 -07:00
|
|
|
|
try
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
2016-10-28 12:59:52 -07:00
|
|
|
|
NaturalComparer nc = new NaturalComparer();
|
2016-09-19 20:52:55 -07:00
|
|
|
|
if (x.SystemID == y.SystemID)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (x.SourceID == y.SourceID)
|
|
|
|
|
|
{
|
2016-10-24 21:32:26 -07:00
|
|
|
|
if (x.Machine != null && y.Machine != null && x.Machine.Name == y.Machine.Name)
|
2016-09-19 20:52:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
|
|
|
|
|
|
{
|
2016-10-05 10:14:49 -07:00
|
|
|
|
if (Path.GetDirectoryName(Style.RemovePathUnsafeCharacters(x.Name)) == Path.GetDirectoryName(Style.RemovePathUnsafeCharacters(y.Name)))
|
2016-09-26 15:49:46 -07:00
|
|
|
|
{
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return nc.Compare(Path.GetFileName(Style.RemovePathUnsafeCharacters(x.Name)), Path.GetFileName(Style.RemovePathUnsafeCharacters(y.Name)));
|
2016-09-26 15:49:46 -07:00
|
|
|
|
}
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return nc.Compare(Path.GetDirectoryName(Style.RemovePathUnsafeCharacters(x.Name)), Path.GetDirectoryName(Style.RemovePathUnsafeCharacters(y.Name)));
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
else if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type != ItemType.Rom && y.Type != ItemType.Disk))
|
|
|
|
|
|
{
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((x.Type != ItemType.Rom && x.Type != ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
|
|
|
|
|
|
{
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-26 15:49:46 -07:00
|
|
|
|
if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name))
|
|
|
|
|
|
{
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return nc.Compare(Path.GetFileName(x.Name), Path.GetFileName(y.Name));
|
2016-09-26 15:49:46 -07:00
|
|
|
|
}
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return nc.Compare(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name));
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return nc.Compare(x.Machine.Name, y.Machine.Name);
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return (norename ? nc.Compare(x.Machine.Name, y.Machine.Name) : x.SourceID - y.SourceID);
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
2016-10-28 12:59:52 -07:00
|
|
|
|
return (norename ? nc.Compare(x.Machine.Name, y.Machine.Name) : x.SystemID - y.SystemID);
|
2016-10-24 21:32:26 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Absorb the error
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2016-09-22 20:30:04 -07:00
|
|
|
|
|
|
|
|
|
|
#endregion // Static Methods
|
2016-09-19 20:52:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|