hermes_rs 0.1.14

A dependency-free disassembler and assembler for the Hermes bytecode
Documentation
use hermes_rs::HermesFile;
use std::env;
use std::fs::File;
use std::io;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: {} <input_file>", args[0]);
        return;
    }
    let filepath = &args[1];

    // check if file exists
    if !std::path::Path::new(filepath).exists() {
        println!("File not found: {}", filepath);
        std::process::exit(1);
    }

    let f = File::open(filepath).expect("no file found");
    let mut reader = io::BufReader::new(f);
    let hermes_file = HermesFile::deserialize(&mut reader);

    println!("# R2 script for Hermes bytecode file: {}", filepath);
    println!("# Generated by hermes_rs\n");
    println!("# Hermes File Version: {}", hermes_file.header.version);
    println!("# File Size: {} bytes", hermes_file.header.file_length);
    println!("# Function Count: {}\n", hermes_file.header.function_count);
    println!("f hbc.header=0x0");
    println!("f hbc.header.size=0x{:x}\n", hermes_file.header.file_length);

    println!("# Function flags");
    for (i, function_header) in hermes_file.function_headers.iter().enumerate() {
        let function_name =
            hermes_file.get_string_from_storage_by_index(function_header.func_name() as usize);
        let sanitized_name = if function_name.is_empty() {
            format!("func_{}", i)
        } else {
            function_name.replace(|c: char| !c.is_alphanumeric() && c != '_', "_")
        };
        println!(
            "\'f func.hermes.{} {} 0x{:x}",
            sanitized_name,
            function_header.size(),
            function_header.offset()
        );
    }

    println!("\n# String flags");
    let strings = hermes_file.get_strings();
    for (i, s) in strings.iter().enumerate() {
        // Maybe there's a better way? Arabic chars are a headache
        let sanitized_name = s
            .chars()
            .map(|c| {
                if c.is_ascii_alphanumeric() || c == '_' {
                    c
                } else {
                    '_'
                }
            })
            .collect::<String>();
        let size = s.len();
        let offset = hermes_file.string_storage.get(i).unwrap().offset;
        let unique_name = format!("{}_{}", sanitized_name, i);
        println!("'f str.{} {} 0x{:x}", unique_name, size, offset);
    }
}