tjs2dec/
model.rs

1use std::fmt;
2
3#[derive(Debug, Clone)]
4pub struct Tjs2File {
5    pub toplevel: i32,
6    pub const_pools: ConstPools,
7    pub objects: Vec<Tjs2Object>,
8}
9
10#[derive(Debug, Clone, Default)]
11pub struct ConstPools {
12    pub bytes: Vec<i8>,
13    pub shorts: Vec<i16>,
14    pub ints: Vec<i32>,
15    pub longs: Vec<i64>,
16    pub doubles: Vec<f64>,
17    pub strings: Vec<String>,
18    pub octets: Vec<Vec<u8>>,
19}
20
21#[derive(Debug, Clone)]
22pub struct Tjs2Object {
23    pub index: usize,
24
25    pub parent: i32,
26    pub name_string_index: i32,
27    pub name: Option<String>,
28    pub context_type: i32,
29
30    pub max_variable_count: i32,
31    pub variable_reserve_count: i32,
32    pub max_frame_count: i32,
33    pub func_decl_arg_count: i32,
34    pub func_decl_unnamed_arg_array_base: i32,
35    pub func_decl_collapse_base: i32,
36
37    pub prop_setter: i32,
38    pub prop_getter: i32,
39    pub super_class_getter: i32,
40
41    pub code: Vec<i32>,              // i16 words, sign-extended to i32
42    pub data: Vec<Variant>,          // vdata[]
43    pub scgetterps: Vec<i32>,        // unused for now
44    pub properties: Vec<(i32, i32)>, // (name_string_index, object_index)
45}
46
47#[derive(Debug, Clone)]
48pub enum Variant {
49    Void,
50    NullObject,       // TYPE_OBJECT (krkrz uses this mainly for null closure in bytecode)
51    InterObject(i32), // TYPE_INTER_OBJECT
52    InterGenerator(i32), // TYPE_INTER_GENERATOR
53    String(i32),      // index into string pool
54    Octet(i32),       // index into octet pool
55    Real(i32),        // index into double pool
56    Byte(i32),        // index into byte pool
57    Short(i32),       // index into short pool
58    Integer(i32),     // index into int pool
59    Long(i32),        // index into long pool
60    Unknown,
61}
62
63impl Variant {
64    pub fn to_readable(&self, pools: &ConstPools) -> String {
65        match *self {
66            Variant::Void => "void".to_string(),
67            Variant::NullObject => "null".to_string(),
68            Variant::InterObject(idx) => format!("#InterObject({})", idx),
69            Variant::InterGenerator(idx) => format!("#InterGenerator({})", idx),
70            Variant::String(i) => {
71                let s = pools
72                    .strings
73                    .get(i as usize)
74                    .cloned()
75                    .unwrap_or_else(|| "<bad-string-index>".to_string());
76                format!("#Var.String({})", fmt_quoted(&s))
77            }
78            Variant::Octet(i) => {
79                let n = pools.octets.get(i as usize).map(|b| b.len()).unwrap_or(0);
80                format!("#Var.Octet(len={})", n)
81            }
82            Variant::Real(i) => {
83                let v = pools.doubles.get(i as usize).cloned().unwrap_or(f64::NAN);
84                format!("#Var.Real({})", v)
85            }
86            Variant::Byte(i) => {
87                let v = pools.bytes.get(i as usize).cloned().unwrap_or(0);
88                format!("#Var.Byte({})", v)
89            }
90            Variant::Short(i) => {
91                let v = pools.shorts.get(i as usize).cloned().unwrap_or(0);
92                format!("#Var.Short({})", v)
93            }
94            Variant::Integer(i) => {
95                let v = pools.ints.get(i as usize).cloned().unwrap_or(0);
96                format!("#Var.Integer({})", v)
97            }
98            Variant::Long(i) => {
99                let v = pools.longs.get(i as usize).cloned().unwrap_or(0);
100                format!("#Var.Long({})", v)
101            }
102            Variant::Unknown => "<unknown>".to_string(),
103        }
104    }
105}
106
107fn fmt_quoted(s: &str) -> String {
108    let mut out = String::with_capacity(s.len() + 2);
109    out.push('"');
110    for ch in s.chars() {
111        match ch {
112            '\\' => out.push_str("\\\\"),
113            '"' => out.push_str("\\\""),
114            '\n' => out.push_str("\\n"),
115            '\r' => out.push_str("\\r"),
116            '\t' => out.push_str("\\t"),
117            _ => out.push(ch),
118        }
119    }
120    out.push('"');
121    out
122}