1use crate::check::Check;
13use crate::error::{Error, Result};
14use crate::io::{Reader, Writer};
15
16pub const LTBL_HEADER_LEN: usize = 16;
19pub const LTBL_ENTRY_SIZE_V1: u32 = 28;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
24pub struct LayerEntry {
25 pub data_size: u32,
27 pub first_lrov: u32,
30 pub first_layr: u32,
32 pub additional_sector_count: u32,
35 pub data_offset: u64,
37 pub sector_id: u32,
39}
40
41impl LayerEntry {
42 pub fn is_empty(&self) -> bool {
44 self.data_size == 0
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct LayerTable {
51 pub table_version: u32,
53 pub layer_count: u32,
55 pub entry_size: u32,
57 pub entry_count: u32,
59 pub entries: Vec<LayerEntry>,
61 first: Vec<u32>,
63}
64
65impl LayerTable {
66 pub fn parse(payload: &[u8]) -> Result<LayerTable> {
68 let mut r = Reader::checked(payload, Check::LtblEntrySize);
69 let table_version = r.u32()?;
70 if table_version != 1 {
71 return Err(Error::new(
72 Check::LtblVersion,
73 format!("unsupported table_version {table_version}"),
74 ));
75 }
76 let layer_count = r.u32()?;
77 let entry_size = r.u32()?;
78 let entry_count = r.u32()?;
79 if entry_size < LTBL_ENTRY_SIZE_V1 {
80 return Err(Error::new(
81 Check::LtblEntrySize,
82 format!("entry_size {entry_size} is below the {LTBL_ENTRY_SIZE_V1} byte v1 layout"),
83 ));
84 }
85 let table_len = (entry_count as usize)
86 .checked_mul(entry_size as usize)
87 .ok_or_else(|| Error::new(Check::LtblEntryCount, "the layer table length overflows"))?;
88 if table_len != r.remaining() {
93 return Err(Error::new(
94 Check::LtblEntryCount,
95 format!(
96 "entry_count {entry_count} of {entry_size} bytes needs {table_len} bytes, {} remain",
97 r.remaining()
98 ),
99 ));
100 }
101 let mut entries = Vec::with_capacity(entry_count as usize);
102 for _ in 0..entry_count {
103 entries.push(LayerEntry {
104 data_size: r.u32()?,
105 first_lrov: r.u32()?,
106 first_layr: r.u32()?,
107 additional_sector_count: r.u32()?,
108 data_offset: r.u64()?,
109 sector_id: r.u32()?,
110 });
111 r.skip(entry_size as usize - LTBL_ENTRY_SIZE_V1 as usize)?;
113 }
114 let first = layer_index(&entries, layer_count)?;
115 Ok(LayerTable {
116 table_version,
117 layer_count,
118 entry_size,
119 entry_count,
120 entries,
121 first,
122 })
123 }
124
125 pub fn new(entries: Vec<LayerEntry>, layer_count: u32) -> Result<LayerTable> {
128 let first = layer_index(&entries, layer_count)?;
129 Ok(LayerTable {
130 table_version: 1,
131 layer_count,
132 entry_size: LTBL_ENTRY_SIZE_V1,
133 entry_count: entries.len() as u32,
134 entries,
135 first,
136 })
137 }
138
139 pub fn to_bytes(&self) -> Vec<u8> {
141 let mut w = Writer::with_capacity(
142 LTBL_HEADER_LEN + self.entries.len() * LTBL_ENTRY_SIZE_V1 as usize,
143 );
144 w.u32(self.table_version);
145 w.u32(self.layer_count);
146 w.u32(LTBL_ENTRY_SIZE_V1);
147 w.u32(self.entries.len() as u32);
148 for entry in &self.entries {
149 w.u32(entry.data_size);
150 w.u32(entry.first_lrov);
151 w.u32(entry.first_layr);
152 w.u32(entry.additional_sector_count);
153 w.u64(entry.data_offset);
154 w.u32(entry.sector_id);
155 }
156 w.into_vec()
157 }
158
159 pub fn layer_entries(&self, layer: u32) -> &[LayerEntry] {
163 let Some(&start) = self.first.get(layer as usize) else {
164 return &[];
165 };
166 let start = start as usize;
167 let count = 1 + self.entries[start].additional_sector_count as usize;
169 &self.entries[start..start + count]
170 }
171
172 pub fn first_entry(&self, layer: u32) -> Option<&LayerEntry> {
174 self.layer_entries(layer).first()
175 }
176
177 pub fn entry(&self, layer: u32, sector_id: u32) -> Option<&LayerEntry> {
179 self.layer_entries(layer)
180 .iter()
181 .find(|entry| entry.sector_id == sector_id)
182 }
183
184 pub fn is_multi_sector(&self) -> bool {
190 (0..self.layer_count).any(|layer| {
191 self.layer_entries(layer)
192 .iter()
193 .filter(|entry| !entry.is_empty())
194 .count()
195 > 1
196 })
197 }
198}
199
200fn layer_index(entries: &[LayerEntry], layer_count: u32) -> Result<Vec<u32>> {
206 let mut first = Vec::with_capacity(layer_count as usize);
211 let mut cursor = 0usize;
212 for layer in 0..layer_count {
213 if cursor >= entries.len() {
214 return Err(Error::new(
215 Check::LtblLayerIndexRange,
216 format!(
217 "layer {layer} has no first entry: {} of the {layer_count} layers account \
218 for every one of the {} entries",
219 first.len(),
220 entries.len()
221 ),
222 ));
223 }
224 let count = 1 + entries[cursor].additional_sector_count as usize;
225 if entries.len() - cursor < count {
226 return Err(Error::new(
227 Check::LtblEntryCount,
228 format!(
229 "layer {layer} declares {count} entries, but only {} remain after {}",
230 entries.len() - cursor,
231 cursor
232 ),
233 ));
234 }
235 for (k, entry) in entries[cursor..cursor + count].iter().enumerate().skip(1) {
236 if entry.additional_sector_count != 0 {
237 return Err(Error::new(
238 Check::LtblEntryCount,
239 format!(
240 "layer {layer}'s entry {k} carries additional_sector_count {}, which only \
241 a layer's first entry may",
242 entry.additional_sector_count
243 ),
244 ));
245 }
246 }
247 first.push(cursor as u32);
248 cursor += count;
249 }
250 if cursor != entries.len() {
251 return Err(Error::new(
252 Check::LtblEntryCount,
253 format!(
254 "{layer_count} layers account for {cursor} entries, but the table declares {}",
255 entries.len()
256 ),
257 ));
258 }
259
260 for layer in 0..layer_count {
262 let start = first[layer as usize] as usize;
263 let count = 1 + entries[start].additional_sector_count as usize;
264 for pair in entries[start..start + count].windows(2) {
265 if pair[1].sector_id == pair[0].sector_id {
266 return Err(Error::new(
267 Check::LtblSectorIdUnique,
268 format!("layer {layer} names sector {} twice", pair[1].sector_id),
269 ));
270 }
271 if pair[1].sector_id < pair[0].sector_id {
272 return Err(Error::new(
273 Check::LtblSectorIdsAscending,
274 format!(
275 "layer {layer} names sector {} after sector {}",
276 pair[1].sector_id, pair[0].sector_id
277 ),
278 ));
279 }
280 }
281 }
282
283 for layer in 0..layer_count {
285 let start = first[layer as usize] as usize;
286 if entries[start].sector_id != 0 {
287 return Err(Error::new(
288 Check::LtblFirstEntryIsSectorZero,
289 format!(
290 "layer {layer}'s first entry names sector {}, not the primary sector 0",
291 entries[start].sector_id
292 ),
293 ));
294 }
295 }
296 Ok(first)
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302
303 fn entry(
306 sector_id: u32,
307 first_layr: u32,
308 data_offset: u64,
309 data_size: u32,
310 additional: u32,
311 first_lrov: u32,
312 ) -> LayerEntry {
313 LayerEntry {
314 data_size,
315 first_lrov,
316 first_layr,
317 additional_sector_count: additional,
318 data_offset,
319 sector_id,
320 }
321 }
322
323 fn table() -> LayerTable {
325 LayerTable::new(
326 vec![
327 entry(0, 3, 0, 5, 1, 0),
328 entry(1, 4, 0, 7, 0, 6),
329 entry(0, 3, 5, 0, 0, 0),
330 ],
331 2,
332 )
333 .unwrap()
334 }
335
336 #[test]
337 fn a_table_round_trips_and_indexes_its_layers() {
338 let table = table();
339 assert_eq!(table.table_version, 1);
340 assert_eq!(table.layer_count, 2);
341 assert_eq!(table.entry_size, 28);
342 assert_eq!(table.entry_count, 3);
343 assert_eq!(table.layer_entries(0).len(), 2);
344 assert_eq!(table.layer_entries(1).len(), 1);
345 assert_eq!(table.layer_entries(2).len(), 0, "no such layer");
346 assert_eq!(table.first_entry(1).unwrap().data_size, 0);
347 assert_eq!(table.entry(0, 1).unwrap().first_lrov, 6);
348 assert_eq!(table.entry(0, 2), None);
349 assert!(table.is_multi_sector(), "layer 0 carries two sectors");
350
351 let bytes = table.to_bytes();
352 assert_eq!(bytes.len(), LTBL_HEADER_LEN + 3 * 28);
353 let parsed = LayerTable::parse(&bytes).unwrap();
354 assert_eq!(parsed, table);
355 }
356
357 #[test]
358 fn a_single_sector_file_is_not_multi_sector() {
359 let table =
360 LayerTable::new(vec![entry(0, 3, 0, 5, 0, 0), entry(0, 3, 5, 0, 0, 0)], 2).unwrap();
361 assert!(!table.is_multi_sector());
362
363 let table =
365 LayerTable::new(vec![entry(0, 3, 0, 5, 1, 0), entry(4, 4, 0, 0, 0, 7)], 1).unwrap();
366 assert!(!table.is_multi_sector(), "sector 4 holds no bytes");
367 }
368
369 #[test]
370 fn the_entry_accounting_is_enforced() {
371 let rejects = |entries: Vec<LayerEntry>, layers: u32, check: Check| {
372 assert_eq!(LayerTable::new(entries, layers).unwrap_err().check(), check);
373 };
374
375 rejects(vec![entry(0, 3, 0, 5, 1, 0)], 1, Check::LtblEntryCount);
377 rejects(
379 vec![entry(0, 3, 0, 5, 1, 0), entry(1, 4, 0, 7, 1, 0)],
380 1,
381 Check::LtblEntryCount,
382 );
383 rejects(
385 vec![entry(0, 3, 0, 5, 0, 0), entry(0, 3, 5, 1, 0, 0)],
386 1,
387 Check::LtblEntryCount,
388 );
389 rejects(vec![entry(0, 3, 0, 5, 0, 0)], 2, Check::LtblLayerIndexRange);
392 rejects(
394 vec![entry(3, 3, 0, 5, 0, 0)],
395 1,
396 Check::LtblFirstEntryIsSectorZero,
397 );
398 rejects(
400 vec![
401 entry(0, 3, 0, 5, 2, 0),
402 entry(2, 3, 5, 1, 0, 0),
403 entry(1, 3, 6, 1, 0, 0),
404 ],
405 1,
406 Check::LtblSectorIdsAscending,
407 );
408 rejects(
410 vec![
411 entry(0, 3, 0, 5, 2, 0),
412 entry(1, 3, 5, 1, 0, 0),
413 entry(1, 3, 6, 1, 0, 0),
414 ],
415 1,
416 Check::LtblSectorIdUnique,
417 );
418 }
419
420 #[test]
421 fn a_table_whose_bytes_disagree_with_its_header_is_rejected() {
422 let bytes = table().to_bytes();
423
424 let mut short = bytes.clone();
427 short[12..16].copy_from_slice(&2u32.to_le_bytes());
428 assert_eq!(
429 LayerTable::parse(&short).unwrap_err().check(),
430 Check::LtblEntryCount
431 );
432
433 let mut over = bytes.clone();
436 over[12..16].copy_from_slice(&9u32.to_le_bytes());
437 assert_eq!(
438 LayerTable::parse(&over).unwrap_err().check(),
439 Check::LtblEntryCount
440 );
441
442 let mut long = bytes.clone();
445 long[16 + 12..16 + 16].copy_from_slice(&9u32.to_le_bytes());
446 assert_eq!(
447 LayerTable::parse(&long).unwrap_err().check(),
448 Check::LtblEntryCount
449 );
450 }
451
452 #[test]
453 fn a_bad_version_entry_size_or_stride_is_rejected() {
454 let mut bytes = table().to_bytes();
455
456 let mut version = bytes.clone();
457 version[0..4].copy_from_slice(&2u32.to_le_bytes());
458 assert_eq!(
459 LayerTable::parse(&version).unwrap_err().check(),
460 Check::LtblVersion
461 );
462
463 let mut small = bytes.clone();
464 small[8..12].copy_from_slice(&27u32.to_le_bytes());
465 assert_eq!(
466 LayerTable::parse(&small).unwrap_err().check(),
467 Check::LtblEntrySize
468 );
469
470 bytes[12..16].copy_from_slice(&9u32.to_le_bytes());
472 assert_eq!(
473 LayerTable::parse(&bytes).unwrap_err().check(),
474 Check::LtblEntryCount
475 );
476 }
477
478 #[test]
479 fn a_wider_entry_strides_past_unknown_fields() {
480 let mut w = Writer::new();
482 w.u32(1);
483 w.u32(1);
484 w.u32(32);
485 w.u32(2);
486 for (sector, offset, size, additional) in [(0u32, 0u64, 5u32, 1u32), (2, 5, 7, 0)] {
487 w.u32(size);
488 w.u32(0);
489 w.u32(3);
490 w.u32(additional);
491 w.u64(offset);
492 w.u32(sector);
493 w.u32(0xDEAD_BEEF); }
495 let parsed = LayerTable::parse(&w.into_vec()).unwrap();
496 assert_eq!(parsed.entry_size, 32);
497 assert_eq!(parsed.layer_entries(0).len(), 2);
498 assert_eq!(parsed.entry(0, 2).unwrap().data_offset, 5);
499 }
500}