rsmp4decrypt 0.1.0

Rust bindings and a CLI for Bento4 mp4decrypt
Documentation
use std::{
    env, fs,
    path::{Path, PathBuf},
};

fn collect_cpp_files(dir: &Path) -> Vec<PathBuf> {
    let mut files = fs::read_dir(dir)
        .unwrap_or_else(|error| panic!("failed to read {}: {error}", dir.display()))
        .filter_map(|entry| {
            let path = entry.ok()?.path();
            (path.extension().and_then(|ext| ext.to_str()) == Some("cpp")).then_some(path)
        })
        .collect::<Vec<_>>();

    files.sort();
    files
}

fn main() {
    let manifest_dir = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR env variable not set"),
    );
    let bento4_root = manifest_dir.join("vendor").join("bento4-src");
    let source_root = bento4_root.join("Source").join("C++");

    if !source_root.join("Core").join("Ap4.h").exists() {
        panic!(
            "Bento4 source snapshot is missing. Expected sources under {}",
            manifest_dir.join("vendor").join("bento4-src").display()
        );
    }

    println!("cargo:rerun-if-changed={}", bento4_root.display());
    println!("cargo:rerun-if-changed=src/native/rsmp4decrypt.cpp");
    println!("cargo:rerun-if-changed=src/native/rsmp4decrypt.h");

    let include_dirs = [
        source_root.join("Core"),
        source_root.join("Codecs"),
        source_root.join("Crypto"),
        source_root.join("MetaData"),
    ];

    let mut build = cc::Build::new();
    build
        .cpp(true)
        .warnings(false)
        .extra_warnings(false)
        .includes(include_dirs);

    for component in ["Codecs", "Core", "Crypto", "MetaData"] {
        for file in collect_cpp_files(&source_root.join(component)) {
            build.file(file);
        }
    }

    build.file(
        source_root
            .join("System")
            .join("StdC")
            .join("Ap4StdCFileByteStream.cpp"),
    );

    let random_source = if env::var("CARGO_CFG_TARGET_OS")
        .expect("CARGO_CFG_TARGET_OS env variable not set")
        == "windows"
    {
        source_root
            .join("System")
            .join("Win32")
            .join("Ap4Win32Random.cpp")
    } else {
        source_root
            .join("System")
            .join("Posix")
            .join("Ap4PosixRandom.cpp")
    };
    build.file(random_source);

    build.file(
        manifest_dir
            .join("src")
            .join("native")
            .join("rsmp4decrypt.cpp"),
    );
    build.compile("rsmp4decrypt");
}