Skip to content

Commit 19b92a1

Browse files
committed
add export sources
1 parent fd6eba4 commit 19b92a1

File tree

11 files changed

+146
-18
lines changed

11 files changed

+146
-18
lines changed

Cargo.lock

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@ parking_lot = { version = "0.12.3", features = ["deadlock_detection"] }
4343

4444
fontdb = "0.23.0"
4545
rfd = "0.15.0"
46+
open = "5.3.2"
4647

4748
log = { version = "0.4", features = ["std"] }

asm/src/dex/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ pub use raw::*;
22
pub mod element;
33

44
use crate::dex::element::{AsElement, ClassContentElement};
5-
use crate::impls::jvms::r::{ReadContext, U32BasedSize};
5+
use crate::impls::jvms::r::{ReadContext, ReadFrom, U32BasedSize};
66
use crate::impls::ToArc;
77
use crate::smali::SmaliNode;
8-
use crate::{AsmErr, AsmResult};
8+
use crate::{AsmErr, AsmResult, StrRef};
99
pub use constant::*;
1010
use std::io::Read;
1111
pub use util::*;
@@ -29,20 +29,21 @@ impl DexFile {
2929
}
3030
pub fn resolve_from_bytes(bytes: &[u8]) -> AsmResult<Self> {
3131
let mut context = ReadContext::little_endian(bytes);
32-
context.read()
32+
DexFile::read_from(&mut context)
3333
}
3434
}
3535

3636
pub struct DexFileAccessor {
3737
pub file: DexFile,
38+
pub file_name: StrRef,
3839
pub bytes: Vec<u8>,
3940
pub endian: bool,
4041
pub call_site_ids: Vec<CallSiteId>,
4142
pub method_handles: Vec<MethodHandle>,
4243
}
4344

4445
impl DexFileAccessor {
45-
pub fn new(file: DexFile, bytes: Vec<u8>) -> Self {
46+
pub fn new(file: DexFile, bytes: Vec<u8>, file_name: StrRef) -> Self {
4647
let endian = file.header.endian_tag == Header::BIG_ENDIAN_TAG;
4748
let map_list = Self::get_map_list(&bytes, &file.header, endian)
4849
.unwrap_or_default();
@@ -65,7 +66,7 @@ impl DexFileAccessor {
6566
}
6667
let call_site_ids = Self::get_call_site_ids(&bytes, call_site_off, call_site_size, endian);
6768
let method_handles = Self::get_method_handles(&bytes, method_handle_off, method_handle_size, endian);
68-
Self { file, bytes, endian, call_site_ids, method_handles }
69+
Self { file, bytes, endian, call_site_ids, method_handles, file_name }
6970
}
7071

7172
pub fn get_class_element(&self, class_data_off: DUInt) -> AsmResult<ClassContentElement> {

asm/src/impls/dex/r/raw.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ impl ReadFrom for EncodedCatchHandler {
166166
}
167167
}
168168

169-
impl ReadFrom for DexFile {
170-
fn read_from(context: &mut ReadContext) -> AsmResult<Self> {
169+
impl DexFile {
170+
pub(crate) fn read_from(context: &mut ReadContext) -> AsmResult<Self> {
171171
let header: Header = context.read()?;
172172
let string_ids = context.read_vec(header.string_ids_size)?;
173173
let type_ids = context.read_vec(header.type_ids_size)?;

asm/src/smali.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub struct SmaliNode {
1212

1313
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
1414
pub enum SmaliToken {
15+
SourceInfo(StrRef),
16+
1517
Raw(ConstStr),
1618
Op(ConstStr),
1719

@@ -125,6 +127,7 @@ pub fn tokens_to_raw(tokens: &[SmaliToken]) -> String {
125127
impl SmaliToken {
126128
pub fn raw(&self) -> String {
127129
match self {
130+
Self::SourceInfo(source) => format!("# source: {source}"),
128131
Self::Raw(tag) => tag.to_string(),
129132
Self::Op(op) => op.to_string(),
130133
Self::LineStartOffsetMarker { raw, .. } => raw.clone(),

asm/tests/dex/read_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use java_asm::dex::{DexFile, DexFileAccessor};
22
use std::sync::Arc;
33
use std::time::Instant;
4+
use java_asm::StrRef;
45

56
#[test]
67
fn read_dex_test() {
@@ -30,5 +31,5 @@ fn read_test_dex_file() -> DexFileAccessor {
3031
let dex_file_bytes = include_bytes!("../res/dex/classes14.dex");
3132
let dex_file = DexFile::resolve_from_bytes(dex_file_bytes).unwrap();
3233
println!("Dex file resolved in {:?}", start.elapsed());
33-
DexFileAccessor::new(dex_file, dex_file_bytes.to_vec())
34+
DexFileAccessor::new(dex_file, dex_file_bytes.to_vec(), StrRef::from("classes14.dex"))
3435
}

asm_egui/src/smali.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use eframe::epaint::Color32;
22
use egui::text::LayoutJob;
33
use egui::{CursorIcon, FontId, Response, ScrollArea, TextStyle, Ui, Vec2};
44
use java_asm::smali::SmaliToken;
5+
use java_asm::StrRef;
56
use java_asm_server::ui::{AppContainer, Content, Top};
67
use java_asm_server::AsmServer;
78
use std::ops::{Deref, DerefMut};
@@ -104,6 +105,20 @@ impl<'a> RenderContext<'a> {
104105
} = self;
105106
let dft_color = *dft_color;
106107
match token {
108+
SmaliToken::SourceInfo(source_info) => {
109+
let text = format!("#from: {source_info}");
110+
let text_ui = simple_text(ui, text, font, smali_style.literal)
111+
.on_hover_cursor(CursorIcon::PointingHand);
112+
let text_ui = text_ui
113+
.on_hover_ui(|ui| {
114+
ui.style_mut().interaction.selectable_labels = true;
115+
self.source_file_info_menu(ui, source_info);
116+
});
117+
text_ui.context_menu(|ui| {
118+
self.source_file_info_menu(ui, source_info);
119+
});
120+
text_ui
121+
},
107122
SmaliToken::Raw(s) => simple_text(ui, s.to_string(), font, dft_color),
108123
SmaliToken::Op(s) => simple_text(ui, s.to_string(), font, smali_style.op),
109124
SmaliToken::LineStartOffsetMarker { raw, .. } => {
@@ -139,6 +154,17 @@ impl<'a> RenderContext<'a> {
139154
}
140155
}
141156

157+
fn source_file_info_menu(
158+
&mut self, ui: &mut Ui, source_file_info: &StrRef,
159+
) {
160+
ui.horizontal(|ui| {
161+
let link = ui.link(format!("Export Source: {source_file_info}"));
162+
if link.clicked() {
163+
self.server.dialog_to_save_file(source_file_info);
164+
}
165+
});
166+
}
167+
142168
fn descriptor_menu(
143169
&mut self, ui: &mut Ui, descriptor: &str,
144170
) {

asm_server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ log = { workspace = true }
1717

1818
fontdb = { workspace = true }
1919
rfd = { workspace = true }
20+
open = { workspace = true }
2021

2122
enum_dispatch = { workspace = true }
2223

asm_server/src/impls/apk_load.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::impls::server::{ProgressMessage, ServerMessage};
22
use crate::server::OpenFileError;
3-
use crate::Accessor;
3+
use crate::{Accessor, ExportableSource};
44
use java_asm::dex::{ClassDef, DexFile, DexFileAccessor};
5-
use java_asm::smali::SmaliNode;
5+
use java_asm::smali::{stb, SmaliNode, SmaliToken};
66
use java_asm::{DescriptorRef, StrRef};
77
use log::{error, warn};
88
use std::collections::HashMap;
@@ -13,6 +13,7 @@ use zip::ZipArchive;
1313

1414
pub struct ApkAccessor {
1515
pub map: HashMap<DescriptorRef, ClassPosition>,
16+
pub dex_sources: HashMap<StrRef, Arc<DexFileAccessor>>,
1617
}
1718

1819
type ClassPosition = (Arc<DexFileAccessor>, ClassDef);
@@ -37,12 +38,18 @@ pub async fn read_apk(
3738

3839
// put dex files
3940
let dex_file_count = dex_files.len();
40-
let dex_files = dex_files.iter().map(|name| {
41-
let mut file = zip_archive.by_index(*name).map_err(OpenFileError::LoadZip)?;
41+
let mut dex_sources = HashMap::new();
42+
let dex_files = dex_files.iter().map(|entry_index| {
43+
let mut file = zip_archive.by_index(*entry_index).map_err(OpenFileError::LoadZip)?;
44+
let file_name = StrRef::from(file.name());
45+
let file_name_for_dex_sources = file_name.clone();
4246
let mut bytes = Vec::new();
4347
file.read_to_end(&mut bytes).map_err(OpenFileError::Io)?;
4448
let dex_file = DexFile::resolve_from_bytes(&bytes).map_err(OpenFileError::ResolveError)?;
45-
Ok(Arc::new(DexFileAccessor::new(dex_file, bytes)))
49+
let dex_file_accessor = Arc::new(DexFileAccessor::new(dex_file, bytes, file_name));
50+
51+
dex_sources.insert(file_name_for_dex_sources, dex_file_accessor.clone());
52+
Ok(dex_file_accessor)
4653
}).map(|res: Result<Arc<DexFileAccessor>, OpenFileError>| {
4754
match res {
4855
Ok(dex_file) => Some(dex_file),
@@ -73,7 +80,7 @@ pub async fn read_apk(
7380
};
7481
map.shrink_to_fit();
7582
send_loaded(&sender).await;
76-
Ok(ApkAccessor { map })
83+
Ok(ApkAccessor { map, dex_sources })
7784
}
7885

7986
async fn send_progress(
@@ -118,10 +125,34 @@ impl Accessor for ApkAccessor {
118125
fn read_content(&self, class_key: &str) -> Option<SmaliNode> {
119126
let class_position = self.map.get(class_key);
120127
if let Some((accessor, class_def)) = class_position {
121-
accessor.get_class_smali(*class_def).ok()
128+
let dex_file_name = accessor.file_name.clone();
129+
let smali_node = accessor.get_class_smali(*class_def).ok();
130+
let Some(smali_node) = smali_node else {
131+
warn!("No class content found for: {}", class_key);
132+
return None;
133+
};
134+
let mut smali_node = smali_node;
135+
let source_tag_smali = stb().push(SmaliToken::SourceInfo(dex_file_name)).s();
136+
smali_node.children.insert(0, source_tag_smali);
137+
Some(smali_node)
122138
} else {
123139
warn!("No class content found for: {}", class_key);
124140
None
125141
}
126142
}
143+
144+
// source key is the dex file name.
145+
fn peek_source(&self, source_key: &str) -> Option<ExportableSource> {
146+
let dex_source = self.dex_sources.get(source_key);
147+
let Some(dex_source) = dex_source else {
148+
warn!("No source found for: {source_key} when trying peek source.");
149+
return None;
150+
};
151+
let file_name = dex_source.file_name.clone();
152+
let source = dex_source.bytes.clone();
153+
Some(ExportableSource {
154+
exportable_name: file_name,
155+
source,
156+
})
157+
}
127158
}

asm_server/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ pub trait Accessor {
4848
/// the format of class_key is [DescriptorRef]
4949
fn exist_class(&self, class_key: &str) -> bool;
5050
fn read_content(&self, class_key: &str) -> Option<SmaliNode>;
51+
52+
fn peek_source(&self, source_key: &str) -> Option<ExportableSource>;
53+
}
54+
55+
pub struct ExportableSource {
56+
pub exportable_name: StrRef,
57+
pub source: Vec<u8>,
5158
}
5259

5360
pub struct MethodMeta {

0 commit comments

Comments
 (0)