mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-06 10:31:05 +00:00
OCIO: refuse a .csp LUT whose header claims an oversized table before reserving it (#2938)
This commit is contained in:
1 parent
6572514eb1
commit
58ca9c1c1b
2 files changed
+30
-7
No files matched your search
@@ -57,7 +57,7 @@ pub fn parse_spi1d(text: &str) -> Option<Lut> {
|
||||
}
|
||||
}
|
||||
// A 1D table is interpolated by index, so cap it like the lattices (2²⁴ entries).
|
||||
if !(2..=1 << 24).contains(&len)
|
||||
if !(2..=MAX_1D).contains(&len)
|
||||
|| !matches!(comps, 1 | 3)
|
||||
|| values.len() != len.checked_mul(comps)?
|
||||
|| from[1] <= from[0]
|
||||
@@ -79,7 +79,7 @@ pub fn parse_spi3d(text: &str) -> Option<Lut> {
|
||||
lines.next()?;
|
||||
let size: Vec<usize> = lines.next()?.split_whitespace().map(|t| t.parse().ok()).collect::<Option<_>>()?;
|
||||
let n = *size.first()?;
|
||||
if size.len() != 3 || size.iter().any(|s| *s != n) || !(2..=129).contains(&n) {
|
||||
if size.len() != 3 || size.iter().any(|s| *s != n) || !(2..=MAX_LATTICE).contains(&n) {
|
||||
return None;
|
||||
}
|
||||
let mut d3 = vec![[0.0f32; 3]; n * n * n];
|
||||
@@ -154,6 +154,11 @@ pub fn parse_3dl(text: &str) -> Option<Lut> {
|
||||
Some(Lut { n1: 0, d1: vec![], n3: n, d3, dmin: [0.0; 3], dmax: [1.0; 3] })
|
||||
}
|
||||
|
||||
/// Largest lattice side the lattice readers accept (`.spi3d`, `.csp`).
|
||||
const MAX_LATTICE: usize = 129;
|
||||
/// Most entries of a 1D table (interpolated by index, so capped like the lattices: 2²⁴).
|
||||
const MAX_1D: usize = 1 << 24;
|
||||
|
||||
/// Parse a cineSpace `.csp` LUT (1D or 3D, with its three pre-LUT shapers).
|
||||
pub fn parse_csp(text: &str) -> Option<(Lut, [Vec<(f32, f32)>; 3])> {
|
||||
let mut lines = text.lines().map(str::trim).filter(|l| !l.is_empty());
|
||||
@@ -185,8 +190,15 @@ pub fn parse_csp(text: &str) -> Option<(Lut, [Vec<(f32, f32)>; 3])> {
|
||||
if sz.len() != 3 || sz[0] != sz[1] || sz[1] != sz[2] {
|
||||
return None;
|
||||
}
|
||||
let n = sz[0] as usize;
|
||||
let mut d3 = Vec::with_capacity(n * n * n);
|
||||
// The size comes from the file: an integer lattice size the other lattice readers accept
|
||||
// (2..=129), checked before anything is allocated. Rows are read before they are stored,
|
||||
// so a short file never reserves the table it claims.
|
||||
let n = sz[0];
|
||||
if n.fract() != 0.0 || !(2.0..=MAX_LATTICE as f32).contains(&n) {
|
||||
return None;
|
||||
}
|
||||
let n = n as usize;
|
||||
let mut d3 = Vec::new();
|
||||
for _ in 0..n * n * n {
|
||||
let v = nums(lines.next()?)?;
|
||||
if v.len() != 3 {
|
||||
@@ -194,10 +206,13 @@ pub fn parse_csp(text: &str) -> Option<(Lut, [Vec<(f32, f32)>; 3])> {
|
||||
}
|
||||
d3.push([v[0], v[1], v[2]]);
|
||||
}
|
||||
(n >= 2).then_some((Lut { n1: 0, d1: vec![], n3: n, d3, dmin: [0.0; 3], dmax: [1.0; 3] }, shaper))
|
||||
Some((Lut { n1: 0, d1: vec![], n3: n, d3, dmin: [0.0; 3], dmax: [1.0; 3] }, shaper))
|
||||
} else {
|
||||
let n: usize = lines.next()?.parse().ok()?;
|
||||
let mut d1 = Vec::with_capacity(n);
|
||||
if !(2..=MAX_1D).contains(&n) {
|
||||
return None;
|
||||
}
|
||||
let mut d1 = Vec::new();
|
||||
for _ in 0..n {
|
||||
let v = nums(lines.next()?)?;
|
||||
if v.len() != 3 {
|
||||
@@ -205,7 +220,7 @@ pub fn parse_csp(text: &str) -> Option<(Lut, [Vec<(f32, f32)>; 3])> {
|
||||
}
|
||||
d1.push([v[0], v[1], v[2]]);
|
||||
}
|
||||
(n >= 2).then_some((Lut { n1: n, d1, n3: 0, d3: vec![], dmin: [0.0; 3], dmax: [1.0; 3] }, shaper))
|
||||
Some((Lut { n1: n, d1, n3: 0, d3: vec![], dmin: [0.0; 3], dmax: [1.0; 3] }, shaper))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,6 +179,14 @@ fn lut_files_parse_and_interpolate() {
|
||||
assert!((o[0] - 0.25).abs() < 1e-6 && (o[1] - 0.4).abs() < 1e-6, "{o:?}");
|
||||
let inv = x.apply(o, 2, true, "");
|
||||
assert!((inv[0] - 0.5).abs() < 1e-4, "{inv:?}");
|
||||
// A .csp whose header claims a huge or fractional table is refused before anything is reserved.
|
||||
let head = "CSPLUTV100\n{k}\n\n2\n0 1\n0 1\n2\n0 1\n0 1\n2\n0 1\n0 1\n\n";
|
||||
for (k, size) in [("3D", "100000 100000 100000"), ("3D", "130 130 130"), ("3D", "2.5 2.5 2.5"), ("1D", "4000000000000")] {
|
||||
let text = head.replace("{k}", k) + size + "\n0 0 0\n";
|
||||
assert!(parse_file(&text, "csp").is_none(), "{k} {size}");
|
||||
}
|
||||
// A short file that claims a valid size is refused once its rows run out.
|
||||
assert!(parse_file(&(head.replace("{k}", "3D") + "129 129 129\n0 0 0\n"), "csp").is_none());
|
||||
// CDL collection: pick by id.
|
||||
let ccc = r#"<ColorCorrectionCollection><ColorCorrection id="a"><SOPNode><Slope>2 2 2</Slope><Offset>0 0 0</Offset><Power>1 1 1</Power></SOPNode></ColorCorrection>
|
||||
<ColorCorrection id='b'><SOPNode><Slope>0.5 0.5 0.5</Slope></SOPNode><SatNode><Saturation>1</Saturation></SatNode></ColorCorrection></ColorCorrectionCollection>"#;
|
||||
|
||||
Reference in new issue
Block a user