Skip to content

Instantly share code, notes, and snippets.

@vermie
Created July 4, 2010 09:38
Show Gist options
  • Save vermie/463304 to your computer and use it in GitHub Desktop.
Save vermie/463304 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Text;
namespace wowtest
{
/// <summary>
/// Stores the fields of a dbc file's record
/// </summary>
class DBCRecord
{
/// <summary>
/// The value of the fields
/// <para>Ints are boxed, which greatly impacts performance and adds memory overhead</para>
/// </summary>
public object[] Fields
{
get;
private set;
}
/// <summary>
/// Reads a records from the specified stream
/// </summary>
/// <param name="fieldCount">The number of fields to read</param>
/// <param name="input">The stream to read from</param>
public DBCRecord(int fieldCount, BinaryReader input)
{
this.Fields = new object[fieldCount];
for (int i = 0; i < fieldCount; i++)
this.Fields[i] = input.ReadInt32(); // boxing is slow
}
}
/// <summary>
/// Parses and stores records in a dbc file.
/// </summary>
class DBCFile
{
/// <summary>
/// Stores the records.
/// </summary>
private DBCRecord[] records;
/// <summary>
/// Stores all string data
/// </summary>
private char[] stringData;
/// <summary>
/// Reads and parses a dbc file
/// </summary>
/// <param name="path">The path the the dbc file</param>
public DBCFile(string path)
{
DateTime start = DateTime.Now;
// Read dbc as binary file
BinaryReader input = new BinaryReader(new FileStream(path, FileMode.Open), Encoding.UTF8);
// read 'WDBC' string
if (new string(input.ReadChars(4)) != "WDBC")
throw new Exception(string.Format("{0} is not a DBC file.", path));
// get record count
this.records = new DBCRecord[input.ReadInt32()];
// get field count
int fieldCount = input.ReadInt32();
// get record size
/*int recordSize = */input.ReadInt32();
// get string size
int stringSize = input.ReadInt32();
// load records
for (int i = 0; i < this.records.Length; i++)
records[i] = new DBCRecord(fieldCount, input);
// read strings
this.stringData = input.ReadChars(stringSize);
// find and store strings
foreach (DBCRecord record in this.records)
{
for(int i = 0; i < fieldCount; i++)
if(isString(record, i))
record.Fields[i] = getString((int)record.Fields[i]);
}
this.stringData = null;
// print records to tab-delimited file
StreamWriter output = new StreamWriter(new FileStream(path + ".txt", FileMode.OpenOrCreate));
foreach (DBCRecord record in this.records)
{
foreach (object field in record.Fields)
output.Write(string.Format("{0}\t", field));
output.WriteLine();
}
Console.WriteLine("Took {0:F0} seconds to process {1} records", (DateTime.Now - start).TotalSeconds, this.records.Length);
}
/// <summary>
/// Determines whether the specified field holds a string reference
/// </summary>
/// <param name="record">The record to check</param>
/// <param name="fieldIndex">The field to check</param>
/// <returns>True if the value is a string reference</returns>
private bool isString(DBCRecord record, int fieldIndex)
{
int stringIndex = (int)record.Fields[fieldIndex]; // unboxing is slow
// check stringdata bounds
if (stringIndex < 0 || stringIndex >= this.stringData.Length)
return false;
// each string in stringdata has a null character in front of them
if (stringIndex != 0 && this.stringData[stringIndex - 1] != '\0')
return false;
// string references in DBCs are followed by 15 fields with 0, then 1 field with 16712190
if (fieldIndex + 16 >= record.Fields.Length)
return false;
int? value;
for (int i = 1; i < 16; i++)
{
value = record.Fields[fieldIndex + i] as int?;
if (value == null || value != 0)
return false;
}
value = record.Fields[fieldIndex + 16] as int?;
if (value == null || value != 16712190)
return false;
// if we made it this far, the field holds a string reference
return true;
}
/// <summary>
/// Get the string at the referenced location
/// </summary>
/// <param name="index">The index in the string data</param>
/// <returns>The string at the specified index</returns>
private string getString(int index)
{
if (index == 0)
return "";
StringBuilder builder = new StringBuilder();
char c;
// append characters until we reach a null character
while ((c = this.stringData[index++]) != '\0')
builder.Append(c);
return builder.ToString();
}
static void Main(string[] args)
{
new DBCFile(@"C:\wowemu\mangos\dbc\Spell.dbc");
Console.WriteLine("\nComplete, press any key...");
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment