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>, pub data: Vec<Variant>, pub scgetterps: Vec<i32>, pub properties: Vec<(i32, i32)>, }
46
47#[derive(Debug, Clone)]
48pub enum Variant {
49 Void,
50 NullObject, InterObject(i32), InterGenerator(i32), String(i32), Octet(i32), Real(i32), Byte(i32), Short(i32), Integer(i32), Long(i32), 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}