#![forbid(unsafe_code)]
#[cfg(feature = "default")]
use flate2::read::ZlibDecoder;
use prost::Message;
use std::convert::From;
#[cfg(feature = "default")]
use std::io::prelude::*;
use std::io::ErrorKind;
use std::str;
pub mod dense;
pub mod pbf;
pub mod util;
#[derive(Debug)]
pub enum Error {
PbfParseError(prost::DecodeError),
IoError(std::io::Error),
InvalidBlobHeader,
InvalidBlobData,
DecompressionError(DecompressionError),
LogicError(String),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for Error {}
pub enum Block<'a> {
Header(pbf::HeaderBlock),
Primitive(pbf::PrimitiveBlock),
Unknown(&'a [u8]),
}
enum BlockType {
Header,
Primitive,
Unknown,
}
impl From<&str> for BlockType {
fn from(value: &str) -> Self {
match value {
"OSMHeader" => BlockType::Header,
"OSMData" => BlockType::Primitive,
_ => BlockType::Unknown,
}
}
}
pub struct RawBlock {
r#type: BlockType,
data: Vec<u8>,
}
pub fn read_blob<Input>(pbf: &mut Input) -> Option<Result<RawBlock, Error>>
where
Input: std::io::Read,
{
let mut header_size_buffer = [0u8; 4];
if let Err(error) = pbf.read_exact(&mut header_size_buffer) {
return match error.kind() {
ErrorKind::UnexpectedEof => None,
_ => Some(Err(Error::IoError(error))),
};
}
Some(read_blob_inner(pbf, header_size_buffer))
}
fn read_blob_inner<Input>(pbf: &mut Input, header_size_buffer: [u8; 4]) -> Result<RawBlock, Error>
where
Input: std::io::Read,
{
use pbf::BlobHeader;
let blob_header_size: usize = i32::from_be_bytes(header_size_buffer)
.try_into()
.map_err(|_err| Error::InvalidBlobHeader)?;
if blob_header_size >= 64 * 1024 {
return Err(Error::InvalidBlobHeader);
}
let mut blob = vec![0u8; blob_header_size];
if let Err(error) = pbf.read_exact(&mut blob) {
return Err(Error::IoError(error));
}
let blob_header = match BlobHeader::decode(&*blob) {
Ok(blob_header) => blob_header,
Err(error) => return Err(Error::PbfParseError(error)),
};
let block_type = BlockType::from(blob_header.r#type.as_ref());
let blob_size: usize = blob_header.datasize.try_into().map_err(|_err| Error::InvalidBlobData)?;
if blob_size >= 32 * 1024 * 1024 {
return Err(Error::InvalidBlobData);
}
blob.resize_with(blob_size, Default::default);
if let Err(error) = pbf.read_exact(&mut blob) {
return Err(Error::IoError(error));
}
let raw_block = RawBlock {
r#type: block_type,
data: blob,
};
Ok(raw_block)
}
pub enum CompressionMethod {
Lz4,
Lzma,
Zlib,
Zstd,
}
#[derive(Debug)]
pub enum DecompressionError {
UnsupportedCompression,
InternalError(Box<dyn std::error::Error + Send + Sync>),
}
pub trait Decompressor {
fn decompress(method: CompressionMethod, input: &[u8], output: &mut [u8]) -> Result<(), DecompressionError>;
}
pub struct DefaultDecompressor;
impl Decompressor for DefaultDecompressor {
#[cfg(feature = "default")]
fn decompress(method: CompressionMethod, input: &[u8], output: &mut [u8]) -> Result<(), DecompressionError> {
match method {
CompressionMethod::Zlib => {
let mut decoder = ZlibDecoder::new(input);
match decoder.read_exact(output) {
Ok(_) => Ok(()),
Err(error) => Err(DecompressionError::InternalError(Box::new(error))),
}
}
_ => Err(DecompressionError::UnsupportedCompression),
}
}
#[cfg(not(feature = "default"))]
fn decompress(_method: CompressionMethod, _input: &[u8], _output: &mut [u8]) -> Result<(), DecompressionError> {
Err(DecompressionError::UnsupportedCompression)
}
}
pub struct BlockParser<D: Decompressor = DefaultDecompressor> {
block_buffer: Vec<u8>,
decompressor: std::marker::PhantomData<D>,
}
impl Default for BlockParser {
fn default() -> Self {
BlockParser::<DefaultDecompressor>::new()
}
}
impl<D: Decompressor> BlockParser<D> {
pub fn new() -> Self {
Self {
block_buffer: Vec::new(),
decompressor: Default::default(),
}
}
#[allow(deprecated)]
pub fn parse_block(&mut self, raw_block: RawBlock) -> Result<Block, Error> {
let blob = match pbf::Blob::decode(&*raw_block.data) {
Ok(blob) => blob,
Err(error) => return Err(Error::PbfParseError(error)),
};
if let Some(uncompressed_size) = blob.raw_size {
let uncompressed_size: usize = uncompressed_size.try_into().map_err(|_err| Error::InvalidBlobData)?;
self.block_buffer.resize_with(uncompressed_size, Default::default);
}
if let Some(blob_data) = blob.data {
match blob_data {
pbf::blob::Data::Raw(raw_data) => self.block_buffer.extend_from_slice(&raw_data),
pbf::blob::Data::ZlibData(zlib_data) => {
if let Err(error) = D::decompress(CompressionMethod::Zlib, &zlib_data, &mut self.block_buffer) {
return Err(Error::DecompressionError(error));
}
}
pbf::blob::Data::Lz4Data(lz4_data) => {
if let Err(error) = D::decompress(CompressionMethod::Lz4, &lz4_data, &mut self.block_buffer) {
return Err(Error::DecompressionError(error));
}
}
pbf::blob::Data::LzmaData(lzma_data) => {
if let Err(error) = D::decompress(CompressionMethod::Lzma, &lzma_data, &mut self.block_buffer) {
return Err(Error::DecompressionError(error));
}
}
pbf::blob::Data::ZstdData(zstd_data) => {
if let Err(error) = D::decompress(CompressionMethod::Zstd, &zstd_data, &mut self.block_buffer) {
return Err(Error::DecompressionError(error));
}
}
pbf::blob::Data::ObsoleteBzip2Data(_) => return Err(Error::InvalidBlobData),
}
} else {
return Err(Error::InvalidBlobData);
}
match raw_block.r#type {
BlockType::Header => match pbf::HeaderBlock::decode(&*self.block_buffer) {
Ok(header_block) => Ok(Block::Header(header_block)),
Err(error) => Err(Error::PbfParseError(error)),
},
BlockType::Primitive => match pbf::PrimitiveBlock::decode(&*self.block_buffer) {
Ok(primitive_block) => Ok(Block::Primitive(primitive_block)),
Err(error) => Err(Error::PbfParseError(error)),
},
BlockType::Unknown => Ok(Block::Unknown(&self.block_buffer)),
}
}
}
pub struct TagReader<'a, I>
where
I: Iterator<Item = (Result<usize, Error>, Result<usize, Error>)>,
{
string_table: &'a pbf::StringTable,
iter: I,
}
impl<'a, I> Iterator for TagReader<'a, I>
where
I: Iterator<Item = (Result<usize, Error>, Result<usize, Error>)>,
{
type Item = (Result<&'a str, Error>, Result<&'a str, Error>);
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some((key, value)) => {
let decode_string = |index: usize| -> Result<&str, Error> {
if let Some(bytes) = self.string_table.s.get(index) {
if let Ok(utf8_string) = str::from_utf8(bytes) {
Ok(utf8_string)
} else {
Err(Error::LogicError(format!("string at index {index} is not valid UTF-8")))
}
} else {
Err(Error::LogicError(format!(
"string table index {index} is out of bounds ({})",
self.string_table.s.len()
)))
}
};
let key = match key {
Ok(key_idx) => decode_string(key_idx),
Err(error) => Err(error),
};
let value = match value {
Ok(value_idx) => decode_string(value_idx),
Err(error) => Err(error),
};
Some((key, value))
}
None => None,
}
}
}
pub fn new_tag_reader<'a>(
string_table: &'a pbf::StringTable,
key_indices: &'a [u32],
value_indices: &'a [u32],
) -> TagReader<'a, impl Iterator<Item = (Result<usize, Error>, Result<usize, Error>)> + 'a> {
TagReader {
string_table,
iter: key_indices
.iter()
.map(|i| Ok(*i as usize))
.zip(value_indices.iter().map(|i| Ok(*i as usize))),
}
}
#[cfg(test)]
mod tag_reader_tests {
use super::*;
#[test]
fn valid_input() {
let key_vals = ["", "key1", "val1", "key2", "val2"];
let string_table = pbf::StringTable {
s: key_vals.iter().map(|s| s.as_bytes().to_vec()).collect(),
};
let key_indices = [1, 3];
let value_indices = [2, 4];
let mut reader = new_tag_reader(&string_table, &key_indices, &value_indices);
matches!(reader.next(), Some((Ok("key1"), Ok("val1"))));
matches!(reader.next(), Some((Ok("key2"), Ok("val2"))));
assert!(reader.next().is_none());
}
}
pub struct DeltaValueReader<'a, T> {
remaining: &'a [T],
accumulated: T,
}
impl<'a, T> DeltaValueReader<'a, T>
where
T: std::default::Default,
{
pub fn new(values: &'a [T]) -> Self {
DeltaValueReader {
remaining: values,
accumulated: T::default(),
}
}
}
impl<T> Iterator for DeltaValueReader<'_, T>
where
T: std::ops::AddAssign + std::clone::Clone,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if let Some((first, elements)) = self.remaining.split_first() {
self.accumulated += first.clone();
self.remaining = elements;
Some(self.accumulated.clone())
} else {
None
}
}
}
#[cfg(test)]
mod delta_value_reader_tests {
use super::*;
#[test]
fn empty_input() {
let mut reader = DeltaValueReader::new(&[] as &[i64]);
assert_eq!(reader.next(), None);
}
#[test]
fn valid_input() {
let values = [10, -1, 4, -2];
let mut reader = DeltaValueReader::new(&values);
assert_eq!(reader.next(), Some(10));
assert_eq!(reader.next(), Some(9));
assert_eq!(reader.next(), Some(13));
assert_eq!(reader.next(), Some(11));
}
}