Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Serial-ATA committed Jan 19, 2025
1 parent 82ffc25 commit 239e5bc
Show file tree
Hide file tree
Showing 72 changed files with 1,630 additions and 824 deletions.
63 changes: 2 additions & 61 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,61 +1,2 @@
[target.'cfg(all())']
rustflags = [
#### DOES NOT CHANGE ####

# Forbids
"-Fclippy::dbg_macro",
"-Fclippy::string_to_string",

# Denies
"-Dclippy::pedantic",
"-Dclippy::all",
"-Drust_2018_idioms",
"-Dtrivial_casts",
"-Dtrivial_numeric_casts",
"-Dunused_import_braces",
"-Dexplicit_outlives_requirements",

# Allows
"-Aunknown_lints",
"-Aclippy::too_many_lines",
"-Aclippy::cast_precision_loss",
"-Aclippy::cast_sign_loss",
"-Aclippy::cast_possible_wrap",
"-Aclippy::cast_possible_truncation",
"-Aclippy::module_name_repetitions",
"-Aclippy::must_use_candidate",
"-Alet_underscore_drop",
"-Aclippy::match_wildcard_for_single_variants",
"-Aclippy::semicolon_if_nothing_returned",
"-Aclippy::new_without_default",
"-Aclippy::from_over_into",
"-Aclippy::upper_case_acronyms",
"-Aclippy::single_match_else",
"-Aclippy::similar_names",
"-Aclippy::len_without_is_empty",
"-Aclippy::needless_late_init",
"-Aclippy::type_complexity",
"-Aclippy::type_repetition_in_bounds",
"-Aunused_qualifications",
"-Aclippy::return_self_not_must_use",
"-Aclippy::bool_to_int_with_if",
"-Aclippy::uninlined_format_args",
"-Aclippy::manual_let_else",

# For Library docs
# "-Dmissing_docs",
# "-Drustdoc::broken_intra_doc_links",
# "-Aclippy::doc_markdown",
# "-Aclippy::tabs_in_doc_comments",

#### EXTRAS BELOW ####
"-Aclippy::inline_always",
"-Aclippy::new-ret-no-self",
"-Aclippy::mut-from-ref",
"-Aclippy::used_underscore_binding",
"-Aclippy::needless_pass_by_value",
"-Aclippy::manual_assert",
"-Aclippy::unnecessary_wraps",
# TODO: Remove this
"-Aclippy::missing-panics-doc",
]
[build]
target-dir = "target"
4 changes: 2 additions & 2 deletions classfile/src/accessflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl_is_methods! {
impl MethodAccessFlags {
is_public => ACC_PUBLIC;
is_private => ACC_PRIVATE;
is_protected => ACC_PRIVATE;
is_protected => ACC_PROTECTED;
is_static => ACC_STATIC;
is_final => ACC_FINAL;
is_synchronized => ACC_SYNCHRONIZED;
Expand Down Expand Up @@ -223,7 +223,7 @@ impl_is_methods! {
impl FieldAccessFlags {
is_public => ACC_PUBLIC;
is_private => ACC_PRIVATE;
is_protected => ACC_PRIVATE;
is_protected => ACC_PROTECTED;
is_static => ACC_STATIC;
is_final => ACC_FINAL;
is_volatile => ACC_VOLATILE;
Expand Down
9 changes: 4 additions & 5 deletions generators/native_methods/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,15 @@ pub fn generate_definitions_for_class(def_path: &Path, class: &Class) {

macro_rules! non_static_signature {
() => {
"\tpub fn _{}(env: std::ptr::NonNull<::jni::env::JniEnv>, locals: \
crate::stack::local_stack::LocalStack) -> crate::native::method::NativeReturn {{"
"\tpub fn _{}(env: ::jni::env::JniEnv, locals: crate::stack::local_stack::LocalStack) -> \
crate::native::method::NativeReturn {{"
};
}

macro_rules! static_signature {
() => {
"\tpub fn _{}(env: std::ptr::NonNull<::jni::env::JniEnv>, class: &'static \
crate::objects::class::Class, locals: crate::stack::local_stack::LocalStack) -> \
crate::native::method::NativeReturn {{"
"\tpub fn _{}(env: ::jni::env::JniEnv, class: &'static crate::objects::class::Class, \
locals: crate::stack::local_stack::LocalStack) -> crate::native::method::NativeReturn {{"
};
}

Expand Down
2 changes: 1 addition & 1 deletion generators/native_methods/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn write_entries_for_class(mut file: Option<File>, def_path: &Path, class: &Clas
Member::Field(field) => {
writeln!(
file.as_mut().expect("file should exist"),
"#[allow(non_upper_case_globals)]\npub const {}: {} = {};",
"#[allow(non_upper_case_globals, dead_code)]\npub const {}: {} = {};",
field.name,
field.ty.map_to_rust_ty(),
field.expr
Expand Down
4 changes: 2 additions & 2 deletions generators/native_methods/src/registernatives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ macro_rules! native_method_table_file_header {
static NATIVES_REGISTERED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
#[allow(trivial_casts, unused_imports)]
pub fn registerNatives(_: std::ptr::NonNull<JniEnv>, _: &'static crate::objects::class::Class) {{
pub fn registerNatives(_: ::jni::env::JniEnv, _: &'static crate::objects::class::Class) {{
use symbols::sym;
if NATIVES_REGISTERED.compare_exchange(false, true, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::Acquire) != Ok(false) {{
Expand Down Expand Up @@ -59,7 +59,7 @@ pub(crate) fn generate_register_natives_table(
)
.unwrap();

for ref member in class.members.extract_if(|member| {
for ref member in class.members.extract_if(.., |member| {
matches!(member, Member::Method(method) if method.name() != "registerNatives" && method.modifiers.contains(AccessFlags::ACC_NATIVE) && !method.modifiers.contains(AccessFlags::ACC_STATIC))
}).collect::<Vec<_>>() {
match member {
Expand Down
131 changes: 36 additions & 95 deletions jimage/src/decompressor.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::error::{Error, Result};
use crate::ImageStrings;

use std::io::Write;
use std::ptr::read_unaligned as ptread;

use common::box_slice;
use common::endian::Endian;
use common::int_types::{u1, u4, u8};
use common::traits::JavaEndianAwareRead;

pub struct ResourceHeader {
pub(crate) __magic: u4,
Expand All @@ -20,85 +20,29 @@ impl ResourceHeader {
pub const RESOURCE_HEADER_MAGIC: u4 = 0xCAFE_FAFA;
}

unsafe fn get_u8(ptr: *mut u1, endian: Endian) -> u8 {
match endian {
Endian::Little => {
u8::from(ptread::<u1>(ptr))
| u8::from(ptread::<u1>(ptr.add(1))) << 8
| u8::from(ptread::<u1>(ptr.add(2))) << 16
| u8::from(ptread::<u1>(ptr.add(3))) << 24
| u8::from(ptread::<u1>(ptr.add(4))) << 32
| u8::from(ptread::<u1>(ptr.add(5))) << 40
| u8::from(ptread::<u1>(ptr.add(6))) << 48
| u8::from(ptread::<u1>(ptr.add(7))) << 56
},
Endian::Big => {
u8::from(ptread::<u1>(ptr)) << 56
| u8::from(ptread::<u1>(ptr.add(1))) << 48
| u8::from(ptread::<u1>(ptr.add(2))) << 40
| u8::from(ptread::<u1>(ptr.add(3))) << 32
| u8::from(ptread::<u1>(ptr.add(4))) << 24
| u8::from(ptread::<u1>(ptr.add(5))) << 16
| u8::from(ptread::<u1>(ptr.add(6))) << 8
| u8::from(ptread::<u1>(ptr.add(7)))
},
}
}

unsafe fn get_u4(ptr: *mut u1, endian: Endian) -> u4 {
match endian {
Endian::Little => {
u4::from(ptread::<u1>(ptr))
| u4::from(ptread::<u1>(ptr.add(1))) << 8
| u4::from(ptread::<u1>(ptr.add(2))) << 16
| u4::from(ptread::<u1>(ptr.add(3))) << 24
},
Endian::Big => {
u4::from(ptread::<u1>(ptr)) << 24
| u4::from(ptread::<u1>(ptr.add(1))) << 16
| u4::from(ptread::<u1>(ptr.add(2))) << 8
| u4::from(ptread::<u1>(ptr.add(3)))
},
}
}

// https://github.com/openjdk/jdk/blob/f80faced6e6c6c1b10541a8b0c91625215c9ef43/src/java.base/share/native/libjimage/imageDecompressor.cpp#L136
/// Decompression entry point. Called from [`ImageFileReader::get_resource`].
#[allow(clippy::size_of_in_element_count)]
pub fn decompress_resource(
compressed: &mut [u1],
compressed: &mut &[u1],
mut uncompressed: &mut [u1],
uncompressed_size: u8,
strings: ImageStrings<'_>,
endian: Endian,
) {
) -> Result<()> {
let mut has_header;

let mut resource = compressed.as_mut_ptr();
let mut resource = compressed.as_ptr();

// Resource could have been transformed by a stack of decompressors.
// Iterate and decompress resources until there is no more header.
loop {
let magic;
let size;
let uncompressed_size;
let decompressor_name_offset;
let decompressor_config_offset;
let is_terminal;
unsafe {
magic = get_u4(resource, endian);
resource = resource.add(core::mem::size_of::<u4>());
size = get_u8(resource, endian);
resource = resource.add(core::mem::size_of::<u8>());
uncompressed_size = get_u8(resource, endian);
resource = resource.add(core::mem::size_of::<u8>());
decompressor_name_offset = get_u4(resource, endian);
resource = resource.add(core::mem::size_of::<u4>());
decompressor_config_offset = get_u4(resource, endian);
resource = resource.add(core::mem::size_of::<u4>());
is_terminal = ptread::<u1>(resource);
resource = resource.add(core::mem::size_of::<u1>());
}
let magic = endian.read_u4(compressed)?;
let size = endian.read_u8(compressed)?;
let uncompressed_size = endian.read_u8(compressed)?;
let decompressor_name_offset = endian.read_u4(compressed)?;
let decompressor_config_offset = endian.read_u4(compressed)?;
let is_terminal = endian.read_u1(compressed)?;

let header = ResourceHeader {
__magic: magic,
Expand All @@ -109,67 +53,64 @@ pub fn decompress_resource(
is_terminal,
};

resource = unsafe { resource.add(size_of::<ResourceHeader>()) };

has_header = header.__magic == ResourceHeader::RESOURCE_HEADER_MAGIC;
if !has_header {
resource = unsafe { resource.sub(size_of::<ResourceHeader>()) };
break;
}

// decompressed_resource array contains the result of decompression
let decompressed_resource = box_slice![0; header.uncompressed_size as usize];

// We need to reconstruct our box and drop it in the next iteration
let decompressed_resource = Box::leak(decompressed_resource);

// Retrieve the decompressor name
let decompressor_name = strings.get(header.decompressor_name_offset);
assert!(
!decompressor_name.is_empty(),
"image decompressor not found"
);

// Retrieve the decompressor instance
// Ask the decompressor to decompress the compressed content
let decompressed_resource;
match decompressor_name {
b"zip" => decompress_zip(resource, decompressed_resource, &header, strings),
b"compact-cp" => decompress_string(resource, decompressed_resource, &header, strings),
_ => panic!(
"image decompressor not found: {}",
std::str::from_utf8(decompressor_name).unwrap()
),
b"zip" => decompressed_resource = decompress_zip(compressed, &header, strings),
b"compact-cp" => {
decompressed_resource = decompress_string(compressed, &header, strings)
},
_ => {
return Err(Error::DecompressorNotFound(
String::from_utf8_lossy(decompressor_name).into_owned(),
))
},
}

// We need to reconstruct our box and drop it in the next iteration
let decompressed_resource = Box::leak(decompressed_resource);

// Drop the previous iteration's decompressed contents
unsafe {
let _ = Box::from_raw(resource);
let _ = Box::from_raw(resource as *mut u1);
}

// Preserve this iteration's decompressed contents for the next round
resource = decompressed_resource.as_mut_ptr();
}

// Now we can write the resource to our uncompressed buffer
uncompressed
.write_all(unsafe {
std::slice::from_raw_parts(resource, uncompressed_size.try_into().unwrap())
})
.unwrap();
uncompressed.write_all(unsafe {
std::slice::from_raw_parts(resource, uncompressed_size.try_into().unwrap())
})?;

Ok(())
}

fn decompress_zip(
_compressed: *mut u1,
_uncompressed: &mut [u1],
_compressed: &mut &[u1],
_header: &ResourceHeader,
_strings: ImageStrings<'_>,
) {
) -> Box<[u1]> {
unimplemented!("zip decompression")
}

fn decompress_string(
_compressed: *mut u1,
_uncompressed: &mut [u1],
_compressed: &mut &[u1],
_header: &ResourceHeader,
_strings: ImageStrings<'_>,
) {
) -> Box<[u1]> {
unimplemented!("string decompression")
}
2 changes: 2 additions & 0 deletions jimage/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum Error {
InvalidMagic,
InvalidTableSize,
BadIndexSize,
DecompressorNotFound(String),

Common(common::error::CommonError),
Io(std::io::Error),
Expand All @@ -22,6 +23,7 @@ impl Display for Error {
f,
"The index does not match the size provided in the header"
),
Self::DecompressorNotFound(s) => write!(f, "Image decompressor \"{s}\" not found"),

Self::Common(err) => write!(f, "{}", err),
Self::Io(err) => write!(f, "{}", err),
Expand Down
Loading

0 comments on commit 239e5bc

Please sign in to comment.