1use crate::Result;
2use jxl_bitstream::{Bitstream, U};
3use jxl_oxide_common::Bundle;
4
5pub struct Toc {
10 num_lf_groups: usize,
11 num_groups: usize,
12 groups: Vec<TocGroup>,
13 bitstream_to_original: Vec<usize>,
14 original_to_bitstream: Vec<usize>,
15 total_size: usize,
16}
17
18impl std::fmt::Debug for Toc {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 f.debug_struct("Toc")
21 .field("num_lf_groups", &self.num_lf_groups)
22 .field("num_groups", &self.num_groups)
23 .field("total_size", &self.total_size)
24 .field(
25 "groups",
26 &format_args!(
27 "({} {})",
28 self.groups.len(),
29 if self.groups.len() == 1 {
30 "entry"
31 } else {
32 "entries"
33 },
34 ),
35 )
36 .field(
37 "bitstream_order",
38 &format_args!(
39 "({})",
40 if self.bitstream_to_original.is_empty() {
41 "empty"
42 } else {
43 "non-empty"
44 },
45 ),
46 )
47 .finish_non_exhaustive()
48 }
49}
50
51#[derive(Debug, Copy, Clone)]
53pub struct TocGroup {
54 pub kind: TocGroupKind,
56 pub offset: usize,
58 pub size: u32,
60}
61
62#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
63pub enum TocGroupKind {
64 All,
65 LfGlobal,
66 LfGroup(u32),
67 HfGlobal,
68 GroupPass { pass_idx: u32, group_idx: u32 },
69}
70
71impl Ord for TocGroupKind {
72 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
73 match (self, other) {
74 (x, y) if x == y => std::cmp::Ordering::Equal,
75 (Self::All, _) => std::cmp::Ordering::Less,
76 (_, Self::All) => std::cmp::Ordering::Greater,
77 (Self::LfGlobal, _) => std::cmp::Ordering::Less,
78 (_, Self::LfGlobal) => std::cmp::Ordering::Greater,
79 (Self::LfGroup(g_self), Self::LfGroup(g_other)) => g_self.cmp(g_other),
80 (Self::LfGroup(_), _) => std::cmp::Ordering::Less,
81 (_, Self::LfGroup(_)) => std::cmp::Ordering::Greater,
82 (Self::HfGlobal, _) => std::cmp::Ordering::Less,
83 (_, Self::HfGlobal) => std::cmp::Ordering::Greater,
84 (
85 Self::GroupPass {
86 pass_idx: p_self,
87 group_idx: g_self,
88 },
89 Self::GroupPass {
90 pass_idx: p_other,
91 group_idx: g_other,
92 },
93 ) => p_self.cmp(p_other).then(g_self.cmp(g_other)),
94 }
95 }
96}
97
98impl PartialOrd for TocGroupKind {
99 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
100 Some(self.cmp(other))
101 }
102}
103
104impl Toc {
105 pub fn bookmark(&self) -> usize {
107 let idx = self.bitstream_to_original.first().copied().unwrap_or(0);
108 self.groups[idx].offset
109 }
110
111 pub fn is_single_entry(&self) -> bool {
113 self.groups.len() <= 1
114 }
115
116 pub fn group_index_bitstream_order(&self, kind: TocGroupKind) -> usize {
117 let original_order = match kind {
118 TocGroupKind::All if self.is_single_entry() => 0,
119 _ if self.is_single_entry() => {
120 panic!("Cannot request group type of {kind:?} for single-group frame",)
121 }
122 TocGroupKind::All => panic!("Cannot request group type of All for multi-group frame"),
123 TocGroupKind::LfGlobal => 0,
124 TocGroupKind::LfGroup(lf_group_idx) => 1 + lf_group_idx as usize,
125 TocGroupKind::HfGlobal => 1 + self.num_lf_groups,
126 TocGroupKind::GroupPass {
127 pass_idx,
128 group_idx,
129 } => {
130 1 + self.num_lf_groups
131 + 1
132 + pass_idx as usize * self.num_groups
133 + group_idx as usize
134 }
135 };
136
137 if self.original_to_bitstream.is_empty() {
138 original_order
139 } else {
140 self.original_to_bitstream[original_order]
141 }
142 }
143
144 pub fn total_byte_size(&self) -> usize {
146 self.total_size
147 }
148
149 pub fn iter_bitstream_order(&self) -> impl Iterator<Item = TocGroup> + Send {
150 let groups = if self.bitstream_to_original.is_empty() {
151 self.groups.clone()
152 } else {
153 self.bitstream_to_original
154 .iter()
155 .map(|&idx| self.groups[idx])
156 .collect()
157 };
158 groups.into_iter()
159 }
160}
161
162impl Toc {
163 pub(crate) fn adjust_offsets(&mut self, global_frame_offset: usize) {
164 if global_frame_offset == 0 {
165 return;
166 }
167
168 for group in &mut self.groups {
169 group.offset = group
170 .offset
171 .checked_sub(global_frame_offset)
172 .expect("group offset is smaller than global frame offset");
173 }
174 }
175}
176
177impl Bundle<&crate::FrameHeader> for Toc {
178 type Error = crate::Error;
179
180 fn parse(bitstream: &mut Bitstream, ctx: &crate::FrameHeader) -> Result<Self> {
181 let num_groups = ctx.num_groups();
182 let num_passes = ctx.passes.num_passes;
183
184 let entry_count = if num_groups == 1 && num_passes == 1 {
185 1
186 } else {
187 1 + ctx.num_lf_groups() + 1 + num_groups * num_passes
188 };
189
190 if entry_count > 65536 {
191 return Err(jxl_bitstream::Error::ValidationFailed("Too many TOC entries").into());
192 }
193
194 let permutated_toc = bitstream.read_bool()?;
195 let permutation = if permutated_toc {
196 let mut decoder = jxl_coding::Decoder::parse(bitstream, 8)?;
197 decoder.begin(bitstream)?;
198 let permutation =
199 jxl_coding::read_permutation(bitstream, &mut decoder, entry_count, 0)?;
200 decoder.finalize()?;
201 permutation
202 } else {
203 Vec::new()
204 };
205
206 bitstream.zero_pad_to_byte()?;
207 let sizes = (0..entry_count)
208 .map(|_| bitstream.read_u32(U(10), 1024 + U(14), 17408 + U(22), 4211712 + U(30)))
209 .collect::<std::result::Result<Vec<_>, _>>()?;
210 bitstream.zero_pad_to_byte()?;
211
212 let mut offsets = Vec::with_capacity(sizes.len());
213 let mut acc = bitstream.num_read_bits() / 8;
214 let mut total_size = 0usize;
215 for &size in &sizes {
216 offsets.push(acc);
217 acc += size as usize;
218 total_size += size as usize;
219 }
220
221 let section_kinds = if entry_count == 1 {
222 vec![TocGroupKind::All]
223 } else {
224 let mut out = Vec::with_capacity(entry_count as usize);
225 out.push(TocGroupKind::LfGlobal);
226 for idx in 0..ctx.num_lf_groups() {
227 out.push(TocGroupKind::LfGroup(idx));
228 }
229 out.push(TocGroupKind::HfGlobal);
230 for pass_idx in 0..num_passes {
231 for group_idx in 0..num_groups {
232 out.push(TocGroupKind::GroupPass {
233 pass_idx,
234 group_idx,
235 });
236 }
237 }
238 out
239 };
240
241 let (offsets, sizes, bitstream_to_original, original_to_bitstream) = if permutated_toc {
242 let mut bitstream_to_original = vec![0usize; permutation.len()];
243 let mut offsets_out = Vec::with_capacity(permutation.len());
244 let mut sizes_out = Vec::with_capacity(permutation.len());
245 for (idx, &perm) in permutation.iter().enumerate() {
246 offsets_out.push(offsets[perm]);
247 sizes_out.push(sizes[perm]);
248 bitstream_to_original[perm] = idx;
249 }
250 (offsets_out, sizes_out, bitstream_to_original, permutation)
251 } else {
252 (offsets, sizes, Vec::new(), Vec::new())
253 };
254
255 let groups = sizes
256 .into_iter()
257 .zip(offsets)
258 .zip(section_kinds)
259 .map(|((size, offset), kind)| TocGroup { kind, offset, size })
260 .collect::<Vec<_>>();
261
262 Ok(Self {
263 num_lf_groups: ctx.num_lf_groups() as usize,
264 num_groups: num_groups as usize,
265 groups,
266 bitstream_to_original,
267 original_to_bitstream,
268 total_size,
269 })
270 }
271}