gistools/readers/pmtiles/
reader.rs1use super::{
2 PMDirectory, PMTilePos, S2_PM_HEADER_SIZE_BYTES, S2_PM_ROOT_SIZE, S2PMEntries, S2PMHeader,
3 find_tile,
4};
5use crate::{
6 data_structures::Cache,
7 parsers::{Buffer, Reader},
8 util::decompress_data,
9};
10use alloc::{string::String, vec::Vec};
11use s2_tilejson::{Metadata, UnknownMetadata};
12use s2json::Face;
13
14#[derive(Debug)]
70pub struct PMTilesReader<R: Reader> {
71 header: Option<S2PMHeader>,
72 root_dir: PMDirectory,
73 root_dir_s2: S2PMEntries,
74 metadata: Metadata,
75 dir_cache: Cache<u64, PMDirectory>,
76 reader: R,
77}
78impl<R: Reader> PMTilesReader<R> {
79 pub fn new(reader: R, max_size: Option<usize>) -> Self {
81 let max_size = max_size.unwrap_or(20);
82 Self {
83 header: None,
84 root_dir: PMDirectory::default(),
85 root_dir_s2: S2PMEntries::default(),
86 metadata: Metadata::default(),
87 dir_cache: Cache::new(max_size, None),
88 reader,
89 }
90 }
91
92 pub async fn get_header(&mut self) -> S2PMHeader {
94 if self.header.is_some() {
95 return self.header.unwrap();
96 }
97
98 let data = self.get_range(0, S2_PM_ROOT_SIZE as u64).await;
99 let header_data = data[0..S2_PM_HEADER_SIZE_BYTES].to_vec();
100 let mut header = S2PMHeader::from_bytes(&mut header_data.into());
102
103 let json_offset = header.metadata_offset as usize;
105 let json_length = header.metadata_length as usize;
106 let json_metadata = decompress_data(
107 &data[json_offset..(json_offset + json_length)],
108 header.internal_compression,
109 )
110 .unwrap();
111 let meta: UnknownMetadata = serde_json::from_str(&String::from_utf8_lossy(&json_metadata))
112 .unwrap_or_else(|e| panic!("ERROR: {}", e));
113 self.metadata = meta.to_metadata();
114
115 let root_dir_offset = header.root_directory_offset as usize;
117 let root_dir_length = header.root_directory_length as usize;
118 let root_dir_data = decompress_data(
119 &data[root_dir_offset..(root_dir_offset + root_dir_length)],
120 header.internal_compression,
121 )
122 .unwrap();
123 self.root_dir = PMDirectory::from_buffer(&mut root_dir_data.into());
124
125 if header.is_s2 {
126 self.get_s2_metadata(&data, &mut header);
127 }
128
129 self.header = Some(header);
130
131 header
132 }
133
134 pub fn get_s2_metadata(&mut self, data: &[u8], header: &mut S2PMHeader) {
136 self.root_dir_s2.face_0 = self.root_dir.clone();
138 for face in [Face::Face1, Face::Face2, Face::Face3, Face::Face4, Face::Face5] {
140 let root_offset = header.get_root_offset(face) as usize;
141 let root_length = header.get_root_length(face) as usize;
142 let face_dir_data = decompress_data(
143 &data[root_offset..(root_offset + root_length)],
144 header.internal_compression,
145 )
146 .unwrap();
147 self.root_dir_s2.set_dir(face, PMDirectory::from_buffer(&mut face_dir_data.into()));
148 }
149 }
150
151 pub fn get_metadata(&mut self) -> &Metadata {
153 &self.metadata
154 }
155
156 pub async fn get_tile_s2(&mut self, face: Face, zoom: u8, x: u64, y: u64) -> Option<Vec<u8>> {
158 self.get_tile(Some(face), zoom, x, y).await
159 }
160
161 pub async fn get_tile_wm(&mut self, zoom: u8, x: u64, y: u64) -> Option<Vec<u8>> {
163 self.get_tile(None, zoom, x, y).await
164 }
165
166 pub async fn get_tile(
168 &mut self,
169 face: Option<Face>,
170 zoom: u8,
171 x: u64,
172 y: u64,
173 ) -> Option<Vec<u8>> {
174 let header = self.get_header().await;
175 let tile_id = PMTilePos::new(zoom, x, y).to_id();
176 let mut d_o = header.root_directory_offset;
179 let mut d_l = header.root_directory_length;
180
181 for _ in 0..4 {
182 let directory = self.get_directory(d_o, d_l, face).await;
183 if directory.is_empty() {
184 return None;
185 }
186 let entry = find_tile(&directory.entries, tile_id);
187 match entry {
188 None => {
189 return None;
190 }
191 Some(entry) => {
192 if entry.run_length > 0 {
193 let entry_data = self
194 .get_range(header.data_offset + entry.offset, entry.length as u64)
195 .await;
196 return Some(
197 decompress_data(&entry_data, header.internal_compression).unwrap(),
198 );
199 } else {
200 d_o = header.leaf_directory_offset + entry.offset;
201 d_l = entry.length as u64;
202 }
203 }
204 }
205 }
206
207 panic!("Maximum directory depth exceeded");
208 }
209
210 async fn get_directory(&mut self, offset: u64, length: u64, face: Option<Face>) -> PMDirectory {
212 let dir = match face {
213 None => &self.root_dir,
214 Some(f) => self.root_dir_s2.get(f),
215 };
216 let internal_compression = self.header.unwrap().internal_compression;
217 let root_directory_offset = self.header.unwrap().root_directory_offset;
218 if offset == root_directory_offset {
220 return dir.clone();
221 }
222 if let Some(cache) = self.dir_cache.get(&offset) {
224 cache.clone()
225 } else {
226 let resp = self.get_range(offset, length).await;
228 let data = decompress_data(&resp, internal_compression).unwrap();
229 let mut buffer: Buffer = Buffer::new(data);
230 let directory = PMDirectory::from_buffer(&mut buffer);
231 if directory.is_empty() {
232 panic!("Empty directory is invalid");
233 }
234 self.dir_cache.set(offset, directory.clone());
236
237 directory
238 }
239 }
240
241 async fn get_range(&mut self, offset: u64, length: u64) -> Vec<u8> {
243 let len = self.reader.len();
244 if len != 0 {
245 let end = u64::min(len, offset + length);
247 self.reader.slice(Some(offset), Some(end))
248 } else {
249 self.reader.get_slice(offset, Some(length)).await
250 }
251 }
252}