Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add little-endian support #46

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions benches/filetests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use std::io::{self, Read};

use test::Bencher;

use nbt::de::from_gzip;
use nbt::de::from_gzip_reader;
use nbt::ser::to_writer;
use nbt::Endianness;

mod data {
include!("../tests/data.rs.in");
Expand All @@ -29,7 +30,7 @@ fn deserialize_big1_as_struct(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
let _: data::Big1 = from_gzip(&mut src).unwrap();
let _: data::Big1 = from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

Expand All @@ -40,25 +41,25 @@ fn deserialize_big1_as_blob(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
nbt::Blob::from_gzip(&mut src).unwrap();
nbt::Blob::from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

#[bench]
fn serialize_big1_as_struct(b: &mut Bencher) {
let mut file = File::open("tests/big1.nbt").unwrap();
let nbt: data::Big1 = from_gzip(&mut file).unwrap();
let nbt: data::Big1 = from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
to_writer(&mut io::sink(), &nbt, None)
to_writer(&mut io::sink(), &nbt, None, Endianness::BigEndian)
});
}

#[bench]
fn serialize_big1_as_blob(b: &mut Bencher) {
let mut file = File::open("tests/big1.nbt").unwrap();
let nbt = nbt::Blob::from_gzip(&mut file).unwrap();
let nbt = nbt::Blob::from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
nbt.write(&mut io::sink())
nbt.to_writer(&mut io::sink(), Endianness::BigEndian)
});
}
#[bench]
Expand All @@ -68,7 +69,7 @@ fn deserialize_simple_player_as_struct(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
let _: data::PlayerData = from_gzip(&mut src).unwrap();
let _: data::PlayerData = from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

Expand All @@ -79,25 +80,25 @@ fn deserialize_simple_player_as_blob(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
nbt::Blob::from_gzip(&mut src).unwrap();
nbt::Blob::from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

#[bench]
fn serialize_simple_player_as_struct(b: &mut Bencher) {
let mut file = File::open("tests/simple_player.dat").unwrap();
let nbt: data::PlayerData = from_gzip(&mut file).unwrap();
let nbt: data::PlayerData = from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
to_writer(&mut io::sink(), &nbt, None)
to_writer(&mut io::sink(), &nbt, None, Endianness::BigEndian)
});
}

#[bench]
fn serialize_simple_player_as_blob(b: &mut Bencher) {
let mut file = File::open("tests/simple_player.dat").unwrap();
let nbt = nbt::Blob::from_gzip(&mut file).unwrap();
let nbt = nbt::Blob::from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
nbt.write(&mut io::sink())
nbt.to_writer(&mut io::sink(), Endianness::BigEndian)
});
}

Expand All @@ -108,7 +109,7 @@ fn deserialize_complex_player_as_struct(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
let _: data::PlayerData = from_gzip(&mut src).unwrap();
let _: data::PlayerData = from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

Expand All @@ -119,25 +120,25 @@ fn deserialize_complex_player_as_blob(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
nbt::Blob::from_gzip(&mut src).unwrap();
nbt::Blob::from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

#[bench]
fn serialize_complex_player_as_struct(b: &mut Bencher) {
let mut file = File::open("tests/complex_player.dat").unwrap();
let nbt: data::PlayerData = from_gzip(&mut file).unwrap();
let nbt: data::PlayerData = from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
to_writer(&mut io::sink(), &nbt, None)
to_writer(&mut io::sink(), &nbt, None, Endianness::BigEndian)
});
}

#[bench]
fn serialize_complex_player_as_blob(b: &mut Bencher) {
let mut file = File::open("tests/complex_player.dat").unwrap();
let nbt = nbt::Blob::from_gzip(&mut file).unwrap();
let nbt = nbt::Blob::from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
nbt.write(&mut io::sink())
nbt.to_writer(&mut io::sink(), Endianness::BigEndian)
});
}

Expand All @@ -148,7 +149,7 @@ fn deserialize_level_as_struct(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
let _: data::Level = from_gzip(&mut src).unwrap();
let _: data::Level = from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

Expand All @@ -159,24 +160,24 @@ fn deserialize_level_as_blob(b: &mut Bencher) {
file.read_to_end(&mut contents).unwrap();
b.iter(|| {
let mut src = std::io::Cursor::new(&contents[..]);
nbt::Blob::from_gzip(&mut src).unwrap();
nbt::Blob::from_gzip_reader(&mut src, Endianness::BigEndian).unwrap();
});
}

#[bench]
fn serialize_level_as_struct(b: &mut Bencher) {
let mut file = File::open("tests/level.dat").unwrap();
let nbt: data::Level = from_gzip(&mut file).unwrap();
let nbt: data::Level = from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
to_writer(&mut io::sink(), &nbt, None)
to_writer(&mut io::sink(), &nbt, None, Endianness::BigEndian)
});
}

#[bench]
fn serialize_level_as_blob(b: &mut Bencher) {
let mut file = File::open("tests/level.dat").unwrap();
let nbt = nbt::Blob::from_gzip(&mut file).unwrap();
let nbt = nbt::Blob::from_gzip_reader(&mut file, Endianness::BigEndian).unwrap();
b.iter(|| {
nbt.write(&mut io::sink())
nbt.to_writer(&mut io::sink(), Endianness::BigEndian)
});
}
3 changes: 2 additions & 1 deletion examples/nbtprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ use std::process::exit;

use nbt::Result;
use nbt::Blob;
use nbt::Endianness;

fn run() -> Result<()> {
let args: Vec<String> = env::args().collect();
if let Some(arg) = args.into_iter().skip(1).take(1).next() {
let mut file = fs::File::open(&arg)?;
println!("================================= NBT Contents =================================");
let blob = Blob::from_reader(&mut file)?;
let blob = Blob::from_reader(&mut file, Endianness::BigEndian)?;
println!("{}", blob);
println!("============================== JSON Representation =============================");
match serde_json::to_string_pretty(&blob) {
Expand Down
49 changes: 25 additions & 24 deletions src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ use std::fmt;
use std::io;
use std::ops::Index;

use byteorder::WriteBytesExt;
use flate2::Compression;
use flate2::read::{GzDecoder, ZlibDecoder};
use flate2::write::{GzEncoder, ZlibEncoder};

use error::{Error, Result};
use raw;
use raw::{RawReader, RawWriter, Endianness};
use value::Value;

/// A generic, complete object in Named Binary Tag format.
Expand All @@ -23,7 +22,7 @@ use value::Value;
/// (through Gzip or zlib compression) methods.
///
/// ```rust
/// use nbt::{Blob, Value};
/// use nbt::{Blob, Value, Endianness};
///
/// // Create a `Blob` from key/value pairs.
/// let mut nbt = Blob::new();
Expand All @@ -33,7 +32,7 @@ use value::Value;
///
/// // Write a compressed binary representation to a byte array.
/// let mut dst = Vec::new();
/// nbt.to_zlib_writer(&mut dst).unwrap();
/// nbt.to_zlib_writer(&mut dst, Endianness::BigEndian).unwrap();
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Blob {
Expand All @@ -53,17 +52,18 @@ impl Blob {
}

/// Extracts an `Blob` object from an `io::Read` source.
pub fn from_reader<R>(src: &mut R) -> Result<Blob>
pub fn from_reader<R>(src: &mut R, endian: Endianness) -> Result<Blob>
where R: io::Read
{
let (tag, title) = try!(raw::emit_next_header(src));
let mut src = RawReader::new(src, endian);
let (tag, title) = src.emit_next_header()?;
// Although it would be possible to read NBT format files composed of
// arbitrary objects using the current API, by convention all files
// have a top-level Compound.
if tag != 0x0a {
return Err(Error::NoRootCompound);
}
let content = try!(Value::from_reader(tag, src));
let content = Value::from_raw_reader(tag, &mut src)?;
match content {
Value::Compound(map) => Ok(Blob { title: title, content: map }),
_ => Err(Error::NoRootCompound),
Expand All @@ -72,51 +72,52 @@ impl Blob {

/// Extracts an `Blob` object from an `io::Read` source that is
/// compressed using the Gzip format.
pub fn from_gzip_reader<R>(src: &mut R) -> Result<Blob>
pub fn from_gzip_reader<R>(src: &mut R, endian: Endianness) -> Result<Blob>
where R: io::Read
{
// Reads the gzip header, and fails if it is incorrect.
let mut data = try!(GzDecoder::new(src));
Blob::from_reader(&mut data)
let mut data = GzDecoder::new(src)?;
Blob::from_reader(&mut data, endian)
}

/// Extracts an `Blob` object from an `io::Read` source that is
/// compressed using the zlib format.
pub fn from_zlib_reader<R>(src: &mut R) -> Result<Blob>
pub fn from_zlib_reader<R>(src: &mut R, endian: Endianness) -> Result<Blob>
where R: io::Read
{
Blob::from_reader(&mut ZlibDecoder::new(src))
Blob::from_reader(&mut ZlibDecoder::new(src), endian)
}

/// Writes the binary representation of this `Blob` to an `io::Write`
/// destination.
pub fn to_writer<W>(&self, mut dst: &mut W) -> Result<()>
pub fn to_writer<W>(&self, dst: &mut W, endian: Endianness) -> Result<()>
where W: io::Write
{
dst.write_u8(0x0a)?;
raw::write_bare_string(&mut dst, &self.title)?;
let mut dst = RawWriter::new(dst, endian);
dst.write_bare_byte(0x0a)?;
dst.write_bare_string(&self.title)?;
for (name, ref nbt) in self.content.iter() {
dst.write_u8(nbt.id())?;
raw::write_bare_string(&mut dst, name)?;
nbt.to_writer(&mut dst)?;
dst.write_bare_byte(nbt.id())?;
dst.write_bare_string(name)?;
nbt.to_raw_writer(&mut dst)?;
}
raw::close_nbt(&mut dst)
dst.close_nbt()
}

/// Writes the binary representation of this `Blob`, compressed using
/// the Gzip format, to an `io::Write` destination.
pub fn to_gzip_writer<W>(&self, dst: &mut W) -> Result<()>
pub fn to_gzip_writer<W>(&self, dst: &mut W, endian: Endianness) -> Result<()>
where W: io::Write
{
self.to_writer(&mut GzEncoder::new(dst, Compression::Default))
self.to_writer(&mut GzEncoder::new(dst, Compression::Default), endian)
}

/// Writes the binary representation of this `Blob`, compressed using
/// the Zlib format, to an `io::Write` dst.
pub fn to_zlib_writer<W>(&self, dst: &mut W) -> Result<()>
pub fn to_zlib_writer<W>(&self, dst: &mut W, endian: Endianness) -> Result<()>
where W: io::Write
{
self.to_writer(&mut ZlibEncoder::new(dst, Compression::Default))
self.to_writer(&mut ZlibEncoder::new(dst, Compression::Default), endian)
}

/// Insert an `Value` with a given name into this `Blob` object. This
Expand Down Expand Up @@ -146,7 +147,7 @@ impl Blob {
}

/// Tries to get a named `Value` in the blob.
pub fn get<S>(&self, name: S) -> Option<&Value>
pub fn get<S>(&self, name: S) -> Option<&Value>
where S: Into<&'static str>
{
self.content.get(name.into())
Expand Down
Loading