Reject signed row numbers in XLSX cell references

Found while testing crates/textimport/src/xlsx.rs:15

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilverandClaude Haiku 5.5 committed 2026-11-08 18:14:57 +01:00
1 parent 2e9b46c1d5
commit 5da2393e28
1 file changed
+14 -1
+14 -1
View File
@@ -12,7 +12,11 @@ use crate::{ImportError, Imported};
/// "B12" → (row 11, column 1).
fn cell_ref(r: &str) -> Option<(usize, usize)> {
let letters: String = r.chars().take_while(char::is_ascii_alphabetic).collect();
let row: usize = r[letters.len()..].parse().ok()?;
let digits = &r[letters.len()..];
if !digits.bytes().all(|b| b.is_ascii_digit()) {
return None;
}
let row: usize = digits.parse().ok()?;
let col = letters.chars().try_fold(0usize, |acc, c| {
let digit = (c.to_ascii_uppercase() as u8).checked_sub(b'A')? as usize + 1;
acc.checked_mul(26)?.checked_add(digit)
@@ -331,6 +335,15 @@ mod tests {
buf.into_inner()
}
#[test]
fn cell_ref_rejects_signed_or_malformed_rows() {
assert_eq!(cell_ref("B12"), Some((11, 1)));
assert_eq!(cell_ref("A+1"), None);
assert_eq!(cell_ref("A-1"), None);
assert_eq!(cell_ref("A"), None);
assert_eq!(cell_ref("A1x"), None);
}
/// A `t="s"` cell materialises its own copy of the shared string, so one big string with many
/// references multiplies: the audit's case is a 1 MB string and 3M cells, terabytes, built
/// before the grid cap applies (#1584). Collection now carries its own byte budget.