1use memmap2::Mmap;
8use ndarray::{azip, par_azip, Array2, ArrayView2};
9use quick_xml::DeError;
10use std::fs::File;
11use std::path::Path;
12use std::slice::from_raw_parts;
13use std::str::{from_utf8, FromStr, Utf8Error};
14use zerocopy::{BE, F32};
15
16use num_complex::{Complex, Complex32};
17use quick_xml::de::from_str;
18use serde::Deserialize;
19use thiserror::Error;
20
21use nitf_rs::{Nitf, NitfError};
22
23pub mod dep;
24pub mod v1_3_0;
25
26pub fn read_sicd(path: &Path) -> Result<Sicd, SicdError> {
44 let file = File::open(path)?;
45 Sicd::from_file(file)
46}
47
48#[derive(Error, Debug)]
49pub enum SicdError {
50 #[error("unknown sicd version {0}")]
52 VersionError(String),
53 #[error("metadata for version {0} is not implemented")]
55 Unimpl(String),
56 #[error("file does not appear to be a SICD")]
57 NotASicd,
58 #[error(transparent)]
60 IOError(#[from] std::io::Error),
61 #[error(transparent)]
62 NitfError(#[from] NitfError),
63 #[error(transparent)]
64 UTF8(#[from] Utf8Error),
65 #[error(transparent)]
66 DESER(#[from] DeError),
67}
68
69pub struct Sicd<'a> {
73 pub nitf: Nitf,
75 pub meta: SicdMeta,
77 pub version: SicdVersion,
79 pub image_data: Vec<ImageData<'a>>,
81}
82
83#[derive(Debug)]
85pub struct ImageData<'a> {
86 pub array: ArrayView2<'a, Complex<F32<BE>>>,
88 _mmap: Mmap,
90}
91
92impl<'a> ImageData<'a> {
93 fn initialize(mmap: Mmap, n_rows: usize, n_cols: usize) -> Self {
94 let byte_slice_len = mmap.len();
95 let new_size = byte_slice_len / std::mem::size_of::<Complex<F32<BE>>>();
96 let f32_ptr = mmap.as_ptr() as *const Complex<F32<BE>>;
97 let float_slice = unsafe { from_raw_parts(f32_ptr, new_size) };
98 let array = ArrayView2::from_shape((n_rows, n_cols), float_slice).unwrap();
99 Self { array, _mmap: mmap }
100 }
101}
102pub trait ToNative {
103 fn to_native(&self) -> Array2<Complex32>;
105 fn par_to_native(&self) -> Array2<Complex32>;
107}
108
109impl<'a> ToNative for ArrayView2<'a, Complex<F32<BE>>> {
110 fn to_native(&self) -> Array2<Complex32> {
111 let mut out = Array2::from_elem((self.nrows(), self.ncols()), Complex32::default());
112 azip!((be in self, ne in &mut out) {
113 ne.re = be.re.get();
114 ne.im = be.im.get();
115 });
116 out
117 }
118
119 fn par_to_native(&self) -> Array2<Complex32> {
120 let mut out = Array2::from_elem((self.nrows(), self.ncols()), Complex32::default());
121 par_azip!((be in self, ne in &mut out) {
122 ne.re = be.re.get();
123 ne.im = be.im.get();
124 });
125 out
126 }
127}
128
129#[derive(Debug, Deserialize, PartialEq)]
130pub enum SicdVersion {
131 V0_3_1,
132 V0_4_0,
133 V0_4_1,
134 V0_5_0,
135 V1_0_0,
136 V1_0_1,
137 V1_1_0,
138 V1_2_0,
139 V1_2_1,
140 V1_3_0,
141}
142
143impl FromStr for SicdVersion {
144 type Err = SicdError;
145 fn from_str(s: &str) -> Result<Self, Self::Err> {
146 match s.split("urn:SICD:").collect::<String>().as_str() {
147 "0.3.1" => Ok(SicdVersion::V0_3_1),
148 "0.4.0" => Ok(SicdVersion::V0_4_0),
149 "0.4.1" => Ok(SicdVersion::V0_4_1),
150 "0.5.0" => Ok(SicdVersion::V0_5_0),
151 "1.0.0" => Ok(SicdVersion::V1_0_0),
152 "1.0.1" => Ok(SicdVersion::V1_0_1),
153 "1.1.0" => Ok(SicdVersion::V1_1_0),
154 "1.2.0" => Ok(SicdVersion::V1_2_0),
155 "1.2.1" => Ok(SicdVersion::V1_2_1),
156 "1.3.0" => Ok(SicdVersion::V1_3_0),
157 _ => Err(SicdError::VersionError(s.to_string())),
158 }
159 }
160}
161
162#[derive(Debug)]
163pub enum SicdMeta {
164 V0_3_1, V0_4_0(dep::v0_4_0::SicdMeta),
166 V0_4_1, V0_5_0(dep::v0_5_0::SicdMeta),
168 V1(v1_3_0::SicdMeta),
169}
170
171impl SicdMeta {
172 pub fn get_v0_3_1_meta(self) -> SicdError {
173 SicdError::Unimpl("0.3.1".to_string())
174 }
175 pub fn get_v0_4_0_meta(self) -> Option<dep::v0_4_0::SicdMeta> {
176 match self {
177 Self::V0_4_0(meta) => Some(meta),
178 _ => None,
179 }
180 }
181 pub fn get_v0_4_1_meta(self) -> SicdError {
182 SicdError::Unimpl("0.4.1".to_string())
183 }
184 pub fn get_v0_5_0_meta(self) -> Option<dep::v0_5_0::SicdMeta> {
185 match self {
186 Self::V0_5_0(meta) => Some(meta),
187 _ => None,
188 }
189 }
190 pub fn get_v1_meta(self) -> Option<v1_3_0::SicdMeta> {
191 match self {
192 Self::V1(meta) => Some(meta),
193 _ => None,
194 }
195 }
196}
197impl<'a> Sicd<'a> {
198 pub fn from_file(mut file: File) -> Result<Self, SicdError> {
199 let nitf = Nitf::from_reader(&mut file)?;
200 if nitf.nitf_header.numdes.val == 0 {
201 return Err(SicdError::NotASicd)
202 }
203 let dex_data = nitf.data_extension_segments[0].get_data_map(&mut file)?;
204 let sicd_str = from_utf8(&dex_data[..])?;
205 let (version, meta) = parse_sicd(sicd_str)?;
206
207 let image_data: Vec<_> = nitf
208 .image_segments
209 .iter()
210 .map(|seg| {
211 ImageData::initialize(
212 seg.get_data_map(&mut file).unwrap(),
213 seg.header.nrows.val as usize,
214 seg.header.ncols.val as usize,
215 )
216 })
217 .collect();
218
219 Ok(Self {
220 nitf,
221 meta,
222 version,
223 image_data,
224 })
225 }
226}
227
228#[derive(Debug, Deserialize, PartialEq, Clone)]
229struct VersionGetter {
230 #[serde(rename = "@xmlns")]
231 pub version: String,
232}
233
234fn parse_sicd(sicd_str: &str) -> Result<(SicdVersion, SicdMeta), SicdError> {
235 let tmp: VersionGetter = from_str(sicd_str)?;
237 let sicd_version = SicdVersion::from_str(&tmp.version)?;
238 use SicdError::Unimpl;
239 match sicd_version {
240 SicdVersion::V0_3_1 => Err(Unimpl("V0_3_1".to_string())),
241 SicdVersion::V0_4_0 => Ok((SicdVersion::V0_4_0, SicdMeta::V0_4_0(from_str(sicd_str)?))),
242 SicdVersion::V0_4_1 => Err(Unimpl("V0_4_1".to_string())),
243 SicdVersion::V0_5_0 => Ok((SicdVersion::V0_5_0, SicdMeta::V0_5_0(from_str(sicd_str)?))),
244 other => Ok((other, SicdMeta::V1(from_str(sicd_str)?))),
246 }
247}