From 663d015efa6d6dc71956ad9f9310774d16bdcdd6 Mon Sep 17 00:00:00 2001 From: Vladislav Golub Date: Sat, 5 Oct 2019 22:52:01 +0300 Subject: [PATCH] Add chunk read decompression --- Cargo.toml | 3 ++- src/lib.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa1c41e..ed3afb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] byteorder = "1.3" +flate2 = "1.0" [dev-dependencies] -tempfile = "3.1" \ No newline at end of file +tempfile = "3.1" diff --git a/src/lib.rs b/src/lib.rs index c664ea8..156c313 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt}; +use flate2::read; use std::fs::{File, OpenOptions}; -use std::io::{Error, Read, Seek, SeekFrom}; +use std::io::{Cursor, Error, Read, Seek, SeekFrom}; use std::path::Path; /// Amount of chunks in region. @@ -95,13 +96,17 @@ impl Region { return Ok(chunks_metadata); } - fn read_chunk(&mut self, x: u8, z: u8) -> Result, Error> { + pub fn read_chunk_data(&mut self, x: u8, z: u8) -> Result, Error> { assert!(32 > x, "Region chunk x coordinate out of bounds"); assert!(32 > z, "Region chunk y coordinate out of bounds"); let metadata = self.get_metadata(x, z); - let seek_offset = metadata.sector_index as u64 * REGION_SECTOR_BYTES_LENGTH as u64; + if metadata.is_empty() { + return Ok(Vec::new()); + } + + let seek_offset = metadata.sector_index as u64 * REGION_SECTOR_BYTES_LENGTH as u64; self.file.seek(SeekFrom::Start(seek_offset))?; let maximum_length = metadata.sectors as u32 * REGION_SECTOR_BYTES_LENGTH as u32; @@ -115,11 +120,26 @@ impl Region { ); let compression_scheme = self.file.read_u8()?; + let mut compressed_buffer = vec![0u8; (length - 1) as usize]; + self.file.read_exact(&mut compressed_buffer)?; + + let cursor = Cursor::new(&compressed_buffer); + let mut buffer = Vec::new(); + + match compression_scheme { + 1 => { + read::GzDecoder::new(cursor).read_to_end(&mut buffer)?; + } + 2 => { + read::ZlibDecoder::new(cursor).read_to_end(&mut buffer)?; + } + _ => panic!( + "Unsupported compression scheme of type {}", + compression_scheme + ), + } - let mut buf = vec![0u8; (length - 1) as usize]; - self.file.read_exact(&mut buf); - - Ok(buf) + Ok(buffer) } fn get_metadata(&self, x: u8, z: u8) -> ChunkMetadata { @@ -181,4 +201,26 @@ mod tests { } } + #[test] + fn test_read_chunk_data_existing() { + let path = Path::new("./test/region.mca"); + assert!(path.exists()); + + let mut region = Region::new(path).unwrap(); + let vec = region.read_chunk_data(4, 4).unwrap(); + + assert_eq!(vec.len(), 28061); + } + + #[test] + fn test_read_chunk_data_empty() { + let path = Path::new("./test/empty_region.mca"); + assert!(path.exists()); + + let mut region = Region::new(path).unwrap(); + let vec = region.read_chunk_data(0, 0).unwrap(); + + assert_eq!(vec.len(), 0); + } + }