| 9 | /// Returns None if the file is empty or has no chunks. |
| 10 | #[must_use] |
| 11 | pub fn read_region<B: Read + Seek>( |
| 12 | mut buf: B, |
| 13 | region_x: i32, |
| 14 | region_z: i32, |
| 15 | ) -> Result<Option<([u8; 4096], Vec<(i32, i32, Vec<u8>)>)>> { |
| 16 | let mut locations = [0u8; 4096]; |
| 17 | if let Err(err) = buf.read_exact(&mut locations) { |
| 18 | if err.kind() == std::io::ErrorKind::UnexpectedEof { |
| 19 | return Ok(None); |
| 20 | } |
| 21 | } |
| 22 | |
| 23 | let mut timestamps = [0u8; 4096]; |
| 24 | buf.read_exact(&mut timestamps) |
| 25 | .context("buffer's length < 8192")?; |
| 26 | |
| 27 | let mut compressed_chunks = Vec::new(); |
| 28 | |
| 29 | for i in 0..1024usize { |
| 30 | let loc = &locations[i * 4..(i + 1) * 4]; |
| 31 | let offset = u32::from_be_bytes([0, loc[0], loc[1], loc[2]]) as usize; |
| 32 | let size = loc[3] as usize; |
| 33 | |
| 34 | if offset == 0 && size == 0 { |
| 35 | continue; |
| 36 | } |
| 37 | |
| 38 | let byte_offset = offset * SECTOR_SIZE; |
| 39 | buf.seek(SeekStart(byte_offset as u64)) |
| 40 | .with_context(|| format!("at chunk #{i}: failed to seek {byte_offset}"))?; |
| 41 | |
| 42 | let mut header = [0u8; 5]; |
| 43 | buf.read_exact(&mut header) |
| 44 | .with_context(|| format!("at chunk #{i}: failed to read chunk header"))?; |
| 45 | |
| 46 | let data_length = u32::from_be_bytes([header[0], header[1], header[2], header[3]]) as usize; |
| 47 | let compression_type = header[4]; |
| 48 | |
| 49 | let compressed_len = data_length.saturating_sub(1); |
| 50 | let mut compressed_data = vec![0u8; compressed_len]; |
| 51 | buf.read_exact(&mut compressed_data).with_context(|| { |
| 52 | format!("at chunk #{i}: failed to read chunk body (length: {compressed_len})") |
| 53 | })?; |
| 54 | |
| 55 | compressed_chunks.push((i, compression_type, compressed_data)); |
| 56 | } |
| 57 | |
| 58 | let chunks: Vec<(i32, i32, Vec<u8>)> = compressed_chunks |
| 59 | .into_par_iter() |
| 60 | .filter_map(|(i, compression_type, compressed)| { |
| 61 | if compression_type == 2 { |
| 62 | let mut decoder = ZlibDecoder::new(&compressed[..]); |
| 63 | let mut nbt = Vec::new(); |
| 64 | match decoder.read_to_end(&mut nbt) { |
| 65 | Ok(_) => { |
| 66 | let local_x = (i % 32) as i32; |
| 67 | let local_z = (i / 32) as i32; |
| 68 | return Some((region_x * 32 + local_x, region_z * 32 + local_z, nbt)); |