Skip to main content

ecitygml_io/gml/
read.rs

1use crate::error::Error;
2use crate::gml::read_impl::decode;
3use std::fs::File;
4use std::io::{BufReader, Read};
5
6use crate::error::Error::InvalidFileExtension;
7use crate::format::CitygmlFormat;
8use crate::gml::validate_impl::validate_from_reader;
9use ecitygml_core::model::core::CityModel;
10use std::path::Path;
11
12/// `CitygmlReader` reads CityGML datasets.
13///
14#[derive(Debug, Clone)]
15pub struct GmlReader<R: Read> {
16    reader: R,
17    format: CitygmlFormat,
18    rebuild_object_bounds: bool,
19}
20
21impl<R: Read> GmlReader<R> {
22    /// Create a new [`GmlReader`] from an existing `Reader`.
23    pub fn new(reader: R, format: CitygmlFormat) -> Self {
24        Self {
25            reader,
26            format,
27            rebuild_object_bounds: true,
28        }
29    }
30
31    fn read(self) -> Result<Vec<u8>, Error> {
32        let mut content = Vec::new();
33
34        match self.format {
35            CitygmlFormat::Gml => {
36                BufReader::new(self.reader).read_to_end(&mut content)?;
37            }
38            CitygmlFormat::GmlZst => {
39                zstd::Decoder::new(BufReader::new(self.reader))?.read_to_end(&mut content)?;
40            }
41            CitygmlFormat::GmlGz => {
42                flate2::read::GzDecoder::new(BufReader::new(self.reader))
43                    .read_to_end(&mut content)?;
44            }
45        }
46
47        Ok(content)
48    }
49
50    pub fn validate(self) -> Result<crate::gml::validate::report::Report, Error> {
51        validate_from_reader(self.read()?)
52    }
53
54    pub fn with_rebuild_object_bounds(mut self, rebuild_object_bounds: bool) -> Self {
55        self.rebuild_object_bounds = rebuild_object_bounds;
56        self
57    }
58
59    pub fn finish(self) -> Result<CityModel, Error> {
60        let rebuild_object_bounds = self.rebuild_object_bounds;
61        let mut city_model = decode(self.read()?)?;
62
63        if rebuild_object_bounds {
64            city_model.refresh_bounded_by_recursive();
65        }
66
67        Ok(city_model)
68    }
69}
70
71impl GmlReader<File> {
72    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, Error> {
73        let format = CitygmlFormat::from_path(path.as_ref()).ok_or_else(|| {
74            InvalidFileExtension(
75                path.as_ref()
76                    .extension()
77                    .and_then(|ext| ext.to_str())
78                    .unwrap_or_default()
79                    .to_string(),
80            )
81        })?;
82
83        let file = std::fs::File::open(path.as_ref())?;
84
85        Ok(Self::new(file, format))
86    }
87}