@ -1,11 +1,10 @@
use crate ::nbt ::{ NBTError , NBTReader , NBTValue } ;
use crate ::nbt ::{ NBTError , NBTReader , NBTValue } ;
use crate ::region_file ::BLOCK_SIZE ;
use byteorder ::{ BigEndian , ReadBytesExt } ;
use byteorder ::{ BigEndian , ByteOrder , ReadBytesExt } ;
use flate2 ::bufread ::ZlibDecoder ;
use crate ::region_file ::BLOCK_SIZE ;
use flate2 ::read ::ZlibDecoder ;
use std ::fmt ::{ Display , Formatter } ;
use std ::fmt ::{ Display , Formatter } ;
use std ::fs ::File ;
use std ::io ::{ self , BufReader , Error } ;
use std ::io ::{ self , BufReader , Error , Read , Seek , SeekFrom } ;
type IOResult < T > = io ::Result < T > ;
type IOResult < T > = io ::Result < T > ;
@ -17,48 +16,33 @@ const TAG_Z_POS: &str = "zPos";
pub struct Chunk {
pub struct Chunk {
pub length : u32 ,
pub length : u32 ,
pub compression_type : u8 ,
pub compression_type : u8 ,
nbt_raw : Vec < u8 > ,
}
}
impl Chunk {
impl Chunk {
pub fn from_buf_reader ( reader : & mut BufReader < File > , include_nbt : bool ) -> IOResult < Self > {
pub fn from_buf_reader < R : io ::Read + io ::Seek > ( reader : & mut R ) -> IOResult < Self > {
let mut length_raw = [ 0 u8 ; 4 ] ;
let length = reader . read_u32 ::< BigEndian > ( ) ? ;
reader . read_exact ( & mut length_raw ) ? ;
if length > 128 * BLOCK_SIZE as u32 {
let length = BigEndian ::read_u32 ( & length_raw ) ;
return Err ( io ::Error ::from ( io ::ErrorKind ::InvalidData ) ) ;
let compression_type = reader . read_u8 ( ) ? ;
let mut nbt_raw = Vec ::new ( ) ;
if include_nbt {
for _ in 0 .. ( ( length - 1 ) as f32 / BLOCK_SIZE as f32 ) . ceil ( ) as u8 {
let mut buffer = [ 0 u8 ; BLOCK_SIZE ] ;
reader . read ( & mut buffer ) ? ;
nbt_raw . append ( & mut buffer . to_vec ( ) ) ;
}
nbt_raw . truncate ( ( length - 1 ) as usize ) ;
}
if length > 0 {
reader . seek ( SeekFrom ::Current ( ( length - 1 ) as i64 ) ) ? ;
} else {
reader . seek ( SeekFrom ::Current ( ( length ) as i64 ) ) ? ;
}
}
let compression_type = reader . read_u8 ( ) ? ;
Ok ( Self {
Ok ( Self {
compression_type ,
compression_type ,
length ,
length ,
nbt_raw ,
} )
} )
}
}
pub fn validate_nbt_data ( & mut self ) -> Result < ( ) , ChunkScanError > {
pub fn validate_nbt_data < R : io ::Read + io ::Seek > (
if self . compression_type = = 2 {
& mut self ,
let mut decoder = ZlibDecoder ::new ( & self . nbt_raw [ .. ] ) ;
reader : & mut R ,
let mut data = Vec ::new ( ) ;
) -> Result < ( ) , ChunkScanError > {
decoder . read_to_end ( & mut data ) ? ;
let data = if self . compression_type = = 2 {
self . nbt_raw = data ;
let mut nbt_reader = NBTReader ::new ( BufReader ::new ( ZlibDecoder ::new ( reader ) ) ) ;
}
nbt_reader . parse ( ) ?
let mut reader = NBTReader ::new ( & self . nbt_raw [ .. ] ) ;
} else {
let data = reader . parse ( ) ? ;
let mut nbt_reader = NBTReader ::new ( reader ) ;
nbt_reader . parse ( ) ?
} ;
if ! data . contains_key ( TAG_LEVEL ) {
if ! data . contains_key ( TAG_LEVEL ) {
Err ( ChunkScanError ::MissingTag ( TAG_LEVEL ) )
Err ( ChunkScanError ::MissingTag ( TAG_LEVEL ) )
@ -87,6 +71,7 @@ pub enum ChunkScanError {
NBTError ( NBTError ) ,
NBTError ( NBTError ) ,
MissingTag ( & ' static str ) ,
MissingTag ( & ' static str ) ,
InvalidFormat ( & ' static str ) ,
InvalidFormat ( & ' static str ) ,
InvalidLength ( u32 ) ,
}
}
impl Display for ChunkScanError {
impl Display for ChunkScanError {
@ -97,6 +82,7 @@ impl Display for ChunkScanError {
Self ::NBTError ( nbt ) = > write! ( f , "NBT Error: {}" , nbt ) ,
Self ::NBTError ( nbt ) = > write! ( f , "NBT Error: {}" , nbt ) ,
Self ::MissingTag ( tag ) = > write! ( f , "Missing Tag in NBT Data: {}" , tag ) ,
Self ::MissingTag ( tag ) = > write! ( f , "Missing Tag in NBT Data: {}" , tag ) ,
Self ::InvalidFormat ( tag ) = > write! ( f , "Unexpected data format for NBT Tag {}" , tag ) ,
Self ::InvalidFormat ( tag ) = > write! ( f , "Unexpected data format for NBT Tag {}" , tag ) ,
Self ::InvalidLength ( length ) = > write! ( f , "Invalid chunk data length: {}" , length ) ,
}
}
}
}
}
}