Skip to content

In some cases ObjectHandler::peak_name will return String contains NUL character #9

@XiNoYv

Description

@XiNoYv

In some cases ObjectHandler::peak_name will return String contains NUL character.

Using example code from README:

test/test1.rs
use std::{
    fs::{DirBuilder, File},
    io::{Seek, Write},
    path::Path,
};

use rabex::config::ExtractionConfig;
use rabex::files::{BundleFile, SerializedFile};

#[test]
#[ignore = "Enable this to see output"]
fn test1() {
    let mut reader = File::open(r"buli_super").unwrap();
    let export_dir = Path::new("dump");

    // parse the bundle file
    let config = ExtractionConfig::new(None, "".to_string());
    let mut bundle = BundleFile::from_reader(&mut reader, &config).unwrap();

    // iterate over the files in the bundle
    for directory in &bundle.m_DirectoryInfo {
        if directory.path.ends_with(".resS") {
            continue;
        }
        // generate export dir for cab
        let export_cab_dir = export_dir.join(&directory.path);
        // seek to the start of the file in the bundle
        bundle
            .m_BlockReader
            .seek(std::io::SeekFrom::Start(directory.offset as u64))
            .unwrap();

        // try to parse the file as a SerializedFile
        match SerializedFile::from_reader(&mut bundle.m_BlockReader, &config) {
            Ok(serialized) => {
                // iterate over objects
                for object in &serialized.m_Objects {
                    // get a helper object to parse the object
                    let mut handler =
                        serialized.get_object_handler(object, &mut bundle.m_BlockReader);

                    // try to get the name
                    let name = match handler.peak_name() {
                        Ok(name) => format!("{}_{}", object.m_PathID, name),
                        Err(_) => format!("{}", object.m_PathID),
                    };

                    // ensure that the parent directory exists
                    let dst_path = export_cab_dir.join(name);
                    DirBuilder::new()
                        .recursive(true)
                        .create(dst_path.parent().unwrap())
                        .unwrap_or_else(|_| panic!("Failed to create {:?}", dst_path.parent()));

                    // parse the object as json
                    let json = handler.parse_as_json().unwrap();
                    // println!("{:?}", json);
                    File::create(format!("{}.json", dst_path.to_string_lossy()))
                        .unwrap()
                        .write_all(json.to_string().as_bytes())
                        .unwrap();

                    // parse the object as yaml
                    let yaml = handler.parse_as_yaml().unwrap().unwrap();
                    // println!("{:?}", yaml);
                    File::create(format!("{}.yaml", dst_path.to_string_lossy()))
                        .unwrap()
                        .write_all(serde_yaml::to_string(&yaml).unwrap().as_bytes())
                        .unwrap();

                    // parse the object as msgpack
                    let msgpack = handler.parse_as_msgpack().unwrap();
                    File::create(format!("{}.msgpack", dst_path.to_string_lossy()))
                        .unwrap()
                        .write_all(&msgpack)
                        .unwrap();

                    // serialize as actual class
                    // note: a small part of the object classes isn't implemented yet
                    if object.m_ClassID == rabex::objects::map::AssetBundle {
                        let ab = handler
                            .parse::<rabex::objects::classes::AssetBundle>()
                            .unwrap();
                        println!("{:?}", ab);
                    }
                }
            }
            Err(e) => {
                // TODO - try to filter out resource files
                println!(
                    "Failed to parse {} as SerializedFile.",
                    &directory.path.to_string()
                );
            }
        }
    }
}

Specifically, in this code

                    // try to get the name
                    let name = match handler.peak_name() {
                        Ok(name) => format!("{}_{}", object.m_PathID, name),
                        Err(_) => format!("{}", object.m_PathID),
                    };

                    // ensure that the parent directory exists
                    let dst_path = export_cab_dir.join(name);
                    DirBuilder::new()
                        .recursive(true)
                        .create(dst_path.parent().unwrap())
                        .unwrap_or_else(|_| panic!("Failed to create {:?}", dst_path.parent()));

                    // parse the object as json
                    let json = handler.parse_as_json().unwrap();
                    // println!("{:?}", json);
                    File::create(format!("{}.json", dst_path.to_string_lossy()))
                        .unwrap()
                        .write_all(json.to_string().as_bytes())
                        .unwrap();

name could contain \0 thus dst_path would also contain \0 char which results in the following error on windows

thread 'test1' panicked at tests\test1.rs:65:26:
called `Result::unwrap()` on an `Err` value: Error { kind: InvalidInput, message: "strings passed to WinAPI cannot contain NULs" }

Related file
buli_super.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions