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}