Skip to content

Commit

Permalink
Fix loading from older SDKs & use faster CAB search code
Browse files Browse the repository at this point in the history
  • Loading branch information
emoose committed Feb 1, 2020
1 parent b7dc6c2 commit 9bcf35f
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 52 deletions.
5 changes: 2 additions & 3 deletions XbRecUnpack/CabFile.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;

// TODO: this doesn't support cabs that use multiple CFFOLDERS (if any do)
// Also only supports LZX compression, there's code to support non-compressed data too but it's untested
namespace XbRecUnpack
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
Expand Down
3 changes: 0 additions & 3 deletions XbRecUnpack/LzxDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace XbRecUnpack
Expand Down
2 changes: 0 additions & 2 deletions XbRecUnpack/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using DiscUtils.Iso9660;
Expand Down
1 change: 0 additions & 1 deletion XbRecUnpack/RecoveryControlFile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace XbRecUnpack
Expand Down
103 changes: 66 additions & 37 deletions XbRecUnpack/RemoteRecovery.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace XbRecUnpack
Expand Down Expand Up @@ -60,17 +58,24 @@ public bool Read()

Console.WriteLine("Scanning EXE...");
cabHeaderPos = new List<long>();
while(reader.BaseStream.Position + 8 < reader.BaseStream.Length)

// Track position/length ourselves instead of needing to call stream accessors
long position = reader.BaseStream.Position;
long length = reader.BaseStream.Length;

// Fast pattern search via sliding-window, kinda
// From https://codereview.stackexchange.com/questions/202235/finding-specific-small-byte-arrays-in-large-binary-files
ulong pattern = ((ulong)0x4643534D).EndianSwap();
ulong view = 0;
long viewed = 0;

while (position + 8 < length)
{
var currentPos = reader.BaseStream.Position;
if (reader.ReadUInt64() == 0x4643534D)
{
cabHeaderPos.Add(currentPos);
var size = reader.ReadUInt32();
reader.BaseStream.Position += (size - 0xC);
}
else
reader.BaseStream.Position = currentPos + 1;
view = (view << 8) | reader.ReadByte() ; // shift-in next byte
position++;
viewed++;
if (view == pattern && viewed >= 8) // make sure we already got at least 4 bytes
cabHeaderPos.Add(position - 8);
}

if (cabHeaderPos.Count < 2)
Expand All @@ -79,36 +84,50 @@ public bool Read()
return false;
}

string[] csv = null;
// Read the second cab in the file, contains some meta info about the other ones
reader.BaseStream.Position = cabHeaderPos[1];
var metaCab = new CabFile(reader.BaseStream);
if (!metaCab.Read())
while (cabHeaderPos.Count > 1)
{
Console.WriteLine("Error: failed to read meta-cab!");
return false;
}
reader.BaseStream.Position = cabHeaderPos[1];

// Remove the meta cab from cab header list...
cabHeaderPos.RemoveAt(1);
// Remove the meta cab from cab header list...
cabHeaderPos.RemoveAt(1);

// Read the manifest file...
var manifest = new CFFILE();
if (!metaCab.GetEntry("manifest.csv", ref manifest, false))
{
Console.WriteLine("Error: failed to find manifest.csv inside meta-cab!");
return false;
}
// Try reading metacab
var metaCab = new CabFile(reader.BaseStream);
if (!metaCab.Read())
continue;

var manifestStream = metaCab.OpenFile(manifest);
if (manifestStream == null)
return false;
// Read the manifest file...
var manifest = new CFFILE();
if (!metaCab.GetEntry("manifest.csv", ref manifest, false))
continue;

Stream manifestStream = null;
try
{
manifestStream = metaCab.OpenFile(manifest);
if (manifestStream == null)
continue;
}
catch
{
continue;
}

using (var reader2 = new BinaryReader(manifestStream))
{
byte[] data = reader2.ReadBytes((int)reader2.BaseStream.Length);
var str = Encoding.ASCII.GetString(data);
csv = str.Replace("\r\n", "\n").Split(new char[] { '\n' });
}
break;
}

string[] csv;
using (var reader2 = new BinaryReader(manifestStream))
if(csv == null)
{
byte[] data = reader2.ReadBytes((int)reader2.BaseStream.Length);
var str = Encoding.ASCII.GetString(data);
csv = str.Replace("\r\n", "\n").Split(new char[]{ '\n' });
Console.WriteLine("Error: failed to read manifest.csv from meta-cab section!");
return false;
}

Variants = new List<string>();
Expand All @@ -118,10 +137,14 @@ public bool Read()
if (string.IsNullOrEmpty(line))
continue;

var parts = line.Split(new char[] { ',' });
if (parts.Length < 6)
var parts = new List<string>(line.Split(new char[] { ',' }));
if (parts.Count < 6)
continue;

// Older SDKs don't have a variant section, so we'll insert one
if (parts[1] == "file" || parts[1] == "copy" || parts[1] == "sharedfile" || parts[1] == "backupsharedfile" || parts[1] == "singlefile")
parts.Insert(1, "");

if (parts[2] != "file" && parts[2] != "copy" && parts[2] != "sharedfile" && parts[2] != "backupsharedfile" && parts[2] != "singlefile")
continue;

Expand Down Expand Up @@ -275,6 +298,12 @@ public bool Extract(string destDirPath, bool listOnly = false)
totalIndex++;
}

if (mainCab.Entries.Count > cabIndex)
{
var diff = mainCab.Entries.Count - cabIndex;
Console.WriteLine($"Note: CAB contains {diff} more file{(diff == 1 ? "" : "s")} than were inside the manifest!");
}

return true;
}
}
Expand Down
6 changes: 6 additions & 0 deletions XbRecUnpack/XbRecUnpack.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
<TargetFrameworks>net472</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Discutils" Version="0.11.0.2" />
</ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions XbRecUnpack/XboxGDFImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;

// NOTE: Only tested with Xbox OG recovery ISOs, games & X360 ISOs likely won't work well with it
namespace XbRecUnpack
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
Expand Down Expand Up @@ -237,5 +237,4 @@ public override void Close()
source.Close();
}
}

}
4 changes: 0 additions & 4 deletions XbRecUnpack/XboxRom.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
namespace XbRecUnpack
Expand Down

0 comments on commit 9bcf35f

Please sign in to comment.