ghidra-version-manager 0.6.0

Ghidra Version Manager
use std::{collections::BTreeMap, path::Path};

use anyhow::Context;

#[derive(Debug)]
pub struct GhidraPropsFile {
    pub fields: BTreeMap<String, Vec<String>>,
}

impl GhidraPropsFile {
    pub fn from_path(path: &Path) -> anyhow::Result<Self> {
        let mut out = BTreeMap::new();

        let data = std::fs::read_to_string(path)?;

        for line in data.lines() {
            if line.starts_with('#') {
                continue;
            }

            if line.contains('=') {
                let eq = line.chars().position(|c| c == '=').context("Missing eq")?;
                let key = &line[..eq];
                let val = &line[eq + 1..];

                out.entry(key.to_string())
                    .and_modify(|f: &mut Vec<String>| f.push(val.to_string()))
                    .or_insert(vec![val.to_string()]);
            }
        }

        Ok(Self { fields: out })
    }

    pub fn save_to_file(&self, path: &Path) -> anyhow::Result<()> {
        std::fs::write(path, self.generate_prop_content())?;
        Ok(())
    }

    fn generate_prop_content(&self) -> String {
        let mut out = String::new();

        for (key, vals) in self.fields.iter() {
            for val in vals {
                out.push_str(key);
                out.push('=');
                out.push_str(val);
                out.push('\n');
            }
        }

        out
    }

    pub fn get_by_key(&self, key: &str) -> Option<Vec<String>> {
        self.fields.get(key).cloned()
    }

    pub fn put(&mut self, key: &str, val: Vec<String>) {
        self.fields.insert(key.to_string(), val);
    }
}