Skip to content

Commit

Permalink
Merge pull request #628 from Enet4/bug/parser/bad_element_to_tokens
Browse files Browse the repository at this point in the history
[parser] Add robustness to data element token writing
  • Loading branch information
Enet4 authored Jan 16, 2025
2 parents 17e26a0 + 8acffa1 commit c0a486d
Showing 1 changed file with 59 additions and 4 deletions.
63 changes: 59 additions & 4 deletions parser/src/dataset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,10 +532,36 @@ where

let token = DataToken::from(header);
match token {
DataToken::SequenceStart { .. } => {
DataToken::SequenceStart { tag, len } => {
// retrieve sequence value, begin item sequence
match elem.into_value() {
Value::Primitive(_) | Value::PixelSequence { .. } => unreachable!(),
v @ Value::Primitive(_) => {
// this can only happen in malformed data (wrong VR),
// but we try to handle it gracefully anyway:
// return a header token instead and continue
// as if it were a primitive value
if len.is_defined() {
tracing::warn!("Unexpected primitive value after header {} with VR SQ", tag);
let adapted_elem = DataElement::new_with_len(tag, VR::SQ, len, v);
(
Some(DataToken::ElementHeader(*adapted_elem.header())),
DataElementTokens::Header(Some(adapted_elem)),
)
} else {
// without a defined length,
// it is too risky to provide any tokens
tracing::warn!("Unexpected primitive value after header {} with VR SQ, ignoring", tag);
(None, DataElementTokens::End)
}
},
Value::PixelSequence { .. } => {
// this is also invalid because
// this is a data element sequence start,
// not a pixel data fragment sequence start.
// stop here and return nothing
tracing::warn!("Unexpected pixel data fragments after header {} with VR SQ, ignored", tag);
(None, DataElementTokens::End)
},
Value::Sequence(seq) => {
let seq = if options.force_invalidate_sq_length {
seq.into_items().into_vec().into()
Expand Down Expand Up @@ -981,8 +1007,7 @@ where
#[cfg(test)]
mod tests {
use dicom_core::{
dicom_value, header::HasLength, DataElement, DataElementHeader, DicomValue, Length,
PrimitiveValue, Tag, VR,
dicom_value, header::HasLength, value::PixelFragmentSequence, DataElement, DataElementHeader, DicomValue, Length, PrimitiveValue, Tag, VR
};

use super::{DataToken, IntoTokens, IntoTokensOptions, LazyDataToken};
Expand Down Expand Up @@ -1280,4 +1305,34 @@ mod tests {

assert_eq!(decoder.position(), 6);
}

/// A malformed data element (wrong VR) should not panic
/// when converting it to tokens
#[test]
fn bad_element_to_tokens() {
let e: DataElement = DataElement::new_with_len(
Tag(0x0008, 0x0080),
VR::SQ, // wrong VR
Length(6),
PrimitiveValue::from("Oops!"),
);

// should not panic
let tokens = e.into_tokens().collect::<Vec<_>>();
// still expects 2 tokens (header + value)
assert_eq!(tokens.len(), 2);

let e: DataElement = DataElement::new(
Tag(0x7FE0, 0x0010),
VR::SQ, // wrong VR
PixelFragmentSequence::new_fragments(vec![
// one fragment
vec![0x55; 128]
]),
);

// should not panic,
// other than that there are no guarantees about the output
let _ = e.into_tokens().collect::<Vec<_>>();
}
}

0 comments on commit c0a486d

Please sign in to comment.