obfuskator/crates/noxis-classfile/src/format/write/mod.rs
loki5512344 a641e69455 Initial commit: noxis JVM bytecode obfuscator
Workspace of 9 crates (noxis, noxis-core, noxis-classfile, noxis-analysis,
noxis-passes, noxis-runtime, noxis-jar, noxis-verify, noxis-structure-check).
AGPL-3.0-only license, Rust 2024 edition, unsafe_code denied.
2026-10-08 22:01:03 +02:00

93 lines
3.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Наш IR → байты `.class` через backend `ristretto_classfile`.
//!
//! Пул собирается с нуля детерминированным обходом; backend сам пересчитывает
//! номера инструкций в байтовые смещения и проверяет результат (`verify`).
mod attrs;
pub(crate) mod code;
pub(crate) mod pool;
use ristretto_classfile::{
ClassAccessFlags, ClassFile as RtClass, Field as RtField, FieldAccessFlags, FieldType,
Method as RtMethod, MethodAccessFlags, Version as RtVersion,
};
use crate::error::ClassfileError;
use crate::model::{ClassFile, Field, Method};
/// Класс нашего IR → байты `.class`.
pub(crate) fn write_class(class: &ClassFile) -> Result<Vec<u8>, ClassfileError> {
let mut pool = pool::Pool::new();
let version = RtVersion::from(class.version.major, class.version.minor)
.map_err(|e| ClassfileError::Write(e.to_string()))?;
let this_class = pool.class(&class.this_class)?;
let super_class = match &class.super_class {
None => 0,
Some(name) => pool.class(name)?,
};
let mut interfaces = Vec::with_capacity(class.interfaces.len());
for interface in &class.interfaces {
interfaces.push(pool.class(interface)?);
}
let mut fields = Vec::with_capacity(class.fields.len());
for field in &class.fields {
fields.push(convert_field(field, &mut pool)?);
}
let mut methods = Vec::with_capacity(class.methods.len());
for method in &class.methods {
methods.push(convert_method(method, &mut pool)?);
}
let mut attributes = Vec::with_capacity(class.attributes.len());
for attr in &class.attributes {
attributes.push(attrs::convert(attr, &mut pool)?);
}
let rt = RtClass {
version,
constant_pool: pool.finish(),
access_flags: ClassAccessFlags::from_bits_truncate(class.access_flags),
this_class,
super_class,
interfaces,
fields,
methods,
attributes,
code_source_url: None,
};
rt.verify()
.map_err(|e| ClassfileError::Write(format!("собранный класс не верифицируется: {e}")))?;
let mut bytes = Vec::new();
rt.to_bytes(&mut bytes)
.map_err(|e| ClassfileError::Write(e.to_string()))?;
Ok(bytes)
}
fn convert_field(field: &Field, pool: &mut pool::Pool) -> Result<RtField, ClassfileError> {
Ok(RtField {
access_flags: FieldAccessFlags::from_bits_truncate(field.access_flags),
name_index: pool.utf8(&field.name)?,
descriptor_index: pool.utf8(&field.descriptor)?,
field_type: FieldType::parse(&field.descriptor)
.map_err(|e| ClassfileError::Write(format!("кривой дескриптор поля: {e}")))?,
attributes: field
.attributes
.iter()
.map(|attr| attrs::convert(attr, pool))
.collect::<Result<_, _>>()?,
})
}
fn convert_method(method: &Method, pool: &mut pool::Pool) -> Result<RtMethod, ClassfileError> {
let mut attributes = Vec::with_capacity(method.attributes.len() + 1);
for attr in &method.attributes {
attributes.push(attrs::convert(attr, pool)?);
}
if let Some(code) = &method.code {
attributes.push(code::convert_code(code, pool)?);
}
Ok(RtMethod {
access_flags: MethodAccessFlags::from_bits_truncate(method.access_flags),
name_index: pool.utf8(&method.name)?,
descriptor_index: pool.utf8(&method.descriptor)?,
attributes,
})
}