use std::sync::atomic::{AtomicUsize, Ordering};
use crate::deobfuscation::renamer::{
context::{IdentifierKind, RenameContext},
RenameProvider,
};
#[derive(Debug, Default)]
pub struct SimpleNameGenerator {
types: usize,
methods: usize,
fields: usize,
params: usize,
}
impl SimpleNameGenerator {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn next_type_name(&mut self) -> String {
let name = Self::index_to_name(self.types);
self.types += 1;
name
}
pub fn next_method_name(&mut self) -> String {
let name = Self::index_to_name_lower(self.methods);
self.methods += 1;
name
}
pub fn next_field_name(&mut self) -> String {
let name = format!("f_{}", Self::index_to_name_lower(self.fields));
self.fields += 1;
name
}
pub fn next_param_name(&mut self) -> String {
let name = format!("p_{}", Self::index_to_name_lower(self.params));
self.params += 1;
name
}
#[must_use]
pub fn index_to_name(mut index: usize) -> String {
let mut result = String::new();
loop {
let remainder = index % 26;
#[allow(clippy::cast_possible_truncation)]
result.insert(0, (b'A' + remainder as u8) as char);
if index < 26 {
break;
}
index = index / 26 - 1;
}
result
}
#[must_use]
pub fn index_to_name_lower(mut index: usize) -> String {
let mut result = String::new();
loop {
let remainder = index % 26;
#[allow(clippy::cast_possible_truncation)]
result.insert(0, (b'a' + remainder as u8) as char);
if index < 26 {
break;
}
index = index / 26 - 1;
}
result
}
}
pub struct SimpleProvider {
type_counter: AtomicUsize,
method_counter: AtomicUsize,
field_counter: AtomicUsize,
param_counter: AtomicUsize,
}
impl SimpleProvider {
#[must_use]
pub fn new() -> Self {
Self {
type_counter: AtomicUsize::new(0),
method_counter: AtomicUsize::new(0),
field_counter: AtomicUsize::new(0),
param_counter: AtomicUsize::new(0),
}
}
}
impl RenameProvider for SimpleProvider {
fn name(&self) -> &'static str {
"SimpleProvider"
}
fn initialize(&mut self) -> crate::Result<()> {
Ok(())
}
fn suggest_name(&self, context: &RenameContext) -> crate::Result<Option<String>> {
let kind = match context.kind {
Some(k) => k,
None => return Ok(None),
};
let name = match kind {
IdentifierKind::Type => {
let idx = self.type_counter.fetch_add(1, Ordering::Relaxed);
SimpleNameGenerator::index_to_name(idx)
}
IdentifierKind::Method => {
let idx = self.method_counter.fetch_add(1, Ordering::Relaxed);
SimpleNameGenerator::index_to_name_lower(idx)
}
IdentifierKind::Field => {
let idx = self.field_counter.fetch_add(1, Ordering::Relaxed);
format!("f_{}", SimpleNameGenerator::index_to_name_lower(idx))
}
IdentifierKind::Parameter => {
let idx = self.param_counter.fetch_add(1, Ordering::Relaxed);
format!("p_{}", SimpleNameGenerator::index_to_name_lower(idx))
}
};
Ok(Some(name))
}
fn shutdown(&mut self) -> crate::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::deobfuscation::renamer::{
context::{IdentifierKind, RenameContext},
providers::simple::{SimpleNameGenerator, SimpleProvider},
RenameProvider,
};
#[test]
fn test_name_generator() {
assert_eq!(SimpleNameGenerator::index_to_name(0), "A");
assert_eq!(SimpleNameGenerator::index_to_name(25), "Z");
assert_eq!(SimpleNameGenerator::index_to_name(26), "AA");
assert_eq!(SimpleNameGenerator::index_to_name(27), "AB");
assert_eq!(SimpleNameGenerator::index_to_name(702), "AAA");
}
#[test]
fn test_name_generator_lower() {
assert_eq!(SimpleNameGenerator::index_to_name_lower(0), "a");
assert_eq!(SimpleNameGenerator::index_to_name_lower(25), "z");
assert_eq!(SimpleNameGenerator::index_to_name_lower(26), "aa");
}
#[test]
fn test_name_generator_sequential() {
let mut gen = SimpleNameGenerator::new();
assert_eq!(gen.next_type_name(), "A");
assert_eq!(gen.next_type_name(), "B");
assert_eq!(gen.next_method_name(), "a");
assert_eq!(gen.next_field_name(), "f_a");
assert_eq!(gen.next_param_name(), "p_a");
}
#[test]
fn test_simple_provider_trait() {
let mut provider = SimpleProvider::new();
provider.initialize().unwrap();
let type_ctx = RenameContext {
kind: Some(IdentifierKind::Type),
..Default::default()
};
let method_ctx = RenameContext {
kind: Some(IdentifierKind::Method),
..Default::default()
};
let field_ctx = RenameContext {
kind: Some(IdentifierKind::Field),
..Default::default()
};
let param_ctx = RenameContext {
kind: Some(IdentifierKind::Parameter),
..Default::default()
};
assert_eq!(
provider.suggest_name(&type_ctx).unwrap(),
Some("A".to_string())
);
assert_eq!(
provider.suggest_name(&type_ctx).unwrap(),
Some("B".to_string())
);
assert_eq!(
provider.suggest_name(&method_ctx).unwrap(),
Some("a".to_string())
);
assert_eq!(
provider.suggest_name(&field_ctx).unwrap(),
Some("f_a".to_string())
);
assert_eq!(
provider.suggest_name(¶m_ctx).unwrap(),
Some("p_a".to_string())
);
provider.shutdown().unwrap();
}
#[test]
fn test_simple_provider_no_kind() {
let provider = SimpleProvider::new();
let ctx = RenameContext::default();
assert_eq!(provider.suggest_name(&ctx).unwrap(), None);
}
}