use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::time::Instant;
use wow_cdbc::{DbcParser, FieldType, LazyDbcParser, Schema, SchemaField, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("\n=== WoW DBC Parser - Core Features Demo ===");
println!("This example demonstrates the core features of the DBC parser\n");
parse_with_code_schema()?;
parse_with_lazy_loading()?;
parse_without_schema()?;
Ok(())
}
fn parse_with_code_schema() -> Result<(), Box<dyn std::error::Error>> {
println!("1. Parsing with code-defined schema");
println!(" --------------------------------");
let dbc_path = Path::new("test-data/1.12.1/DBFilesClient/ItemClass.dbc");
if !dbc_path.exists() {
println!(" Skipping: test data file not found");
println!(" Run this example from the project root directory\n");
return Ok(());
}
let file = File::open(dbc_path)?;
let mut reader = BufReader::new(file);
let parser = DbcParser::parse(&mut reader)?;
println!(" Record count: {}", parser.header().record_count);
println!(" Field count: {}", parser.header().field_count);
let mut schema = Schema::new("ItemClass");
schema.add_field(SchemaField::new("ClassID", FieldType::Int32));
schema.add_field(SchemaField::new("SubClassID", FieldType::Int32));
schema.add_field(SchemaField::new("Flags", FieldType::Int32));
schema.add_field(SchemaField::new("ClassName", FieldType::String));
schema.set_key_field("ClassID");
let parser = parser.with_schema(schema)?;
let record_set = parser.parse_records()?;
println!(" Parsed {} records", record_set.len());
if let Some(record) = record_set.get_record(0)
&& let Some(Value::Int32(id)) = record.get_value_by_name("ClassID")
{
println!(" First record ClassID: {id}");
}
if let Some(record) = record_set.get_record_by_key(2)
&& let Some(Value::StringRef(name_ref)) = record.get_value_by_name("ClassName")
{
let name = record_set.get_string(*name_ref)?;
println!(" Class 2 name: {name}");
}
println!(" All item classes:");
for i in 0..record_set.len() {
if let Some(record) = record_set.get_record(i)
&& let (Some(Value::Int32(id)), Some(Value::StringRef(name_ref))) = (
record.get_value_by_name("ClassID"),
record.get_value_by_name("ClassName"),
)
{
let name = record_set.get_string(*name_ref)?;
println!(" - Class {id}: {name}");
}
}
println!();
Ok(())
}
fn parse_with_lazy_loading() -> Result<(), Box<dyn std::error::Error>> {
println!("2. Lazy loading example");
println!(" -------------------");
let dbc_path = Path::new("test-data/1.12.1/DBFilesClient/Talent.dbc");
if !dbc_path.exists() {
println!(" Skipping: test data file not found\n");
return Ok(());
}
let file = File::open(dbc_path)?;
let mut reader = BufReader::new(file);
let parser = DbcParser::parse(&mut reader)?;
let mut schema = Schema::new("Talent");
schema.add_field(SchemaField::new("ID", FieldType::UInt32));
schema.add_field(SchemaField::new("TabID", FieldType::UInt32));
schema.add_field(SchemaField::new("Row", FieldType::UInt32));
schema.add_field(SchemaField::new("Column", FieldType::UInt32));
let field_count = parser.header().field_count as usize;
for i in 4..field_count {
schema.add_field(SchemaField::new(format!("Field{i}"), FieldType::Int32));
}
schema.set_key_field("ID");
let parser = parser.with_schema(schema)?;
let record_set = parser.parse_records()?;
let string_block = std::sync::Arc::new(record_set.string_block().clone());
let start = Instant::now();
let lazy_parser = LazyDbcParser::new(
parser.data(),
parser.header(),
parser.schema(),
string_block,
);
println!(" Processing records lazily...");
let mut count = 0;
for record in lazy_parser.record_iterator() {
let record = record?;
count += 1;
if count <= 3
&& let Some(Value::UInt32(id)) = record.get_value_by_name("ID")
{
println!(" - Record {count}: ID = {id}");
}
}
let elapsed = start.elapsed();
println!(" Processed {count} records in {elapsed:?}");
println!(" Direct access to specific records:");
let indices = vec![0, 10, 20, 30];
for idx in indices {
if idx < parser.header().record_count {
let record = lazy_parser.get_record(idx)?;
if let Some(Value::UInt32(id)) = record.get_value_by_name("ID") {
println!(" - Record {idx}: ID = {id}");
}
}
}
println!();
Ok(())
}
fn parse_without_schema() -> Result<(), Box<dyn std::error::Error>> {
println!("3. Parsing without schema");
println!(" ----------------------");
let dbc_path = Path::new("test-data/1.12.1/DBFilesClient/StableSlotPrices.dbc");
if !dbc_path.exists() {
println!(" Skipping: test data file not found\n");
return Ok(());
}
let file = File::open(dbc_path)?;
let mut reader = BufReader::new(file);
let parser = DbcParser::parse(&mut reader)?;
let header = parser.header();
println!(" File information:");
println!(" - Records: {}", header.record_count);
println!(" - Fields: {}", header.field_count);
println!(" - Record size: {} bytes", header.record_size);
println!(" - String block size: {} bytes", header.string_block_size);
let record_set = parser.parse_records()?;
println!(" Parsed {} records without schema", record_set.len());
println!(" Raw data from first 3 records:");
for i in 0..3.min(record_set.len()) {
if let Some(record) = record_set.get_record(i) {
print!(" Record {i}: ");
for (j, value) in record.values().iter().enumerate() {
if j > 0 {
print!(", ");
}
print!("{value}");
}
println!();
}
}
println!();
Ok(())
}