arsc/writer/
components_sizing.rs1use crate::components::{
2 Arsc, Config, Header, Package, ResourceEntry, ResourceValue, Spec, Specs, StringPool, Type,
3 Value,
4};
5use crate::{Resources, Style, StyleSpan};
6
7pub(in crate::writer) trait ConstByteSizing {
10 const SIZE: usize;
12}
13
14pub(in crate::writer) trait ByteSizing {
17 fn size(&self) -> usize;
19}
20
21impl<T: ConstByteSizing> ByteSizing for T {
22 fn size(&self) -> usize {
23 T::SIZE
24 }
25}
26
27impl ConstByteSizing for Value {
28 const SIZE: usize = 2 + 1 + 1 + 4; }
30
31impl ByteSizing for ResourceValue {
32 fn size(&self) -> usize {
33 match self {
34 ResourceValue::Plain(_) => Value::SIZE,
35 ResourceValue::Bag { parent: _, values } => {
36 4 + 4+ values.len() * (4 + Value::SIZE)
38 }
39 }
40 }
41}
42
43impl ByteSizing for ResourceEntry {
44 fn size(&self) -> usize {
45 2 + 2 + 4 + self.value.size() }
47}
48
49impl ByteSizing for Config {
50 fn size(&self) -> usize {
51 Header::SIZE + 1 + 1 + 2 + 4 + 4 + self.id.len()+ padding(self.id.len())+ self.resources.size()
55 }
56}
57
58impl ByteSizing for Resources {
59 fn size(&self) -> usize {
60 self.entry_count() * 4 + self.resources.iter().map(ByteSizing::size).sum::<usize>()
61 }
62}
63
64impl ConstByteSizing for Spec {
65 const SIZE: usize = 4; }
67
68impl ByteSizing for Specs {
69 fn size(&self) -> usize {
70 Header::SIZE + 1 + 1 + 2 + 4 + self.specs.len() * Spec::SIZE
72 }
73}
74
75impl ByteSizing for Type {
76 fn size(&self) -> usize {
77 let parse_spec = self.specs.as_ref().map(ByteSizing::size).unwrap_or(0);
78 let parse_config = self.configs.iter().map(ByteSizing::size).sum::<usize>();
79 parse_spec + parse_config
80 }
81}
82
83impl ByteSizing for StringPool {
84 fn size(&self) -> usize {
85 let size = Header::SIZE + 5 * 4 + self.strings.len() * 4 + self.styles.len() * 4; let string_length = self
90 .strings
91 .iter()
92 .map(|s| {
93 if self.use_utf8() {
94 StringPool::utf8_string_size(s)
95 } else {
96 StringPool::utf16_string_size(s)
97 }
98 })
99 .sum::<usize>();
100 let string_padding = padding(string_length);
101 let style_size = if self.styles.is_empty() {
102 0
103 } else {
104 self.styles.iter().map(ByteSizing::size).sum::<usize>() + 8 };
106 size + string_length + string_padding + style_size
107 }
108}
109
110impl StringPool {
111 pub(crate) fn utf8_string_size(string: &str) -> usize {
112 let char_count = string.chars().count();
113 let char_count_bytes = if char_count <= 0x7F { 1 } else { 2 };
114
115 let byte_count = string.len();
116 let byte_count_bytes = if byte_count <= 0x7F { 1 } else { 2 };
117
118 char_count_bytes + byte_count_bytes + byte_count + 1 }
120
121 pub(crate) fn utf16_string_size(string: &str) -> usize {
122 let char_count = string.chars().count();
123 let char_count_bytes = if char_count <= 0x7FFF { 2 } else { 4 };
124
125 char_count_bytes + char_count * 2 + 2 }
127}
128
129impl ByteSizing for Style {
130 fn size(&self) -> usize {
131 self.spans.len() * StyleSpan::SIZE + 4
132 }
133}
134
135impl ConstByteSizing for StyleSpan {
136 const SIZE: usize = 4 + 4 + 4;
137}
138
139impl ByteSizing for Package {
140 fn size(&self) -> usize {
141 Header::SIZE + 4 + 256 + 5 * 4 + self.type_names.size()
144 + self.types.iter().map(ByteSizing::size).sum::<usize>()
145 + self.key_names.size()
146 }
147}
148
149impl ByteSizing for Arsc {
150 fn size(&self) -> usize {
151 Header::SIZE + 4 + self.global_string_pool.size()
153 + self.packages.iter().map(ByteSizing::size).sum::<usize>()
154 }
155}
156
157impl ConstByteSizing for Header {
158 const SIZE: usize = 8;
159}
160
161pub(crate) fn padding(size: usize) -> usize {
168 (4 - size % 4) % 4
169}