mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
LR-IMP-FORMATS: ARW6 container rejection tests and tile byte ranges
This commit is contained in:
1 file changed
+84
Vendored
+84
@@ -91,6 +91,16 @@ pub(crate) fn parse_tile_table(strip: &[u8], width: usize, height: usize) -> Res
|
||||
Ok(tiles)
|
||||
}
|
||||
|
||||
/// Tile `i`'s bytes: from its offset to the next tile's offset (the last: the strip end).
|
||||
pub(crate) fn tile_bytes<'a>(strip: &'a [u8], tiles: &[TileEntry], i: usize) -> Option<&'a [u8]> {
|
||||
let start = tiles.get(i)?.offset;
|
||||
let end = match tiles.get(i.checked_add(1)?) {
|
||||
Some(next) => next.offset,
|
||||
None => strip.len(),
|
||||
};
|
||||
strip.get(start..end)
|
||||
}
|
||||
|
||||
/// One of a tile's 13 streams (positions in 16-byte words from the tile start).
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct StreamRef {
|
||||
@@ -294,6 +304,80 @@ mod tests {
|
||||
assert!(parse_tile_header(&tile, 64, 50).is_err()); // VS != th / 2
|
||||
}
|
||||
|
||||
fn put32(b: &mut [u8], at: usize, v: u32) {
|
||||
b[at..at + 4].copy_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tile_table_validation_cases() {
|
||||
let (tile, _) = one_tile(64, 48, 0, Qis::ZERO);
|
||||
let many = |n: usize| {
|
||||
let tiles: Vec<_> = (0..n).map(|i| (64 * i, 0, 64, 48, tile.clone())).collect();
|
||||
strip_of(&arw6_file(&tiles, 64 * n, 48)).to_vec()
|
||||
};
|
||||
let sixteen = many(16);
|
||||
assert_eq!(parse_tile_table(&sixteen, 1024, 48).unwrap().len(), 16);
|
||||
let mut seventeen = sixteen.clone();
|
||||
seventeen[0] = 17;
|
||||
assert!(parse_tile_table(&seventeen, 1088, 48).is_err());
|
||||
|
||||
let two = strip_of(&arw6_file(&[(0, 0, 64, 48, tile.clone()), (64, 0, 64, 48, tile.clone())], 128, 48)).to_vec();
|
||||
assert_eq!(parse_tile_table(&two, 128, 48).unwrap().len(), 2);
|
||||
let mut swapped = two.clone();
|
||||
let (a, b) = (two[8..16].to_vec(), two[32..40].to_vec());
|
||||
swapped[8..16].copy_from_slice(&b);
|
||||
swapped[32..40].copy_from_slice(&a);
|
||||
assert!(parse_tile_table(&swapped, 128, 48).is_err());
|
||||
let mut at_end = two.clone();
|
||||
at_end[32..40].copy_from_slice(&(two.len() as u64).to_le_bytes());
|
||||
assert!(parse_tile_table(&at_end, 128, 48).is_err());
|
||||
|
||||
let one = many(1);
|
||||
let mut wide = one.clone();
|
||||
put32(&mut wide, 24, 72); // w / 2 = 36 is not a multiple of 8
|
||||
assert!(parse_tile_table(&wide, 72, 48).is_err());
|
||||
let mut huge = one.clone();
|
||||
put32(&mut huge, 24, 1 << 20);
|
||||
put32(&mut huge, 28, 1 << 20);
|
||||
assert!(matches!(parse_tile_table(&huge, 1 << 20, 1 << 20), Err(RawError::Limit(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tile_bytes_span_to_the_next_offset() {
|
||||
let (tile, _) = one_tile(64, 48, 0, Qis::ZERO);
|
||||
let file = arw6_file(&[(0, 0, 64, 48, tile.clone()), (64, 0, 64, 48, tile.clone())], 128, 48);
|
||||
let strip = strip_of(&file);
|
||||
let tiles = parse_tile_table(strip, 128, 48).unwrap();
|
||||
let (t0, t1) = (tile_bytes(strip, &tiles, 0).unwrap(), tile_bytes(strip, &tiles, 1).unwrap());
|
||||
assert_eq!(t0.len(), tiles[1].offset - tiles[0].offset);
|
||||
assert_eq!(t0, &tile[..]);
|
||||
assert_eq!(t1.as_ptr() as usize + t1.len(), strip.as_ptr() as usize + strip.len());
|
||||
assert!(tile_bytes(strip, &tiles, 2).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tile_header_and_stream_validation_cases() {
|
||||
let (tile, _) = one_tile(64, 48, 0, Qis::REAL);
|
||||
let h = parse_tile_header(&tile, 64, 48).unwrap();
|
||||
let mut two_streams = tile.clone();
|
||||
two_streams[3 * 16] = 2;
|
||||
assert!(parse_tile_header(&two_streams, 64, 48).is_err());
|
||||
let mut big = tile.clone();
|
||||
big[3 * 16 + 1..3 * 16 + 4].copy_from_slice(&[0xff; 3]); // stream 0 larger than the tile
|
||||
assert!(parse_tile_header(&big, 64, 48).is_err());
|
||||
let mut idx = tile.clone();
|
||||
idx[8 * 16..8 * 16 + 2].copy_from_slice(&[0xff, 0xff]); // index words beyond the stream
|
||||
assert!(parse_tile_header(&idx, 64, 48).is_err());
|
||||
|
||||
let s = &h.streams[9];
|
||||
let mut bad_half = tile.clone();
|
||||
let idx_start = (s.word + 1) * 16;
|
||||
bad_half[idx_start..idx_start + 2].copy_from_slice(&[0xff, 0xff]); // A past the data area
|
||||
assert!(stream_halves(&bad_half, s, h.ntu).is_err());
|
||||
let outside = StreamRef { index_words: 0xffff, ..s.clone() };
|
||||
assert!(stream_halves(&tile, &outside, h.ntu).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_stream_of_an_encoded_tile_parses() {
|
||||
for s in [0u8, 3] {
|
||||
|
||||
Reference in new issue
Block a user