Skip to content

Commit

Permalink
vcf/io/writer/header/record/value: Validate unstructured header recor…
Browse files Browse the repository at this point in the history
…d value

This disallows unstructured header record values to be empty or start
with a structured header record marker (`<`). See _The Variant Call
Format Specification: VCFv4.4 and BCFv2.2_ (2024-04-20) § 1.4
"Meta-information lines".
  • Loading branch information
zaeleus committed May 31, 2024
1 parent 3727fff commit 970bbca
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
6 changes: 6 additions & 0 deletions noodles-vcf/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
header line by line. This makes it so that it is no longer required to read
the entire raw header into memory before parsing.

* vcf/io/writer/header/record/value: Disallow unstructured header records to
be empty or start with a structured header record marker (`<`).

See _The Variant Call Format Specification: VCFv4.4 and BCFv2.2_
(2024-04-20) § 1.4 "Meta-information lines".

* vcf/io/writer/record/reference_bases: Resolve IUPAC ambiguity codes
([#268]).

Expand Down
42 changes: 41 additions & 1 deletion noodles-vcf/src/io/writer/header/record/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,45 @@ pub(super) fn write_string<W>(writer: &mut W, s: &str) -> io::Result<()>
where
W: Write,
{
writer.write_all(s.as_bytes())
// § 1.4 "Meta-information lines" (2024-04-20): "An _unstructured_ meta-information line
// consists of [...] a _value_ (which may not be empty and must not start with a '<'
// character)..."
fn is_valid(s: &str) -> bool {
const LESS_THAN_SIGN: char = '<';
s.chars().next().is_some_and(|c| c != LESS_THAN_SIGN)
}

if is_valid(s) {
writer.write_all(s.as_bytes())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"invalid unstructured header record value",
))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_write_string() -> io::Result<()> {
let mut buf = Vec::new();

write_string(&mut buf, "ndls")?;
assert_eq!(buf, b"ndls");

assert!(matches!(
write_string(&mut buf, ""),
Err(e) if e.kind() == io::ErrorKind::InvalidInput
));

assert!(matches!(
write_string(&mut buf, "<"),
Err(e) if e.kind() == io::ErrorKind::InvalidInput
));

Ok(())
}
}

0 comments on commit 970bbca

Please sign in to comment.