wow-cdbc 0.6.4

Parser for World of Warcraft DBC (client database) files with serialization support
Documentation
use clap::Parser;
use std::path::PathBuf;
use wow_cdbc::DbcParser;

#[derive(Parser)]
#[command(name = "dbc_schema_discovery")]
#[command(about = "Discover the schema of a DBC file through analysis")]
struct Cli {
    /// The DBC file to analyze
    file: PathBuf,

    /// Output schema file (YAML format)
    #[arg(short, long)]
    output: Option<PathBuf>,

    /// Number of records to sample (default: all)
    #[arg(short, long)]
    sample_size: Option<usize>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::init();

    let cli = Cli::parse();

    println!("Analyzing DBC file: {}", cli.file.display());

    // Read and parse the DBC file
    let data = std::fs::read(&cli.file)?;
    let parser = DbcParser::parse_bytes(&data)?;
    let header = parser.header();

    println!("\nDBC Header Information:");
    println!("======================");
    println!("Magic: {}", String::from_utf8_lossy(&header.magic));
    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);

    // For now, we'll create a simple schema based on field count
    // In a real implementation, we would analyze the data to determine field types
    println!("\nSuggested Schema:");
    println!("================");

    let mut schema = serde_yaml_ng::Mapping::new();
    let name = cli
        .file
        .file_stem()
        .and_then(|s| s.to_str())
        .unwrap_or("Unknown")
        .to_string();

    schema.insert(
        serde_yaml_ng::Value::String("name".to_string()),
        serde_yaml_ng::Value::String(name.clone()),
    );

    let mut fields = serde_yaml_ng::Sequence::new();

    // Create fields based on field count
    // This is a simplified approach - real schema discovery would analyze the data
    for i in 0..header.field_count {
        let mut field = serde_yaml_ng::Mapping::new();
        field.insert(
            serde_yaml_ng::Value::String("name".to_string()),
            serde_yaml_ng::Value::String(if i == 0 {
                "ID".to_string()
            } else {
                format!("Field{i}")
            }),
        );
        field.insert(
            serde_yaml_ng::Value::String("type".to_string()),
            serde_yaml_ng::Value::String("UInt32".to_string()),
        );

        if i == 0 {
            field.insert(
                serde_yaml_ng::Value::String("is_key".to_string()),
                serde_yaml_ng::Value::Bool(true),
            );
        }

        fields.push(serde_yaml_ng::Value::Mapping(field));
    }

    schema.insert(
        serde_yaml_ng::Value::String("fields".to_string()),
        serde_yaml_ng::Value::Sequence(fields),
    );

    // Save to YAML if output path provided
    if let Some(output_path) = cli.output {
        let yaml = serde_yaml_ng::to_string(&serde_yaml_ng::Value::Mapping(schema))?;
        std::fs::write(&output_path, yaml)?;
        println!("\nSchema saved to: {}", output_path.display());
    } else {
        // Print schema to stdout
        let yaml = serde_yaml_ng::to_string(&serde_yaml_ng::Value::Mapping(schema))?;
        println!("\n{yaml}");
    }

    println!("\nNote: This is a basic schema. For accurate field type detection,");
    println!("manual analysis or DBD definition files are recommended.");
    println!("DBD definitions can be found at: https://github.com/wowdev/WoWDBDefs");

    Ok(())
}