java_asm/impls/smali/
mod.rs1use crate::impls::ToStringRef;
2use crate::smali::{tokens_to_raw, SmaliNode, SmaliToken};
3
4impl SmaliNode {
5 pub(crate) fn render_internal(&self, ident_level: usize, result: &mut String) {
6 let indent_str = " ".repeat(ident_level);
7 result.push_str(&indent_str);
8 if let Some(offset_hint) = self.offset_hint {
9 result.push_str(&offset_hint.to_string());
10 result.push_str(": ");
11 }
12 let tag = self.tag;
13 if let Some(tag) = tag {
14 result.push_str(&tag.to_string());
15 result.push(' ');
16 }
17 let content = &self.content;
18 if !content.is_empty() {
19 result.push_str(&tokens_to_raw(content));
20 result.push(' ')
21 }
22
23 if self.children.is_empty() && self.end_tag.is_none() {
24 return;
25 }
26 for child in &self.children {
27 result.push('\n');
28 child.render_internal(ident_level + 1, result);
29 }
30 if let Some(postfix) = &self.end_tag {
31 result.push('\n');
32 result.push_str(&indent_str);
33 result.push_str(&postfix);
34 }
35 }
36
37 pub(crate) fn render_to_lines_internal(&self) -> Vec<Vec<SmaliToken>> {
39 let max_offset_len = max_offset_hint(self).to_string().len();
40 render_to_lines(self, 0, max_offset_len)
41 }
42}
43
44fn render_to_lines(
45 node: &SmaliNode, ident_width: usize, max_offset_len: usize,
46) -> Vec<Vec<SmaliToken>> {
47 let mut lines = Vec::new();
48
49 let mut current_line = Vec::new();
50 let SmaliNode { tag, content, offset_hint, children, end_tag } = node;
51 current_line.push(offset_or_stub(max_offset_len, offset_hint));
52 current_line.push(indent(ident_width));
53 if let Some(tag) = tag {
54 current_line.push(SmaliToken::Raw(tag));
55 current_line.push(SmaliToken::Raw(" "));
56 }
57 for token in content {
58 current_line.push(token.clone());
59 current_line.push(SmaliToken::Raw(" "));
60 }
61 lines.push(current_line);
62
63 for child in children {
64 let child_lines = render_to_lines(child, ident_width + 2, max_offset_len);
65 lines.extend(child_lines);
66 }
67 if children.len() > 0 {
68 lines.push(vec![])
69 }
70 if let Some(postfix) = end_tag {
71 lines.push(vec![
72 indent(ident_width),
73 SmaliToken::Raw(postfix),
74 ]);
75 }
76 lines
77}
78
79fn max_offset_hint(smali_node: &SmaliNode) -> u32 {
80 let mut max = 0;
81 for child in &smali_node.children {
82 max = max.max(max_offset_hint(child));
83 }
84 if let Some(offset_hint) = smali_node.offset_hint {
85 max = max.max(offset_hint);
86 }
87 max
88}
89
90fn offset_or_stub(
91 max_offset_len: usize, offset_hint: &Option<u32>,
92) -> SmaliToken {
93 let raw = if let Some(offset_hint) = offset_hint {
94 format!("{offset_hint:width$}", width = max_offset_len)
95 } else {
96 " ".repeat(max_offset_len)
97 };
98 SmaliToken::LineStartOffsetMarker { offset: *offset_hint, raw }
99}
100
101fn indent(indent_width: usize) -> SmaliToken {
102 SmaliToken::Other(" ".repeat(indent_width).to_ref())
103}