From ba171bad33767ad52e0900760358bac3df69f896 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sat, 14 Jan 2023 20:05:38 +0100 Subject: add support for reading brotli and gzip files --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/gpx.rs | 42 +++++++++++++++++++++++++++++++++++++++--- src/main.rs | 8 ++++++-- 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 337cfc7..b995bd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,21 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "anes" version = "0.1.6" @@ -82,6 +97,27 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.11.1" @@ -564,10 +600,12 @@ dependencies = [ name = "hittekaart" version = "0.1.0" dependencies = [ + "brotli", "clap 4.1.0", "color-eyre", "colorgrad", "criterion", + "flate2", "fnv", "image", "imageproc", diff --git a/Cargo.toml b/Cargo.toml index cf67d91..f50423e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,11 @@ name = "hittebench" harness = false [dependencies] +brotli = "3.3.4" clap = { version = "4.1.0", features = ["derive"] } color-eyre = "0.6.2" colorgrad = "0.6.2" +flate2 = "1.0.25" fnv = "1.0.7" image = "0.24.5" imageproc = "0.23.0" diff --git a/src/gpx.rs b/src/gpx.rs index 337a2a9..9dd7725 100644 --- a/src/gpx.rs +++ b/src/gpx.rs @@ -3,9 +3,16 @@ //! We *could* use the [gpx](https://github.com/georust/gpx) crate, but we don't care about much //! other than the coordinates of the tracks. By implementing the little functionality ourselves, //! we can use a fast XML parser ([roxmltree](https://github.com/RazrFalcon/roxmltree)). -use std::{f64::consts::PI, fs, path::Path}; +use std::{ + f64::consts::PI, + ffi::OsStr, + fs::{self, File}, + io::{BufReader, Read}, + path::Path, +}; use color_eyre::eyre::{eyre, Result}; +use flate2::bufread::GzDecoder; use roxmltree::{Document, Node, NodeType}; #[derive(Debug, Copy, Clone, PartialEq)] @@ -67,12 +74,41 @@ pub fn extract_from_str(input: &str) -> Result> { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Compression { None, + Gzip, + Brotli, +} + +impl Compression { + pub fn suggest_from_path>(path: P) -> Option { + let Some(ext) = path.as_ref().extension() else { return None }; + if OsStr::new("br") == ext { + Some(Compression::Brotli) + } else if [OsStr::new("gz"), OsStr::new("gzip")].contains(&ext) { + Some(Compression::Gzip) + } else if OsStr::new("gpx") == ext { + Some(Compression::None) + } else { + None + } + } } pub fn extract_from_file>( path: P, - _compression: Compression, + compression: Compression, ) -> Result> { - let content = fs::read_to_string(path)?; + let content = match compression { + Compression::None => fs::read_to_string(path)?, + Compression::Gzip => { + let mut result = String::new(); + GzDecoder::new(BufReader::new(File::open(path)?)).read_to_string(&mut result)?; + result + } + Compression::Brotli => { + let mut result = Vec::new(); + brotli::BrotliDecompress(&mut BufReader::new(File::open(path)?), &mut result)?; + String::from_utf8(result)? + } + }; extract_from_str(&content) } diff --git a/src/main.rs b/src/main.rs index f4a7aa7..e2dacb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use std::{ }; use clap::Parser; -use color_eyre::eyre::{bail, Context, Result}; +use color_eyre::eyre::{bail, eyre, Context, Result}; use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle}; use is_terminal::IsTerminal; use rayon::ThreadPoolBuilder; @@ -14,6 +14,8 @@ mod gpx; mod layer; mod renderer; +use gpx::Compression; + #[derive(Parser, Debug, Clone)] #[command(author, version, about)] struct Args { @@ -70,7 +72,9 @@ fn main() -> Result<()> { let mut tracks = Vec::new(); for file in &args.files { - let data = gpx::extract_from_file(file, gpx::Compression::None).unwrap(); + let compression = Compression::suggest_from_path(file) + .ok_or_else(|| eyre!("Could not determine format for {file:?}"))?; + let data = gpx::extract_from_file(file, compression)?; tracks.push(data); bar.inc(1); } -- cgit v1.2.3