diff --git a/Xbox/DMI.cs b/Xbox/DMI.cs
index c1e87e77c..5a41a47bc 100644
--- a/Xbox/DMI.cs
+++ b/Xbox/DMI.cs
@@ -44,8 +44,31 @@ namespace DiscImageChef.Decoders.Xbox
if(dmi.Length != 2052)
return false;
- // TODO: Need to implement it
- return false;
+ // Version is 1
+ if(BitConverter.ToUInt32(dmi, 4) != 1)
+ return false;
+
+ // Catalogue number is two letters, five numbers, one letter
+ for(int i = 12; i < 14; i++)
+ {
+ if(dmi[i] < 0x41 || dmi[i] > 0x5A)
+ return false;
+ }
+ for(int i = 14; i < 19; i++)
+ {
+ if(dmi[i] < 0x30 || dmi[i] > 0x39)
+ return false;
+ }
+ if(dmi[19] < 0x41 || dmi[19] > 0x5A)
+ return false;
+
+ long timestamp = BitConverter.ToInt64(dmi, 20);
+
+ // Game cannot exist before the Xbox
+ if(timestamp < 0x1BD164833DFC000)
+ return false;
+
+ return true;
}
public static bool IsXbox360(byte[] dmi)
@@ -61,6 +84,43 @@ namespace DiscImageChef.Decoders.Xbox
return signature == 0x584F4258;
}
+ public struct XboxDMI
+ {
+ ///
+ /// Bytes 0 to 1
+ /// Data length
+ ///
+ public ushort DataLength;
+ ///
+ /// Byte 2
+ /// Reserved
+ ///
+ public byte Reserved1;
+ ///
+ /// Byte 3
+ /// Reserved
+ ///
+ public byte Reserved2;
+
+ ///
+ /// Bytes 4 to 7
+ /// 0x01 in XGD
+ ///
+ public uint Version;
+
+ ///
+ /// Bytes 12 to 16
+ /// Catalogue number in XX-XXXXX-X
+ ///
+ public string CatalogNumber;
+
+ ///
+ /// Bytes 20 to 27
+ /// DMI timestamp
+ ///
+ public long Timestamp;
+ }
+
public struct Xbox360DMI
{
///
@@ -104,6 +164,27 @@ namespace DiscImageChef.Decoders.Xbox
public string CatalogNumber;
}
+ public static XboxDMI? DecodeXbox(byte[] response)
+ {
+ bool isXbox = IsXbox(response);
+ if(!isXbox)
+ return null;
+
+ XboxDMI dmi = new XboxDMI();
+
+ dmi.DataLength = (ushort)((response[0] << 8) + response[1]);
+ dmi.Reserved1 = response[2];
+ dmi.Reserved2 = response[3];
+
+ dmi.Version = BitConverter.ToUInt32(response, 4);
+ dmi.Timestamp = BitConverter.ToInt64(response, 20);
+ byte[] tmp = new byte[8];
+ Array.Copy(response, 12, tmp, 0, 8);
+ dmi.CatalogNumber = StringHandlers.CToString(tmp);
+
+ return dmi;
+ }
+
public static Xbox360DMI? DecodeXbox360(byte[] response)
{
bool isX360 = IsXbox360(response);
@@ -130,6 +211,29 @@ namespace DiscImageChef.Decoders.Xbox
return dmi;
}
+ public static string PrettifyXbox(XboxDMI? dmi)
+ {
+ if(dmi == null)
+ return null;
+
+ XboxDMI decoded = dmi.Value;
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append("Catalogue number: ");
+ for(int i = 0; i < 2; i++)
+ sb.AppendFormat("{0}", decoded.CatalogNumber[i]);
+ sb.Append("-");
+ for(int i = 2; i < 7; i++)
+ sb.AppendFormat("{0}", decoded.CatalogNumber[i]);
+ sb.Append("-");
+ sb.AppendFormat("{0}", decoded.CatalogNumber[7]);
+ sb.AppendLine();
+
+ sb.AppendFormat("Timestamp: {0}", DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine();
+
+ return sb.ToString();
+ }
+
public static string PrettifyXbox360(Xbox360DMI? dmi)
{
if(dmi == null)
@@ -188,6 +292,11 @@ namespace DiscImageChef.Decoders.Xbox
return sb.ToString();
}
+ public static string PrettifyXbox(byte[] response)
+ {
+ return PrettifyXbox(DecodeXbox(response));
+ }
+
public static string PrettifyXbox360(byte[] response)
{
return PrettifyXbox360(DecodeXbox360(response));