nitf_rs/
types.rs

1//! Common types use throughout
2use log::{trace, warn};
3use memmap2::{Mmap, MmapOptions};
4use std::fmt::{Debug, Display};
5use std::io::{Read, Seek, Write};
6use std::ops::Deref;
7use std::str::FromStr;
8
9use crate::headers::NitfSegmentHeader;
10use crate::{NitfError, NitfResult};
11
12/// Lowest level object for file parsing
13#[derive(Default, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
14pub struct NitfField<V: FromStr + Debug + Default + Display> {
15    /// Parsed representation of value
16    pub val: V,
17    /// Number of bytes used to store value in file
18    pub length: usize,
19    /// Name of field
20    pub name: String,
21}
22
23/// Provide default field implementations.
24impl<V> NitfField<V>
25where
26    V: FromStr + Debug + Default + Display,
27    <V as FromStr>::Err: Debug,
28{
29    pub fn init(length: u8, name: &str) -> Self {
30        Self {
31            val: V::default(),
32            length: length.into(),
33            name: name.to_string(),
34        }
35    }
36    // Reading/Writing
37
38    /// Read the specified number of bytes and parse the value of a given field
39    pub fn read(&mut self, reader: &mut (impl Read + Seek)) -> NitfResult<()> {
40        let mut bytes = vec![0; self.length];
41        let string;
42
43        // Crash if something goes wrong with the cursor
44        let offset = reader
45            .stream_position()
46            .or(Err(NitfError::ReadFatal(self.name.clone())))?;
47
48        // Crash if there is an error reading the bytes
49        reader
50            .read_exact(&mut bytes)
51            .or(Err(NitfError::ReadFatal(self.name.clone())))?;
52
53        // Try to read the bytes to a string
54        match String::from_utf8(bytes.to_vec()) {
55            // If it's ok, trim and try to parse to enum/native representation
56            Ok(str) => {
57                string = str.clone();
58                // Warn and assign a default value if error parsing
59                self.val = str.trim().parse().unwrap_or_else(|e| {
60                    warn!("Non-fatal error parsing {}: {e:?}", self.name);
61                    V::default()
62                });
63            }
64
65            Err(_) => {
66                string = "Error parsing to string".to_string();
67                warn!("Failed to parse {} from bytes: {bytes:?}", self.name);
68            }
69        }
70        trace!("Read {} at offset {offset}: {string}", self.name);
71        Ok(())
72    }
73
74    pub fn write(&self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
75        let buf = format!("{:<1$}", self.val.to_string(), self.length);
76        let offset = writer.stream_position()?;
77        trace!(
78            "Wrote {} bytes for {} at offset {offset}: {buf}",
79            buf.len(),
80            self.name
81        );
82        writer.write(buf.as_bytes()).map_err(NitfError::IOError)
83    }
84}
85
86impl<V: FromStr + Debug + Default + Display> Display for NitfField<V> {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        write!(
89            f,
90            "{}: {:<2$}",
91            self.name,
92            self.val.to_string(),
93            self.length
94        )
95    }
96}
97
98#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord)]
99pub struct NitfSegment<T: NitfSegmentHeader> {
100    /// Header fields defined in module
101    pub header: T,
102    /// Segment data offset
103    pub header_offset: u64,
104    /// Segment data size
105    pub data_size: u64,
106    /// Segment data offset
107    pub data_offset: u64,
108}
109impl<T: NitfSegmentHeader> NitfSegment<T> {
110    pub(crate) fn read(reader: &mut (impl Read + Seek), data_size: u64) -> NitfResult<Self> {
111        let header_offset = reader.stream_position()?;
112        let header = T::from_reader(reader)?;
113        let data_offset = reader.stream_position()?;
114
115        // Seek to end of data for next segment to be read
116        reader.seek(std::io::SeekFrom::Start(data_offset + data_size))?;
117        Ok(Self {
118            header,
119            header_offset,
120            data_size,
121            data_offset,
122        })
123    }
124
125    /// Write segment header to file
126    pub(crate) fn write_header(&mut self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
127        writer.seek(std::io::SeekFrom::Start(self.header_offset))?;
128        let bytes_written = self.header.write(writer)?;
129        self.data_offset = writer.stream_position()?;
130        Ok(bytes_written)
131    }
132
133    /// Memory-map the data from this segment.
134    pub fn get_data_map(&self, reader: &mut std::fs::File) -> NitfResult<Mmap> {
135        if self.data_offset == 0 {
136            Err(NitfError::Fatal(
137                "Data offset location is not set. Cannot read data".to_string(),
138            ))?
139        }
140        let mut opts = MmapOptions::new();
141        Ok(unsafe {
142            opts.len(self.data_size as usize)
143                .offset(self.data_offset)
144                .map(reader.deref())
145        }?)
146    }
147    /// Write segment data to file. Assumes cursor is in correct position
148    pub fn write_data(&self, writer: &mut (impl Write + Seek), data: &[u8]) -> NitfResult<usize> {
149        writer.seek(std::io::SeekFrom::Start(self.data_offset))?;
150        writer.write(data).map_err(NitfError::IOError)
151    }
152    pub fn length(&self) -> usize {
153        self.header.length() + self.data_size as usize
154    }
155}
156impl<T: NitfSegmentHeader + Display> Display for NitfSegment<T> {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        write!(f, "{}", self.header)
159    }
160}
161/// Standard security metadata
162#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
163pub struct Security {
164    /// File Security Classification
165    pub clas: NitfField<Classification>,
166    /// File Classification Security System
167    pub clsy: NitfField<String>, // TODO: Check value registry
168    /// File Codewords
169    pub code: NitfField<String>,
170    /// File Control and Handling
171    pub ctlh: NitfField<String>,
172    /// File Releasing Instructions
173    pub rel: NitfField<String>,
174    /// File Declassification Type
175    pub dctp: NitfField<DeclassificationType>,
176    /// File Declassification Date
177    pub dcdt: NitfField<String>,
178    /// File Declassification Exemption
179    pub dcxm: NitfField<DeclassificationExemption>,
180    /// File Downgrade
181    pub dg: NitfField<Downgrade>,
182    /// File Downgrade Date
183    pub dgdt: NitfField<String>,
184    /// File Classification Text
185    pub cltx: NitfField<String>,
186    /// File Classification Authority Type
187    pub catp: NitfField<ClassificationAuthorityType>,
188    /// File Classification Authority
189    pub caut: NitfField<String>,
190    /// File Classification Reason
191    pub crsn: NitfField<ClassificationReason>, // TODO: Check value registry
192    /// File Security Source Date
193    pub srdt: NitfField<String>,
194    /// File Security Control Number
195    pub ctln: NitfField<String>,
196}
197
198impl Default for Security {
199    fn default() -> Self {
200        Self {
201            clas: NitfField::init(1u8, "CLAS"),
202            clsy: NitfField::init(2u8, "CLSY"),
203            code: NitfField::init(11u8, "CODE"),
204            ctlh: NitfField::init(2u8, "CTLH"),
205            rel: NitfField::init(20u8, "REL"),
206            dctp: NitfField::init(2u8, "DCTP"),
207            dcdt: NitfField::init(8u8, "DCDT"),
208            dcxm: NitfField::init(4u8, "DCXM"),
209            dg: NitfField::init(1u8, "DG"),
210            dgdt: NitfField::init(8u8, "DGDT"),
211            cltx: NitfField::init(43u8, "CLTX"),
212            catp: NitfField::init(1u8, "CATP"),
213            caut: NitfField::init(40u8, "CAUT"),
214            crsn: NitfField::init(1u8, "CRSN"),
215            srdt: NitfField::init(8u8, "SRDT"),
216            ctln: NitfField::init(15u8, "CTLN"),
217        }
218    }
219}
220
221impl Security {
222    pub fn read(&mut self, reader: &mut (impl Read + Seek)) -> NitfResult<()> {
223        self.clas.read(reader)?;
224        self.clsy.read(reader)?;
225        self.code.read(reader)?;
226        self.ctlh.read(reader)?;
227        self.rel.read(reader)?;
228        self.dctp.read(reader)?;
229        self.dcdt.read(reader)?;
230        self.dcxm.read(reader)?;
231        self.dg.read(reader)?;
232        self.dgdt.read(reader)?;
233        self.cltx.read(reader)?;
234        self.catp.read(reader)?;
235        self.caut.read(reader)?;
236        self.crsn.read(reader)?;
237        self.srdt.read(reader)?;
238        self.ctln.read(reader)?;
239        Ok(())
240    }
241    pub fn write(&self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
242        let mut bytes_written = 0;
243        bytes_written += self.clas.write(writer)?;
244        bytes_written += self.clsy.write(writer)?;
245        bytes_written += self.code.write(writer)?;
246        bytes_written += self.ctlh.write(writer)?;
247        bytes_written += self.rel.write(writer)?;
248        bytes_written += self.dctp.write(writer)?;
249        bytes_written += self.dcdt.write(writer)?;
250        bytes_written += self.dcxm.write(writer)?;
251        bytes_written += self.dg.write(writer)?;
252        bytes_written += self.dgdt.write(writer)?;
253        bytes_written += self.cltx.write(writer)?;
254        bytes_written += self.catp.write(writer)?;
255        bytes_written += self.caut.write(writer)?;
256        bytes_written += self.crsn.write(writer)?;
257        bytes_written += self.srdt.write(writer)?;
258        bytes_written += self.ctln.write(writer)?;
259        Ok(bytes_written)
260    }
261    /// Sum of all security fields
262    pub fn length(&self) -> usize {
263        167
264    }
265}
266impl Display for Security {
267    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268        let mut out_str = String::default();
269        out_str += &format!("{}, ", self.clas);
270        out_str += &format!("{}, ", self.clsy);
271        out_str += &format!("{}, ", self.code);
272        out_str += &format!("{}, ", self.ctlh);
273        out_str += &format!("{}, ", self.rel);
274        out_str += &format!("{}, ", self.dctp);
275        out_str += &format!("{}, ", self.dcdt);
276        out_str += &format!("{}, ", self.dcxm);
277        out_str += &format!("{}, ", self.dg);
278        out_str += &format!("{}, ", self.dgdt);
279        out_str += &format!("{}, ", self.cltx);
280        out_str += &format!("{}, ", self.catp);
281        out_str += &format!("{}, ", self.caut);
282        out_str += &format!("{}, ", self.crsn);
283        out_str += &format!("{}, ", self.srdt);
284        out_str += &format!("{}", self.ctln);
285        write!(f, "{out_str}")
286    }
287}
288
289/// Classification codes
290#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
291pub enum Classification {
292    #[default]
293    /// Unclassified
294    U,
295    /// Top Secret
296    T,
297    /// Secret
298    S,
299    /// Confidential
300    C,
301    /// Restricted
302    R,
303}
304impl FromStr for Classification {
305    type Err = NitfError;
306    fn from_str(s: &str) -> Result<Self, Self::Err> {
307        match s {
308            "U" => Ok(Self::U),
309            "T" => Ok(Self::T),
310            "S" => Ok(Self::S),
311            "C" => Ok(Self::C),
312            "R" => Ok(Self::R),
313            _ => Err(NitfError::ParseError("Classification".to_string())),
314        }
315    }
316}
317impl Display for Classification {
318    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319        match self {
320            Self::U => write!(f, "U"),
321            Self::T => write!(f, "T"),
322            Self::S => write!(f, "S"),
323            Self::C => write!(f, "C"),
324            Self::R => write!(f, "R"),
325        }
326    }
327}
328/// Declassification codes
329#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
330pub enum DeclassificationType {
331    #[default]
332    /// Default value, two spaces
333    DEFAULT,
334    /// Declassify on specific date
335    DD,
336    /// Declassify on occurrence of event
337    DE,
338    /// Downgrade to specified level on specific date
339    GD,
340    /// Downgrade to specified level on occurrence of event
341    GE,
342    /// OADR
343    O,
344    /// Exempt from automatic declassification
345    X,
346}
347impl FromStr for DeclassificationType {
348    type Err = NitfError;
349    fn from_str(s: &str) -> Result<Self, Self::Err> {
350        match s {
351            "" => Ok(Self::DEFAULT),
352            "DD" => Ok(Self::DD),
353            "DE" => Ok(Self::DE),
354            "GD" => Ok(Self::GD),
355            "GE" => Ok(Self::GE),
356            "O" => Ok(Self::O),
357            "X" => Ok(Self::X),
358            _ => Err(NitfError::ParseError("DeclassificationType".to_string())),
359        }
360    }
361}
362impl Display for DeclassificationType {
363    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364        match self {
365            Self::DEFAULT => write!(f, "  "),
366            Self::DD => write!(f, "DD"),
367            Self::DE => write!(f, "DE"),
368            Self::GD => write!(f, "GD"),
369            Self::GE => write!(f, "GE"),
370            Self::O => write!(f, "O"),
371            Self::X => write!(f, "X"),
372        }
373    }
374}
375
376///  Declassification exemption
377#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
378pub enum DeclassificationExemption {
379    #[default]
380    /// Default value, four spaces
381    DEFAULT,
382    /// Valid values
383    DExX1,
384    DExX2,
385    DExX3,
386    DExX4,
387    DExX5,
388    DExX6,
389    DExX7,
390    DExX8,
391    DEx25X1,
392    DEx25X2,
393    DEx25X3,
394    DEx25X4,
395    DEx25X5,
396    DEx25X6,
397    DEx25X7,
398    DEx25X8,
399    DEx25X9,
400    DExDN10,
401    DExDNI,
402}
403impl FromStr for DeclassificationExemption {
404    type Err = NitfError;
405    fn from_str(s: &str) -> Result<Self, Self::Err> {
406        match s {
407            "" => Ok(Self::DEFAULT),
408            "X1" => Ok(Self::DExX1),     // DOD 5200.01-V1, 4-201b(1)
409            "X2" => Ok(Self::DExX2),     // DOD 5200.01-V1, 4-201b(2)
410            "X3" => Ok(Self::DExX3),     // DOD 5200.01-V1, 4-201b(3)
411            "X4" => Ok(Self::DExX4),     // DOD 5200.01-V1, 4-201b(4)
412            "X5" => Ok(Self::DExX5),     // DOD 5200.01-V1, 4-201b(5)
413            "X6" => Ok(Self::DExX6),     // DOD 5200.01-V1, 4-201b(6)
414            "X7" => Ok(Self::DExX7),     // DOD 5200.01-V1, 4-201b(7)
415            "X8" => Ok(Self::DExX8),     // DOD 5200.01-V1, 4-201b(8)
416            "25X1" => Ok(Self::DEx25X1), // DOD 5200.01-V1, 4-301b(1)
417            "25X2" => Ok(Self::DEx25X2), // DOD 5200.01-V1, 4-301b(2)
418            "25X3" => Ok(Self::DEx25X3), // DOD 5200.01-V1, 4-301b(3)
419            "25X4" => Ok(Self::DEx25X4), // DOD 5200.01-V1, 4-301b(4)
420            "25X5" => Ok(Self::DEx25X5), // DOD 5200.01-V1, 4-301b(5)
421            "25X6" => Ok(Self::DEx25X6), // DOD 5200.01-V1, 4-301b(6)
422            "25X7" => Ok(Self::DEx25X7), // DOD 5200.01-V1, 4-301b(7)
423            "25X8" => Ok(Self::DEx25X8), // DOD 5200.01-V1, 4-301b(8)
424            "25X9" => Ok(Self::DEx25X9), // DOD 5200.01-V1, 4-301b(9)
425            "DN10" => Ok(Self::DExDN10),
426            "DNI" => Ok(Self::DExDNI),
427            _ => Err(NitfError::ParseError(
428                "DeclassificationExemption".to_string(),
429            )),
430        }
431    }
432}
433impl Display for DeclassificationExemption {
434    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435        match self {
436            Self::DEFAULT => write!(f, ""),
437            Self::DExX1 => write!(f, "X1"),
438            Self::DExX2 => write!(f, "X2"),
439            Self::DExX3 => write!(f, "X3"),
440            Self::DExX4 => write!(f, "X4"),
441            Self::DExX5 => write!(f, "X5"),
442            Self::DExX6 => write!(f, "X6"),
443            Self::DExX7 => write!(f, "X7"),
444            Self::DExX8 => write!(f, "X8"),
445            Self::DEx25X1 => write!(f, "25X1"),
446            Self::DEx25X2 => write!(f, "25X2"),
447            Self::DEx25X3 => write!(f, "25X3"),
448            Self::DEx25X4 => write!(f, "25X4"),
449            Self::DEx25X5 => write!(f, "25X5"),
450            Self::DEx25X6 => write!(f, "25X6"),
451            Self::DEx25X7 => write!(f, "25X7"),
452            Self::DEx25X8 => write!(f, "25X8"),
453            Self::DEx25X9 => write!(f, "25X9"),
454            Self::DExDN10 => write!(f, "DN10"),
455            Self::DExDNI => write!(f, "DNI"),
456        }
457    }
458}
459
460/// Downgrade classification
461#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
462pub enum Downgrade {
463    #[default]
464    /// Default value, two spaces
465    DEFAULT,
466    /// Secret
467    S,
468    /// Confidential
469    C,
470    /// Restricted
471    R,
472}
473impl FromStr for Downgrade {
474    type Err = NitfError;
475    fn from_str(s: &str) -> Result<Self, Self::Err> {
476        match s {
477            "" => Ok(Self::DEFAULT),
478            "S" => Ok(Self::S),
479            "C" => Ok(Self::C),
480            "R" => Ok(Self::R),
481            _ => Err(NitfError::ParseError("Downgrade".to_string())),
482        }
483    }
484}
485impl Display for Downgrade {
486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
487        match self {
488            Self::DEFAULT => write!(f, ""),
489            Self::S => write!(f, "S"),
490            Self::C => write!(f, "C"),
491            Self::R => write!(f, "R"),
492        }
493    }
494}
495
496/// Classification authority
497#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
498pub enum ClassificationAuthorityType {
499    #[default]
500    /// Default, one space
501    DEFAULT,
502    /// Original classification authority
503    O,
504    /// Derivative from a single source
505    D,
506    /// Derivative from multiple sources
507    M,
508}
509impl FromStr for ClassificationAuthorityType {
510    type Err = NitfError;
511    fn from_str(s: &str) -> Result<Self, Self::Err> {
512        match s {
513            "" => Ok(Self::DEFAULT),
514            "O" => Ok(Self::O),
515            "D" => Ok(Self::D),
516            "M" => Ok(Self::M),
517            _ => Err(NitfError::ParseError(
518                "ClassificationAuthorityType".to_string(),
519            )),
520        }
521    }
522}
523impl Display for ClassificationAuthorityType {
524    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
525        match self {
526            Self::DEFAULT => write!(f, ""),
527            Self::O => write!(f, "O"),
528            Self::D => write!(f, "D"),
529            Self::M => write!(f, "M"),
530        }
531    }
532}
533
534/// Reason for classification
535#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
536pub enum ClassificationReason {
537    #[default]
538    /// Default value, one space
539    DEFAULT,
540    /// Valid values
541    A,
542    B,
543    C,
544    D,
545    E,
546    F,
547    G,
548    H,
549}
550impl FromStr for ClassificationReason {
551    type Err = NitfError;
552    fn from_str(s: &str) -> Result<Self, Self::Err> {
553        match s {
554            "" => Ok(Self::DEFAULT),
555            "A" => Ok(Self::A),
556            "B" => Ok(Self::B),
557            "C" => Ok(Self::C),
558            "D" => Ok(Self::D),
559            "E" => Ok(Self::E),
560            "F" => Ok(Self::F),
561            "G" => Ok(Self::G),
562            "H" => Ok(Self::H),
563            _ => Err(NitfError::ParseError("ClassificationReason".to_string())),
564        }
565    }
566}
567impl Display for ClassificationReason {
568    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
569        match self {
570            Self::DEFAULT => write!(f, ""),
571            Self::A => write!(f, "A"),
572            Self::B => write!(f, "B"),
573            Self::C => write!(f, "C"),
574            Self::D => write!(f, "D"),
575            Self::E => write!(f, "E"),
576            Self::F => write!(f, "F"),
577            Self::G => write!(f, "G"),
578            Self::H => write!(f, "H"),
579        }
580    }
581}
582
583/// Extended sub-header TRE data type
584#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
585pub struct ExtendedSubheader {
586    /// User defined tagged record entries (TREs)
587    tre: Vec<u8>,
588    /// Length of subheader
589    size: usize,
590    /// Name of subheader
591    pub name: String,
592}
593impl ExtendedSubheader {
594    /// Get `tre`
595    pub fn tre(&self) -> &Vec<u8> {
596        &self.tre
597    }
598    /// Get `size`
599    pub fn size(&self) -> &usize {
600        &self.size
601    }
602    pub fn init(name: &str) -> Self {
603        Self {
604            tre: vec![],
605            size: 0,
606            name: name.to_string(),
607        }
608    }
609    /// Updates the TRE byte vector and size field.
610    pub fn set_tre(&mut self, new_tre: Vec<u8>) {
611        self.size = new_tre.len();
612        self.tre = new_tre;
613    }
614    pub fn read(&mut self, reader: &mut (impl Read + Seek), n_bytes: usize) -> NitfResult<()> {
615        self.size = n_bytes;
616        self.tre = vec![0; n_bytes];
617        trace!("Reading: {}", self.name);
618        reader
619            .read_exact(self.tre.as_mut_slice())
620            .map_err(NitfError::IOError)
621    }
622    pub fn write(&self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
623        trace!("Writing: {}", self.name);
624        writer
625            .write(self.tre.as_slice())
626            .map_err(NitfError::IOError)
627    }
628}
629impl Display for ExtendedSubheader {
630    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631        // Can't copy vector directly, convert to slice, then clone into new vector
632        let out_str = String::from_utf8(self.tre.to_vec()).or(Err(std::fmt::Error))?;
633        write!(f, "{}: [{out_str}], ", self.name)
634    }
635}