use crate::{raw, Error, Result};
const REGULAR_HEADER_SIZE: usize = 54;
const EXTENDED_HEADER_SIZE: usize = 60;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Vlr {
pub user_id: String,
pub record_id: u16,
pub description: String,
pub data: Vec<u8>,
}
impl Vlr {
pub fn new(raw_vlr: raw::Vlr) -> Vlr {
use crate::utils::AsLasStr;
Vlr {
user_id: raw_vlr.user_id.as_ref().as_las_string_lossy(),
record_id: raw_vlr.record_id,
description: raw_vlr.description.as_ref().as_las_string_lossy(),
data: raw_vlr.data,
}
}
pub fn into_raw(self, is_extended: bool) -> Result<raw::Vlr> {
use crate::utils::FromLasStr;
let mut user_id = [0; 16];
user_id.as_mut().from_las_str(&self.user_id)?;
let mut description = [0; 32];
description.as_mut().from_las_str(&self.description)?;
Ok(raw::Vlr {
reserved: 0,
user_id,
record_id: self.record_id,
record_length_after_header: self.record_length_after_header(is_extended)?,
description,
data: self.data,
})
}
pub fn len(&self, is_extended: bool) -> usize {
self.data.len()
+ if is_extended {
EXTENDED_HEADER_SIZE
} else {
REGULAR_HEADER_SIZE
}
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn has_large_data(&self) -> bool {
self.data.len() > u16::MAX as usize
}
pub fn is_crs(&self) -> bool {
matches!(
(self.user_id.to_lowercase().as_str(), self.record_id),
("lasf_projection", 2112 | 34735..=34737)
)
}
pub fn is_wkt_crs(&self) -> bool {
matches!(
(self.user_id.to_lowercase().as_str(), self.record_id),
("lasf_projection", 2112)
)
}
pub fn is_geotiff_crs(&self) -> bool {
matches!(
(self.user_id.to_lowercase().as_str(), self.record_id),
("lasf_projection", 34735..=34737)
)
}
fn record_length_after_header(&self, is_extended: bool) -> Result<raw::vlr::RecordLength> {
if is_extended {
Ok(raw::vlr::RecordLength::Evlr(self.data.len() as u64))
} else if self.data.len() > u16::MAX as usize {
Err(Error::VlrTooLong(self.data.len()))
} else {
Ok(raw::vlr::RecordLength::Vlr(self.data.len() as u16))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn len() {
let data = vec![0; 1];
let vlr = Vlr {
data,
..Default::default()
};
assert_eq!(55, vlr.len(false));
assert_eq!(61, vlr.len(true));
}
#[test]
fn too_long() {
let data = vec![0; u16::MAX as usize + 1];
let vlr = Vlr {
data,
..Default::default()
};
assert!(vlr.into_raw(false).is_err());
}
#[test]
fn allow_non_ascii_user_id() {
let raw_vlr = raw::Vlr {
user_id: [194, 174, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0],
..Default::default()
};
let vlr = Vlr::new(raw_vlr);
assert_eq!("®", vlr.user_id);
}
#[test]
fn allow_non_ascii_description() {
let raw_vlr = raw::Vlr {
description: [
194, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
],
..Default::default()
};
let vlr = Vlr::new(raw_vlr);
assert_eq!("®", vlr.description);
}
}