use crate::util::n_times;
use chrono::FixedOffset;
use dicom_core::header::{DataElementHeader, HasLength, Length, SequenceItemHeader, Tag, VR};
use dicom_core::value::{PrimitiveValue, C};
use dicom_encoding::decode::basic::{BasicDecoder, LittleEndianBasicDecoder};
use dicom_encoding::decode::primitive_value::*;
use dicom_encoding::decode::{BasicDecode, DecodeFrom};
use dicom_encoding::text::{
validate_da, validate_dt, validate_tm, DefaultCharacterSetCodec, DynamicTextCodec,
SpecificCharacterSet, TextCodec, TextValidationOutcome,
};
use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianDecoder;
use dicom_encoding::transfer_syntax::{DynDecoder, TransferSyntax};
use smallvec::smallvec;
use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
use std::fmt::Debug;
use std::io::Read;
use std::iter::Iterator;
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum Error {
#[snafu(display("Decoding in transfer syntax {} is unsupported", ts))]
UnsupportedTransferSyntax {
ts: &'static str,
backtrace: Backtrace,
},
#[snafu(display("Unsupported character set {:?}", charset))]
UnsupportedCharacterSet {
charset: SpecificCharacterSet,
backtrace: Backtrace,
},
#[snafu(display("Attempted to read non-primitive value at position {}", position))]
NonPrimitiveType { position: u64, backtrace: Backtrace },
#[snafu(display(
"Undefined value length of element tagged {} at position {}",
tag,
position
))]
UndefinedValueLength {
tag: Tag,
position: u64,
backtrace: Backtrace,
},
#[snafu(display("Could not decode element header at position {}", position))]
DecodeElementHeader {
position: u64,
#[snafu(backtrace)]
source: dicom_encoding::decode::Error,
},
#[snafu(display("Could not decode element header at position {}", position))]
DecodeItemHeader {
position: u64,
#[snafu(backtrace)]
source: dicom_encoding::decode::Error,
},
#[snafu(display("Could not decode text at position {}", position))]
DecodeText {
position: u64,
#[snafu(backtrace)]
source: dicom_encoding::text::DecodeTextError,
},
#[snafu(display(
"Could not read value from source at position {}: {}",
position,
source
))]
ReadValueData {
position: u64,
source: std::io::Error,
backtrace: Backtrace,
},
#[snafu(display("Failed value deserialization at position {}", position))]
DeserializeValue {
position: u64,
source: dicom_core::value::deserialize::Error,
},
#[snafu(display("Invalid integer value at position {}", position))]
ReadInt {
position: u64,
source: std::num::ParseIntError,
},
#[snafu(display("Invalid float value at position {}", position))]
ReadFloat {
position: u64,
source: std::num::ParseFloatError,
},
#[snafu(display("Invalid Date value element `{}` at position {}", string, position))]
InvalidDateValue {
position: u64,
string: String,
backtrace: Backtrace,
},
#[snafu(display("Invalid Time value element `{}` at position {}", string, position))]
InvalidTimeValue {
position: u64,
string: String,
backtrace: Backtrace,
},
#[snafu(display("Invalid DateTime value element `{}` at position {}", string, position))]
InvalidDateTimeValue {
position: u64,
string: String,
backtrace: Backtrace,
},
}
pub type Result<T> = std::result::Result<T, Error>;
pub trait StatefulDecode {
type Reader: Read;
fn decode_header(&mut self) -> Result<DataElementHeader>;
fn decode_item_header(&mut self) -> Result<SequenceItemHeader>;
fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
fn read_value_preserved(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
fn read_value_bytes(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
fn value_reader(
&mut self,
header: &DataElementHeader,
) -> Result<std::io::Take<&mut Self::Reader>>;
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()>;
fn bytes_read(&self) -> u64;
}
pub type DynStatefulDecoder<'s> =
StatefulDecoder<DynDecoder<dyn Read + 's>, BasicDecoder, Box<dyn Read + 's>, DynamicTextCodec>;
const PARSER_BUFFER_CAPACITY: usize = 2048;
#[derive(Debug)]
pub struct StatefulDecoder<D, BD, S, TC> {
from: S,
decoder: D,
basic: BD,
text: TC,
dt_utc_offset: FixedOffset,
buffer: Vec<u8>,
bytes_read: u64,
}
pub type DicomParser<D, BD, S, TC> = StatefulDecoder<D, BD, S, TC>;
impl<'s> DynStatefulDecoder<'s> {
pub fn new_with<S: 's>(
from: S,
ts: &TransferSyntax,
charset: SpecificCharacterSet,
) -> Result<Self>
where
S: Read,
{
let basic = ts.basic_decoder();
let decoder = ts
.decoder()
.context(UnsupportedTransferSyntax { ts: ts.name() })?;
let text = charset
.codec()
.context(UnsupportedCharacterSet { charset })?;
Ok(DynStatefulDecoder::new(
Box::from(from),
decoder,
basic,
text,
))
}
}
pub type FileHeaderParser<S> = StatefulDecoder<
ExplicitVRLittleEndianDecoder,
LittleEndianBasicDecoder,
S,
DefaultCharacterSetCodec,
>;
impl<S> FileHeaderParser<S>
where
S: Read,
{
pub fn file_header_parser(from: S) -> Self {
DicomParser {
from,
basic: LittleEndianBasicDecoder::default(),
decoder: ExplicitVRLittleEndianDecoder::default(),
text: DefaultCharacterSetCodec,
dt_utc_offset: FixedOffset::east(0),
buffer: Vec::with_capacity(PARSER_BUFFER_CAPACITY),
bytes_read: 0,
}
}
}
impl<D, BD, S, TC> StatefulDecoder<D, BD, S, TC> {
pub fn new(from: S, decoder: D, basic: BD, text: TC) -> StatefulDecoder<D, BD, S, TC> {
DicomParser {
from,
basic,
decoder,
text,
dt_utc_offset: FixedOffset::east(0),
buffer: Vec::with_capacity(PARSER_BUFFER_CAPACITY),
bytes_read: 0,
}
}
}
impl<D, T, BD, S, TC> StatefulDecoder<D, BD, S, TC>
where
D: DecodeFrom<T>,
BD: BasicDecode,
S: std::ops::DerefMut<Target = T> + Read,
T: ?Sized + Read,
TC: TextCodec,
{
fn require_known_length(&self, header: &DataElementHeader) -> Result<usize> {
header
.length()
.get()
.map(|len| len as usize)
.context(UndefinedValueLength {
position: self.bytes_read,
tag: header.tag,
})
}
fn read_value_tag(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let ntags = len >> 2;
let parts: Result<C<Tag>> = n_times(ntags)
.map(|_| {
self.basic
.decode_tag(&mut self.from)
.context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::Tags(parts?))
}
fn read_value_ob(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let mut buf = smallvec![0u8; len];
self.from.read_exact(&mut buf).context(ReadValueData {
position: self.bytes_read,
})?;
self.bytes_read += len as u64;
Ok(PrimitiveValue::U8(buf))
}
fn read_value_strs(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let parts: Result<C<_>> = match header.vr() {
VR::AE | VR::CS | VR::AS => self
.buffer
.split(|v| *v == b'\\')
.map(|slice| {
DefaultCharacterSetCodec.decode(slice).context(DecodeText {
position: self.bytes_read,
})
})
.collect(),
_ => self
.buffer
.split(|v| *v == b'\\')
.map(|slice| {
self.text.decode(slice).context(DecodeText {
position: self.bytes_read,
})
})
.collect(),
};
self.bytes_read += len as u64;
Ok(PrimitiveValue::Strs(parts?))
}
fn read_value_str(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
self.bytes_read += len as u64;
Ok(PrimitiveValue::Str(
self.text.decode(&self.buffer[..]).context(DecodeText {
position: self.bytes_read,
})?,
))
}
fn read_value_ss(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 1;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_ss(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::I16(vec?))
}
fn read_value_fl(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 2;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_fl(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::F32(vec?))
}
fn read_value_da(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let buf = trim_trail_empty_bytes(&self.buffer);
if buf.is_empty() {
return Ok(PrimitiveValue::Empty);
}
if validate_da(buf) != TextValidationOutcome::Ok {
let lossy_str = DefaultCharacterSetCodec
.decode(buf)
.unwrap_or_else(|_| "[byte stream]".to_string());
return InvalidDateValue {
position: self.bytes_read,
string: lossy_str,
}
.fail();
}
let vec: Result<C<_>> = buf
.split(|b| *b == b'\\')
.map(|part| {
Ok(parse_date(part)
.context(DeserializeValue {
position: self.bytes_read,
})?
.0)
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::Date(vec?))
}
fn read_value_ds(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let buf = trim_trail_empty_bytes(&self.buffer);
if buf.is_empty() {
return Ok(PrimitiveValue::Empty);
}
let parts: Result<C<f64>> = buf
.split(|b| *b == b'\\')
.map(|slice| {
let codec = SpecificCharacterSet::Default.codec().unwrap();
let txt = codec.decode(slice).context(DecodeText {
position: self.bytes_read,
})?;
let txt = txt.trim();
txt.parse::<f64>().context(ReadFloat {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::F64(parts?))
}
fn read_value_dt(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let buf = trim_trail_empty_bytes(&self.buffer);
if buf.is_empty() {
return Ok(PrimitiveValue::Empty);
}
if validate_dt(buf) != TextValidationOutcome::Ok {
let lossy_str = DefaultCharacterSetCodec
.decode(buf)
.unwrap_or_else(|_| "[byte stream]".to_string());
return InvalidDateTimeValue {
position: self.bytes_read,
string: lossy_str,
}
.fail();
}
let vec: Result<C<_>> = buf
.split(|b| *b == b'\\')
.map(|part| {
Ok(
parse_datetime(part, self.dt_utc_offset).context(DeserializeValue {
position: self.bytes_read,
})?,
)
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::DateTime(vec?))
}
fn read_value_is(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let buf = trim_trail_empty_bytes(&self.buffer);
if buf.is_empty() {
return Ok(PrimitiveValue::Empty);
}
let parts: Result<C<_>> = buf
.split(|v| *v == b'\\')
.map(|slice| {
let codec = SpecificCharacterSet::Default.codec().unwrap();
let txt = codec.decode(slice).context(DecodeText {
position: self.bytes_read,
})?;
let txt = txt.trim();
txt.parse::<i32>().context(ReadInt {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::I32(parts?))
}
fn read_value_tm(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
self.buffer.resize_with(len, Default::default);
self.from
.read_exact(&mut self.buffer)
.context(ReadValueData {
position: self.bytes_read,
})?;
let buf = trim_trail_empty_bytes(&self.buffer);
if buf.is_empty() {
return Ok(PrimitiveValue::Empty);
}
if validate_tm(buf) != TextValidationOutcome::Ok {
let lossy_str = DefaultCharacterSetCodec
.decode(buf)
.unwrap_or_else(|_| "[byte stream]".to_string());
return InvalidTimeValue {
position: self.bytes_read,
string: lossy_str,
}
.fail();
}
let vec: std::result::Result<C<_>, _> = buf
.split(|b| *b == b'\\')
.map(|part| {
parse_time(part).map(|t| t.0).context(DeserializeValue {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::Time(vec?))
}
fn read_value_od(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 3;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_fd(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::F64(vec?))
}
fn read_value_ul(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 2;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_ul(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::U32(vec?))
}
fn read_value_us(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 1;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_us(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::U16(vec?))
}
fn read_value_uv(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 3;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_uv(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::U64(vec?))
}
fn read_value_sl(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 2;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_sl(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::I32(vec?))
}
fn read_value_sv(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let len = self.require_known_length(header)?;
let n = len >> 3;
let vec: Result<C<_>> = n_times(n)
.map(|_| {
self.basic.decode_sv(&mut self.from).context(ReadValueData {
position: self.bytes_read,
})
})
.collect();
self.bytes_read += len as u64;
Ok(PrimitiveValue::I64(vec?))
}
}
impl<S, T, D, BD> StatefulDecoder<D, BD, S, DynamicTextCodec>
where
D: DecodeFrom<T>,
BD: BasicDecode,
S: std::ops::DerefMut<Target = T> + Read,
T: ?Sized + Read,
{
fn set_character_set(&mut self, charset: SpecificCharacterSet) -> Result<()> {
self.text = charset
.codec()
.context(UnsupportedCharacterSet { charset })?;
Ok(())
}
fn read_value_cs(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
let out = self.read_value_strs(header)?;
let parts = match &out {
PrimitiveValue::Strs(parts) => parts,
_ => unreachable!(),
};
if header.tag == Tag(0x0008, 0x0005) {
if let Some(charset) = parts.first().map(|x| x.as_ref()).and_then(|name| {
SpecificCharacterSet::from_code(name).or_else(|| {
eprintln!("Unsupported character set `{}`, ignoring", name);
None
})
}) {
self.set_character_set(charset)?;
}
}
Ok(out)
}
}
impl<S, T, D, BD> StatefulDecode for StatefulDecoder<D, BD, S, DynamicTextCodec>
where
D: DecodeFrom<T>,
BD: BasicDecode,
S: std::ops::DerefMut<Target = T> + Read,
T: ?Sized + Read,
{
type Reader = S;
fn decode_header(&mut self) -> Result<DataElementHeader> {
self.decoder
.decode_header(&mut self.from)
.context(DecodeElementHeader {
position: self.bytes_read,
})
.map(|(header, bytes_read)| {
self.bytes_read += bytes_read as u64;
header
})
.map_err(From::from)
}
fn decode_item_header(&mut self) -> Result<SequenceItemHeader> {
self.decoder
.decode_item_header(&mut self.from)
.context(DecodeItemHeader {
position: self.bytes_read,
})
.map(|header| {
self.bytes_read += 8;
header
})
.map_err(From::from)
}
fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
if header.length() == Length(0) {
return Ok(PrimitiveValue::Empty);
}
match header.vr() {
VR::SQ => {
NonPrimitiveType {
position: self.bytes_read,
}
.fail()
}
VR::AT => self.read_value_tag(header),
VR::AE | VR::AS | VR::PN | VR::SH | VR::LO | VR::UC | VR::UI => {
self.read_value_strs(header)
}
VR::CS => self.read_value_cs(header),
VR::UT | VR::ST | VR::UR | VR::LT => self.read_value_str(header),
VR::UN | VR::OB => self.read_value_ob(header),
VR::US | VR::OW => self.read_value_us(header),
VR::SS => self.read_value_ss(header),
VR::DA => self.read_value_da(header),
VR::DT => self.read_value_dt(header),
VR::TM => self.read_value_tm(header),
VR::DS => self.read_value_ds(header),
VR::FD | VR::OD => self.read_value_od(header),
VR::FL | VR::OF => self.read_value_fl(header),
VR::IS => self.read_value_is(header),
VR::SL => self.read_value_sl(header),
VR::SV => self.read_value_sv(header),
VR::OL | VR::UL => self.read_value_ul(header),
VR::OV | VR::UV => self.read_value_uv(header),
}
}
fn read_value_preserved(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
if header.length() == Length(0) {
return Ok(PrimitiveValue::Empty);
}
match header.vr() {
VR::SQ => {
NonPrimitiveType {
position: self.bytes_read,
}
.fail()
}
VR::AT => self.read_value_tag(header),
VR::AE
| VR::AS
| VR::PN
| VR::SH
| VR::LO
| VR::UC
| VR::UI
| VR::IS
| VR::DS
| VR::DA
| VR::TM
| VR::DT => self.read_value_strs(header),
VR::CS => self.read_value_cs(header),
VR::UT | VR::ST | VR::UR | VR::LT => self.read_value_str(header),
VR::UN | VR::OB => self.read_value_ob(header),
VR::US | VR::OW => self.read_value_us(header),
VR::SS => self.read_value_ss(header),
VR::FD | VR::OD => self.read_value_od(header),
VR::FL | VR::OF => self.read_value_fl(header),
VR::SL => self.read_value_sl(header),
VR::OL | VR::UL => self.read_value_ul(header),
VR::SV => self.read_value_sv(header),
VR::OV | VR::UV => self.read_value_uv(header),
}
}
fn read_value_bytes(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
if header.length() == Length(0) {
return Ok(PrimitiveValue::Empty);
}
match header.vr() {
VR::SQ => {
NonPrimitiveType {
position: self.bytes_read,
}
.fail()
}
_ => self.read_value_ob(header),
}
}
fn value_reader(
&mut self,
header: &DataElementHeader,
) -> Result<std::io::Take<&mut Self::Reader>> {
match header.vr() {
VR::SQ => {
NonPrimitiveType {
position: self.bytes_read,
}
.fail()
}
_ => Ok(self.from.by_ref().take(
header
.length()
.get()
.map(u64::from)
.unwrap_or(std::u64::MAX),
)),
}
}
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
self.from.read_exact(buf).context(ReadValueData {
position: self.bytes_read,
})?;
self.bytes_read += buf.len() as u64;
Ok(())
}
fn bytes_read(&self) -> u64 {
self.bytes_read
}
}
fn trim_trail_empty_bytes(mut x: &[u8]) -> &[u8] {
while x.last() == Some(&b' ') || x.last() == Some(&b'\0') {
x = &x[..x.len() - 1];
}
x
}
#[cfg(test)]
mod tests {
use super::{StatefulDecode, StatefulDecoder};
use dicom_core::header::{DataElementHeader, HasLength, Header, Length};
use dicom_core::{Tag, VR};
use dicom_encoding::decode::basic::LittleEndianBasicDecoder;
use dicom_encoding::text::{DefaultCharacterSetCodec, DynamicTextCodec};
use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianDecoder;
const RAW: &'static [u8; 62] = &[
0x02, 0x00, 0x02, 0x00, 0x55, 0x49, 0x1a, 0x00, 0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34, 0x30,
0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e,
0x31, 0x2e, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x55, 0x49, 0x14, 0x00, 0x31, 0x2e, 0x32,
0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x31, 0x2e, 0x32, 0x2e,
0x31, 0x00,
];
fn is_stateful_decoder<T>(_: &T)
where
T: StatefulDecode,
{
}
#[test]
fn decode_data_elements() {
let mut cursor = &RAW[..];
let mut decoder = StatefulDecoder::new(
&mut cursor,
ExplicitVRLittleEndianDecoder::default(),
LittleEndianBasicDecoder,
Box::new(DefaultCharacterSetCodec) as DynamicTextCodec,
);
is_stateful_decoder(&decoder);
{
let elem = decoder.decode_header().expect("should find an element");
assert_eq!(elem.tag(), Tag(2, 2));
assert_eq!(elem.vr(), VR::UI);
assert_eq!(elem.length(), Length(26));
assert_eq!(decoder.bytes_read(), 8);
let value = decoder
.read_value(&elem)
.expect("value after element header");
assert_eq!(value.multiplicity(), 1);
assert_eq!(value.string(), Ok("1.2.840.10008.5.1.4.1.1.1\0"));
assert_eq!(decoder.bytes_read(), 8 + 26);
}
{
let elem = decoder.decode_header().expect("should find an element");
assert_eq!(elem.tag(), Tag(2, 16));
assert_eq!(elem.vr(), VR::UI);
assert_eq!(elem.length(), Length(20));
assert_eq!(decoder.bytes_read(), 8 + 26 + 8);
let value = decoder
.read_value(&elem)
.expect("value after element header");
assert_eq!(value.multiplicity(), 1);
assert_eq!(value.string(), Ok("1.2.840.10008.1.2.1\0"));
assert_eq!(decoder.bytes_read(), 8 + 26 + 8 + 20);
}
}
#[test]
fn update_character_set() {
const RAW: &'static [u8; 18] = &[
0x08, 0x00, 0x05, 0x00,
b'C', b'S',
0x0a, 0x00,
b'I', b'S', b'O', b'_', b'I', b'R', b' ', b'1', b'9', b'2',
];
let mut cursor = &RAW[..];
let mut decoder = StatefulDecoder::new(
&mut cursor,
ExplicitVRLittleEndianDecoder::default(),
LittleEndianBasicDecoder,
Box::new(DefaultCharacterSetCodec) as DynamicTextCodec,
);
is_stateful_decoder(&decoder);
let header = decoder
.decode_header()
.expect("should find an element header");
assert_eq!(
header,
DataElementHeader {
tag: Tag(0x0008, 0x0005),
vr: VR::CS,
len: Length(10),
}
);
let value = decoder
.read_value_preserved(&header)
.expect("should read a value");
assert_eq!(value.string(), Ok("ISO_IR 192"));
assert_eq!(decoder.text.name(), "ISO_IR 192",);
}
}