Skip to content

Commit

Permalink
implement LongArray read/write operations (fixes #1)
Browse files Browse the repository at this point in the history
Fixes this error when trying to open an NBT file:

    caused by: Got unknown type id c trying to read NBT compound

Thanks to ravomavain@ for fixing an issue in which the length of the
array is stored in a 32 bit int
  • Loading branch information
devvmh committed Jul 6, 2020
1 parent 0282101 commit 05fec15
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/unstable/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum NBT {
List(Vec<NBT>),
Compound(Vec<(Vec<u8>, NBT)>),
IntArray(Vec<i32>),
LongArray(Vec<i64>),
}
impl NBT {
pub fn get<S: AsRef<[u8]>>(&self, val: S) -> Option<&NBT> {
Expand Down Expand Up @@ -55,6 +56,7 @@ impl NBT {
&NBT::List(..) => "List",
&NBT::Compound(..) => "Compound",
&NBT::IntArray(..) => "IntArray",
&NBT::LongArray(..) => "LongArray",
}
}
/// Returns the type of the tag as a single u8
Expand All @@ -72,6 +74,7 @@ impl NBT {
&NBT::List(..) => 9,
&NBT::Compound(..) => 10,
&NBT::IntArray(..) => 11,
&NBT::LongArray(..) => 12,
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/unstable/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ fn read_compound<R: Read>(reader: &mut R) -> Result<NBT> {
0x09 => read_list(reader)?,
0x0a => read_compound(reader)?,
0x0b => read_int_array(reader)?,
0x0c => read_long_array(reader)?,
x => {
bail!("Got unknown type id {:x} trying to read NBT compound", x);
}
Expand Down Expand Up @@ -167,6 +168,7 @@ fn read_list<R: Read>(reader: &mut R) -> Result<NBT> {
0x9 => read_list(reader)?,
0xa => read_compound(reader)?,
0xb => read_int_array(reader)?,
0xc => read_long_array(reader)?,
x => bail!("Got unknown type id {:x} trying to read NBT list", x),
});
}
Expand All @@ -191,3 +193,21 @@ fn read_int_array<R: Read>(reader: &mut R) -> Result<NBT> {

Ok(NBT::IntArray(ret))
}

fn read_long_array<R: Read>(reader: &mut R) -> Result<NBT> {
let length = match read_int(reader)? {
NBT::Int(val) => val as usize,
_ => unreachable!(),
};

let mut ret: Vec<i64> = Vec::new();

for _ in 0..length {
ret.push(match read_long(reader)? {
NBT::Long(val) => val,
_ => unreachable!(),
});
}

Ok(NBT::LongArray(ret))
}
16 changes: 16 additions & 0 deletions src/unstable/string_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ fn read_tag(tokens: &mut Tokens, tag_type: &str) -> Result<NBT> {
"List" => read_list(tokens),
"Compound" => read_compound(tokens),
"IntArray" => read_int_array(tokens),
"LongArray" => read_long_array(tokens),
x => bail!("Unknown tag type {}", x),
}
}
Expand Down Expand Up @@ -311,3 +312,18 @@ fn read_int_array(tokens: &mut Tokens) -> Result<NBT> {
}
Ok(NBT::IntArray(tmp))
}

fn read_long_array(tokens: &mut Tokens) -> Result<NBT> {
let len = match read_int(tokens)? {
NBT::Int(x) => x,
_ => unreachable!(),
};
let mut tmp = Vec::with_capacity(len as usize);
for _ in 0..len {
tmp.push(match read_long(tokens)? {
NBT::Long(x) => x,
_ => unreachable!(),
});
}
Ok(NBT::LongArray(tmp))
}
7 changes: 7 additions & 0 deletions src/unstable/string_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ fn write_tag<W: Write>(w: &mut W, tag: &NBT, indent: u64, compound: bool) -> Res
writeln!(w, "{}", val)?;
}
}
&NBT::LongArray(ref x) => {
writeln!(w, " {}", x.len())?;
for val in x {
write_indent(w, indent)?;
writeln!(w, "{}", val)?;
}
}
}

Ok(())
Expand Down
7 changes: 7 additions & 0 deletions src/unstable/tests/string_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ fn invalid_tag_type() {
assert!(err_msg.contains("Unknown tag type NotATagType"));
}

#[test]
fn long_array() {
/* LongArray should compile */
let _: NBTFile =
try_parse_string(r#"None Compound "tag" Compound "BlockEntityTag" LongArray "Items" 0 String "id" "minecraft:shulker_box" End End End"#).unwrap();
}

#[test]
fn unquoted_string() {
/* Since the rewrite of the tokenizer, strings without quotation marks have
Expand Down
11 changes: 11 additions & 0 deletions src/unstable/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn write_tag<W: Write>(w: &mut W, tag: &NBT) -> Result<()> {
&NBT::List(ref x) => write_list(w, x),
&NBT::Compound(ref x) => write_compound(w, x, true),
&NBT::IntArray(ref x) => write_int_array(w, x),
&NBT::LongArray(ref x) => write_long_array(w, x),
}
}

Expand Down Expand Up @@ -132,3 +133,13 @@ fn write_int_array<W: Write>(w: &mut W, val: &Vec<i32>) -> Result<()> {

Ok(())
}

fn write_long_array<W: Write>(w: &mut W, val: &Vec<i64>) -> Result<()> {
write_int(w, val.len() as i32)?;

for x in val {
write_long(w, *x)?;
}

Ok(())
}

0 comments on commit 05fec15

Please sign in to comment.