blend_info 0.2.9

Print some information about a Blender scene file
Documentation
use std::collections::HashMap;
use std::mem;
use structopt::StructOpt;
// blend_info
use blend_info::{
    calc_mem_tlen, get_char, get_float, get_float2, get_int, get_pointer, get_short, print_pointer,
    read_dna, use_dna, DnaStrC,
};

/// Print some information about a Blender scene file.
#[derive(StructOpt)]
struct Cli {
    /// The path to the file to read
    #[structopt(parse(from_os_str))]
    path: std::path::PathBuf,
    /// Print information about DNA of Blender
    #[structopt(long = "dna")]
    dna: bool,
    /// Print code (e.g. OB, CA, LA, MA, DATA) and pointers
    #[structopt(long = "pointers")]
    pointers: bool,
    /// Print information about a particular struct
    #[structopt(short = "n", long = "struct_name")]
    struct_name: Option<String>,
}

fn main() -> std::io::Result<()> {
    let args = Cli::from_args();
    let print_dna: bool = args.dna;
    let print_pointers: bool = args.pointers;
    let struct_name_opt: Option<String> = args.struct_name;
    // read DNA
    let mut dna_types_hm: HashMap<String, u16> = HashMap::new();
    let mut dna_structs_hm: HashMap<String, DnaStrC> = HashMap::new();
    let mut dna_pointers_hm: HashMap<usize, usize> = HashMap::new();
    let mut dna_2_type_id: Vec<u16> = Vec::new();
    let mut types: Vec<String> = Vec::new();
    let mut num_bytes_read: usize = 0;
    read_dna(
        print_dna,
        print_pointers,
        &args.path,
        &mut dna_types_hm,
        &mut dna_structs_hm,
        &mut dna_pointers_hm,
        &mut dna_2_type_id,
        &mut types,
        &mut num_bytes_read,
    )?;
    if num_bytes_read > 0 {
        // use DNA for something, e.g. find out about cameras
        if let Some(struct_name) = struct_name_opt {
            if struct_name.contains(".") {
                let mut names: Vec<String> =
                    struct_name.split(".").map(|s| s.to_string()).collect();
                let mut names2 = names.split_off(1);
                let mut bytes_read: Vec<u8> = Vec::with_capacity(num_bytes_read);
                let mut structs_read: Vec<String> = Vec::with_capacity(names.len());
                let mut data_read: Vec<u32> = Vec::with_capacity(names.len());
                let mut pointers_read: Vec<(usize, u32)> = Vec::with_capacity(names.len());
                use_dna(
                    print_dna,
                    &args.path,
                    &dna_types_hm,
                    &dna_structs_hm,
                    &names,
                    &dna_2_type_id,
                    &types,
                    &mut bytes_read,
                    &mut structs_read,
                    &mut data_read,
                    &mut pointers_read,
                )?;
                let names3 = names2.split_off(1);
                let mut byte_index: usize = 0;
                for _struct_read in structs_read {
                    if let Some(struct_found) = dna_structs_hm.get(&names[0]) {
                        for member in &struct_found.members {
                            if member.mem_name == names2[0] {
                                // matches struct_name.mem_name
                                if let Some(struct_found2) = dna_structs_hm.get(&member.mem_type) {
                                    // member is struct
                                    if names3.len() > 0 {
                                        // there is a second '.'
                                        for member2 in &struct_found2.members {
                                            if let Some(type_found2) =
                                                dna_types_hm.get(&member2.mem_type)
                                            {
                                                let mem_tlen2: u16 =
                                                    calc_mem_tlen(member2, *type_found2);
                                                if member2.mem_name.contains(&names3[0]) {
                                                    match member2.mem_type.as_str() {
                                                        "char" => {
                                                            let mut id = String::with_capacity(
                                                                mem_tlen2 as usize,
                                                            );
                                                            for i in 0..mem_tlen2 as usize {
                                                                if bytes_read[byte_index + i] == 0 {
                                                                    break;
                                                                }
                                                                id.push(
                                                                    bytes_read[byte_index + i]
                                                                        as char,
                                                                );
                                                            }
                                                            println!("{} = {:?}", struct_name, id);
                                                        }
                                                        "void" => {
                                                            // check first char for '*' (pointer)
                                                            let mut chars = names3[0].chars();
                                                            if let Some(c) = chars.next() {
                                                                if c == '*' {
                                                                    let some_pointer: usize =
                                                                        get_pointer(
                                                                            member2,
                                                                            &bytes_read,
                                                                            byte_index,
                                                                        );
                                                                    print_pointer(
                                                                        some_pointer,
                                                                        &struct_name,
                                                                        &dna_pointers_hm,
                                                                    );
                                                                }
                                                            }
                                                        }
                                                        _ => {
                                                            println!("TODO: {:?}", names2[0]);
                                                        }
                                                    }
                                                }
                                                byte_index += mem_tlen2 as usize;
                                            }
                                        }
                                    } else {
                                        // there is *not* a second '.'

                                        // check first char for '*' (pointer)
                                        let mut chars = member.mem_name.chars();
                                        if let Some(c) = chars.next() {
                                            if c == '*' {
                                                let some_pointer: usize =
                                                    get_pointer(member, &bytes_read, byte_index);
                                                print_pointer(
                                                    some_pointer,
                                                    &struct_name,
                                                    &dna_pointers_hm,
                                                );
                                            }
                                        }
                                        // find mem_type in dna_types.names
                                        if let Some(type_found) = dna_types_hm.get(&member.mem_type)
                                        {
                                            let mem_tlen: u16 = calc_mem_tlen(member, *type_found);
                                            byte_index += mem_tlen as usize;
                                        }
                                    }
                                } else {
                                    // member is *not* a struct

                                    // check first char for '*' (pointer)
                                    let mut chars = member.mem_name.chars();
                                    if let Some(c) = chars.next() {
                                        if c == '*' {
                                            let some_pointer: usize =
                                                get_pointer(member, &bytes_read, byte_index);
                                            print_pointer(
                                                some_pointer,
                                                &struct_name,
                                                &dna_pointers_hm,
                                            );
                                        } else {
                                            // some basic type?
                                            match member.mem_type.as_str() {
                                                "char" => {
                                                    if let Some(type_found) =
                                                        dna_types_hm.get(&member.mem_type)
                                                    {
                                                        let mem_tlen: u16 =
                                                            calc_mem_tlen(member, *type_found);
                                                        let mut some_name = String::with_capacity(
                                                            mem_tlen as usize,
                                                        );
                                                        for i in 0..mem_tlen as usize {
                                                            if bytes_read[byte_index + i] == 0 {
                                                                break;
                                                            }
                                                            some_name.push(
                                                                bytes_read[byte_index + i] as char,
                                                            );
                                                        }
                                                        if mem_tlen == 1 {
                                                            let some_char: u8 = get_char(
                                                                member,
                                                                &bytes_read,
                                                                byte_index,
                                                            );
                                                            println!(
                                                                "{} = {}",
                                                                struct_name, some_char
                                                            );
                                                        } else {
                                                            println!(
                                                                "{} = {:?}",
                                                                struct_name, some_name
                                                            );
                                                        }
                                                    }
                                                }
                                                "float" => {
                                                    let some_float: f32 =
                                                        get_float(member, &bytes_read, byte_index);
                                                    println!(
                                                        "{} = {}_{}",
                                                        struct_name, some_float, "f32"
                                                    );
                                                }
                                                "int" => {
                                                    let some_int: i32 =
                                                        get_int(member, &bytes_read, byte_index);
                                                    println!(
                                                        "{} = {}_{}",
                                                        struct_name, some_int, "i32"
                                                    );
                                                }
                                                "short" => {
                                                    let some_short: i16 =
                                                        get_short(member, &bytes_read, byte_index);
                                                    println!(
                                                        "{} = {}_{}",
                                                        struct_name, some_short, "i16"
                                                    );
                                                }
                                                _ => {
                                                    println!(
                                                        "TODO: {} = {}",
                                                        member.mem_name, member.mem_type
                                                    );
                                                }
                                            }
                                        }
                                    }
                                    // find mem_type in dna_types.names
                                    if let Some(type_found) = dna_types_hm.get(&member.mem_type) {
                                        let mem_tlen: u16 = calc_mem_tlen(member, *type_found);
                                        byte_index += mem_tlen as usize;
                                    }
                                }
                            } else {
                                if member.mem_name.ends_with("[4][4]") {
                                    if member.mem_name.starts_with(&names2[0]) {
                                        let mut mat_values: [f32; 16] = [0.0_f32; 16];
                                        let mut values_read: usize = 0;
                                        for i in 0..4 {
                                            for j in 0..4 {
                                                let mut float_buf: [u8; 4] = [0_u8; 4];
                                                for b in 0..4 as usize {
                                                    float_buf[b] = bytes_read
                                                        [byte_index + values_read * 4 + b];
                                                }
                                                let some_float: f32 =
                                                    unsafe { mem::transmute(float_buf) };
                                                mat_values[i * 4 + j] = some_float;
                                                values_read += 1;
                                            }
                                        }
                                        println!("{} = {:#?}", struct_name, mat_values);
                                    }
                                } else if member.mem_name.ends_with("[2]") {
                                    if member.mem_name.starts_with(&names2[0]) {
                                        // some basic type?
                                        match member.mem_type.as_str() {
                                            "float" => {
                                                let some_floats: [f32; 2] =
                                                    get_float2(member, &bytes_read, byte_index);
                                                println!("{} = {:?}", struct_name, some_floats);
                                            }
                                            _ => {
                                                println!(
                                                    "TODO: {} = {}",
                                                    member.mem_name, member.mem_type
                                                );
                                            }
                                        }
                                    }
                                }
                                // find mem_type in dna_types.names
                                if let Some(type_found) = dna_types_hm.get(&member.mem_type) {
                                    let mem_tlen: u16 = calc_mem_tlen(member, *type_found);
                                    byte_index += mem_tlen as usize;
                                }
                            }
                        }
                    }
                }
            } else {
                let mut type_tlen: u16 = 0;
                // get expected tlen from dna_types
                if let Some(tlen) = dna_types_hm.get(&struct_name) {
                    println!("{} {}", struct_name, tlen);
                    type_tlen = *tlen;
                }
                // use dna_struct
                let mut counter: u16 = 0;
                if let Some(struct_found) = dna_structs_hm.get(&struct_name) {
                    let sdna_nr = struct_found.sdna_nr;
                    println!("struct {} {{ // SDNAnr = {}", struct_name, sdna_nr);
                    for index in 0..struct_found.members.len() {
                        let member = &struct_found.members[index];
                        // find mem_type in dna_types.names
                        if let Some(type_found) = dna_types_hm.get(&member.mem_type) {
                            let mem_tlen: u16 = calc_mem_tlen(member, *type_found);
                            println!("  {} {}; // {}", member.mem_type, member.mem_name, mem_tlen);
                            counter += mem_tlen;
                        }
                    }
                    println!("}}; // {}", counter);
                }
                assert!(counter == type_tlen);
            }
        } else if !print_dna {
            // example usage
            let names: Vec<String> = vec![
                "Object".to_string(),
                "Camera".to_string(),
                "Lamp".to_string(),
                "Material".to_string(),
                "Mesh".to_string(),
                "MPoly".to_string(),
                "MVert".to_string(),
                "MLoop".to_string(),
                "MLoopUV".to_string(),
                "MLoopCol".to_string(),
                "bNodeTree".to_string(),
                "bNodeSocketValueFloat".to_string(),
            ];
            let mut bytes_read: Vec<u8> = Vec::with_capacity(num_bytes_read);
            let mut structs_read: Vec<String> = Vec::with_capacity(names.len());
            let mut data_read: Vec<u32> = Vec::with_capacity(names.len());
            let mut pointers_read: Vec<(usize, u32)> = Vec::with_capacity(names.len());
            use_dna(
                print_dna,
                &args.path,
                &dna_types_hm,
                &dna_structs_hm,
                &names,
                &dna_2_type_id,
                &types,
                &mut bytes_read,
                &mut structs_read,
                &mut data_read,
                &mut pointers_read,
            )?;
            if !print_pointers {
                println!(
                    "TODO: Do something with the {} bytes returned by use_dna(...).",
                    bytes_read.len()
                );
                println!("{:?}", structs_read);
                let sum: u32 = data_read.iter().sum();
                println!("{:?} = {}", data_read, sum);
                println!("=== EXTRACT INFO ===");
            }
            let mut data_read_index: usize = 0;
            let mut index: usize = 0;
            for struct_name in structs_read {
                if !print_pointers {
                    println!("{} ({})", struct_name, data_read_index);
                }
                if let Some(tlen) = dna_types_hm.get(&struct_name) {
                    if data_read[index] == *tlen as u32 {
                        data_read_index += data_read[index] as usize;
                    } else {
                        let num_structs: u32 = data_read[index] / (*tlen as u32);
                        if !print_pointers {
                            println!("{} * {}", num_structs, struct_name);
                        }
                        data_read_index += data_read[index] as usize;
                    }
                } else {
                    data_read_index += data_read[index] as usize;
                }
                index += 1;
            }
            if !print_pointers {
                println!("({})", data_read_index);
                println!("=== EXTRACT INFO ===");
            }
        }
    }
    Ok(())
}