Created
July 4, 2010 09:38
-
-
Save vermie/463304 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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