Skip to content

Commit

Permalink
read dictionary & extract from stuff files
Browse files Browse the repository at this point in the history
  • Loading branch information
handsomematt committed Jan 20, 2017
1 parent ce7ad5f commit 665acf9
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 9 deletions.
8 changes: 7 additions & 1 deletion BW2Unstuff/BW2Unstuff.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<ProjectGuid>{1715CCEB-EAE6-44CF-BC9F-01E564E969DF}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>BW2Unstuff</RootNamespace>
<AssemblyName>BW2Unstuff</AssemblyName>
<AssemblyName>unstuff</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
Expand All @@ -31,6 +31,12 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>BW2Unstuff.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down
107 changes: 102 additions & 5 deletions BW2Unstuff/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;

namespace BW2Unstuff
{
[StructLayout(LayoutKind.Explicit)]
struct FileDictionaryEntry
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string FileName;
[FieldOffset(256)]
public UInt32 FilePosition;
[FieldOffset(260)]
public UInt32 FileLength;
[FieldOffset(264)]
public UInt32 Unknown;
}

class Program
{
static void Main(string[] args)
private const string UsageHelpString = "Usage: {0} everything.stuff (output_directory)";

static int Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine(UsageHelpString, Path.GetFileNameWithoutExtension(Environment.GetCommandLineA‌​rgs()[0]));
return 1;
}

string inputFileName = args[0];
string outputDirectory = (args.Length > 1) ? args[1] : Path.GetFileNameWithoutExtension(inputFileName);

if (!File.Exists(inputFileName))
{
Console.WriteLine("Couldn't find specified file: {0}", inputFileName);
return 1;
}

// make sure our output directory exists
Directory.CreateDirectory(outputDirectory);

using (BinaryReader fileReader = new BinaryReader(File.OpenRead(inputFileName)))
{
var fileLength = fileReader.BaseStream.Length;

fileReader.BaseStream.Seek(-4L, SeekOrigin.End);
var contentLength = fileReader.ReadUInt32();

Console.WriteLine("Content Length: {0} bytes", contentLength);

// todo: this error checking isn't perfect
if (contentLength < 4 || contentLength > fileLength - 32)
{
Console.WriteLine("Error: Invalid TOC");
return 1;
}

var dictionaryLength = (fileLength - contentLength - 4) / Marshal.SizeOf(typeof(FileDictionaryEntry));

Console.WriteLine("{0} file dictionary entries", dictionaryLength);
Console.Write("Reading file dictionary... ");

var fileDictionary = new FileDictionaryEntry[dictionaryLength];
for (int i = 0; i < dictionaryLength; i++)
fileDictionary[i] = ByteToType<FileDictionaryEntry>(fileReader);

Console.WriteLine("Done!");
Console.WriteLine("Extracting files...");

for (int i = 0; i < dictionaryLength; i++)
ExtractFileEntry(fileDictionary[i], fileReader, outputDirectory);

Console.WriteLine("Done!");
}

return 0;
}

public static void ExtractFileEntry(FileDictionaryEntry entry, BinaryReader fileReader, string outputDir)
{
Console.WriteLine(entry.FileName);

string fullFilePath = outputDir + Path.DirectorySeparatorChar + entry.FileName;
string fullDirPath = Path.GetDirectoryName(fullFilePath);

// Make sure the directory exists before we try writing to it.
Directory.CreateDirectory(fullDirPath);

fileReader.BaseStream.Seek(entry.FilePosition, SeekOrigin.Begin);
var fileContents = fileReader.ReadBytes((int)entry.FileLength);

FileStream outputFile = File.OpenWrite(fullFilePath);
outputFile.Write(fileContents, 0, fileContents.Length);
outputFile.Close();
}

// http://stackoverflow.com/a/4074557
public static T ByteToType<T>(BinaryReader reader)
{
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));

GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();

return theStructure;
}
}
}
6 changes: 3 additions & 3 deletions BW2Unstuff/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BW2Unstuff")]
[assembly: AssemblyTitle("unstuff")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BW2Unstuff")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyProduct("unstuff")]
[assembly: AssemblyCopyright("Copyright © Matt Stevens 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand Down

0 comments on commit 665acf9

Please sign in to comment.