1use std::io::{BufReader, Read};
2use byteorder::{BigEndian, ReadBytesExt};
3use crate::{
4    types::{BoundingBox, MapHeader},
5    error::MapforgeError,
6    Result,
7};
8
9const MAGIC_BYTES: &str = "mapsforge binary OSM";
11
12
13const MIN_SUPPORTED_VERSION: u32 = 3;
14
15
16
17impl BoundingBox {
18  
19    pub fn read_from_buffer<R: Read>(reader: &mut BufReader<R>) -> Result<Self> {
22
23        let min_lat = reader.read_i32::<BigEndian>()? as f64 / 1_000_000.0;
26        let min_lon = reader.read_i32::<BigEndian>()? as f64 / 1_000_000.0;
27        let max_lat = reader.read_i32::<BigEndian>()? as f64 / 1_000_000.0; 
28        let max_lon = reader.read_i32::<BigEndian>()? as f64 / 1_000_000.0;
29
30        let bbox = BoundingBox {
31            min_lat,
32            min_lon,
33            max_lat,
34            max_lon,
35        };
36
37        if !bbox.is_valid() {
38            return Err(MapforgeError::InvalidBoundingBox);
39        }
40
41        Ok(bbox)
42    }
43
44
45    fn is_valid(&self) -> bool {
50        self.min_lat >= -90.0 && self.min_lat <= 90.0 &&
51        self.max_lat >= -90.0 && self.max_lat <= 90.0 &&
52        self.min_lon >= -180.0 && self.min_lon <= 180.0 &&
53        self.max_lon >= -180.0 && self.max_lon <= 180.0 &&
54        self.min_lat <= self.max_lat &&
55        self.min_lon <= self.max_lon
56    }
57}
58
59
60
61impl MapHeader {
62
63    pub fn read_from_file<R: Read>(reader: &mut BufReader<R>) -> Result<Self> {
65
66        let mut magic_buf= [0u8;20];
67        reader.read_exact(&mut magic_buf)?;
68        let magic = String::from_utf8_lossy(&magic_buf).trim().to_string();
69
70        if magic != MAGIC_BYTES {
71            return Err(MapforgeError::InvalidMagic);
72        }
73        
74        let header_size = reader.read_u32::<BigEndian>()?;
75        let file_version = reader.read_u32::<BigEndian>()?;
76
77        if file_version < MIN_SUPPORTED_VERSION {
78            return Err(MapforgeError::UnsupportedVersion(file_version));
79        }
80        
81        let file_size = reader.read_u64::<BigEndian>()?;
82        let creation_date = reader.read_u64::<BigEndian>()?;
83
84        let bounding_box = BoundingBox::read_from_buffer(reader)?;
85
86        let tile_size = reader.read_u16::<BigEndian>()?;
87       
88        let projection = String::from("MERCATOR"); 
89
90        let flags = reader.read_u8()?;
91
92
93        let header = MapHeader {
94            magic,
95            header_size,
96            file_version,
97            file_size,
98            creation_date,
99            bounding_box,
100            tile_size,
101            projection,
102            flags,
103        };
104
105        if !header.is_valid() {
106            return Err(MapforgeError::InvalidHeaderSize(header_size));
107        }
108
109        Ok(header)
110
111    }
112
113    pub fn is_valid(&self) -> bool {
114        self.magic.trim() == MAGIC_BYTES &&
115        self.header_size > 0 &&
116        self.file_version >= MIN_SUPPORTED_VERSION
117    }
118
119}