java_asm/impls/smali/
mod.rs

1use 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    // render the smali node to multiple lines.
38    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}