1use bytes::{BufMut, Bytes, BytesMut};
17
18use crate::codec::{Decode, DecodeResult, Encode, EncodeResult, Reader};
19use crate::error::{DecodeError, EncodeError};
20
21pub const MAX_DEPTH: usize = 512;
23
24#[allow(missing_docs)]
26pub mod tag {
27 pub const END: u8 = 0;
28 pub const BYTE: u8 = 1;
29 pub const SHORT: u8 = 2;
30 pub const INT: u8 = 3;
31 pub const LONG: u8 = 4;
32 pub const FLOAT: u8 = 5;
33 pub const DOUBLE: u8 = 6;
34 pub const BYTE_ARRAY: u8 = 7;
35 pub const STRING: u8 = 8;
36 pub const LIST: u8 = 9;
37 pub const COMPOUND: u8 = 10;
38 pub const INT_ARRAY: u8 = 11;
39 pub const LONG_ARRAY: u8 = 12;
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45pub struct RawNbt(Bytes);
46
47impl RawNbt {
48 pub const END: RawNbt = RawNbt(Bytes::from_static(&[0]));
50
51 #[inline]
53 pub fn as_bytes(&self) -> &Bytes {
54 &self.0
55 }
56
57 #[inline]
59 pub fn is_end(&self) -> bool {
60 self.0.first() == Some(&tag::END)
61 }
62
63 pub fn from_bytes(bytes: Bytes) -> DecodeResult<Self> {
65 let mut r = Reader::new(&bytes);
66 let v = Self::read(&mut r)?;
67 r.finish()?;
68 Ok(v)
69 }
70
71 pub fn read(r: &mut Reader<'_>) -> DecodeResult<Self> {
73 let start = r.position();
74 let ty = r.read_u8()?;
75 if ty != tag::END {
76 let name_len = r.read_u16()? as usize;
77 r.skip(name_len)?;
78 skip_payload(r, ty, 0)?;
79 }
80 Ok(RawNbt(r.bytes_since(start)))
81 }
82
83 pub fn read_optional(r: &mut Reader<'_>) -> DecodeResult<Option<Self>> {
85 if r.peek_u8()? == tag::END {
86 r.skip(1)?;
87 Ok(None)
88 } else {
89 Self::read(r).map(Some)
90 }
91 }
92
93 #[inline]
95 pub fn write(&self, w: &mut BytesMut) {
96 w.put_slice(&self.0);
97 }
98
99 #[inline]
101 pub fn write_optional(v: &Option<Self>, w: &mut BytesMut) {
102 match v {
103 Some(n) => n.write(w),
104 None => w.put_u8(tag::END),
105 }
106 }
107
108 pub fn parse(&self) -> DecodeResult<Option<NamedTag>> {
110 let mut r = Reader::new(&self.0);
111 let ty = r.read_u8()?;
112 if ty == tag::END {
113 return Ok(None);
114 }
115 let name = read_mutf8(&mut r)?;
116 let tag = read_payload(&mut r, ty, 0)?;
117 r.finish()?;
118 Ok(Some(NamedTag { name, tag }))
119 }
120
121 pub fn from_named(t: &NamedTag) -> Result<Self, EncodeError> {
123 let mut w = BytesMut::new();
124 t.encode(&mut w)?;
125 Ok(RawNbt(w.freeze()))
126 }
127}
128
129impl Decode for RawNbt {
130 #[inline]
131 fn decode(r: &mut Reader<'_>) -> DecodeResult<Self> {
132 Self::read(r)
133 }
134}
135
136impl Encode for RawNbt {
137 #[inline]
138 fn encode(&self, w: &mut BytesMut) -> EncodeResult {
139 self.write(w);
140 Ok(())
141 }
142}
143
144fn skip_payload(r: &mut Reader<'_>, ty: u8, depth: usize) -> DecodeResult<()> {
146 match ty {
147 tag::BYTE => r.skip(1),
148 tag::SHORT => r.skip(2),
149 tag::INT | tag::FLOAT => r.skip(4),
150 tag::LONG | tag::DOUBLE => r.skip(8),
151 tag::BYTE_ARRAY => {
152 let n = read_array_len(r, 1)?;
153 r.skip(n)
154 }
155 tag::INT_ARRAY => {
156 let n = read_array_len(r, 4)?;
157 r.skip(n * 4)
158 }
159 tag::LONG_ARRAY => {
160 let n = read_array_len(r, 8)?;
161 r.skip(n * 8)
162 }
163 tag::STRING => {
164 let n = r.read_u16()? as usize;
165 r.skip(n)
166 }
167 tag::LIST => {
168 if depth >= MAX_DEPTH {
169 return Err(DecodeError::NbtTooDeep(MAX_DEPTH));
170 }
171 let elem = r.read_u8()?;
172 let n = read_list_len(r, elem)?;
173 match elem {
174 tag::BYTE => r.skip(n),
176 tag::SHORT => r.skip(n * 2),
177 tag::INT | tag::FLOAT => r.skip(n * 4),
178 tag::LONG | tag::DOUBLE => r.skip(n * 8),
179 _ => {
180 for _ in 0..n {
181 skip_payload(r, elem, depth + 1)?;
182 }
183 Ok(())
184 }
185 }
186 }
187 tag::COMPOUND => {
188 if depth >= MAX_DEPTH {
189 return Err(DecodeError::NbtTooDeep(MAX_DEPTH));
190 }
191 loop {
192 let t = r.read_u8()?;
193 if t == tag::END {
194 return Ok(());
195 }
196 let name_len = r.read_u16()? as usize;
197 r.skip(name_len)?;
198 skip_payload(r, t, depth + 1)?;
199 }
200 }
201 other => Err(DecodeError::InvalidNbtTag(other)),
202 }
203}
204
205fn read_array_len(r: &mut Reader<'_>, elem_size: usize) -> DecodeResult<usize> {
207 let n = r.read_i32()?;
208 r.check_count(i64::from(n), elem_size)
209}
210
211fn min_size(elem: u8) -> usize {
213 match elem {
214 tag::BYTE | tag::COMPOUND => 1,
215 tag::SHORT | tag::STRING => 2,
216 tag::INT | tag::FLOAT | tag::BYTE_ARRAY | tag::INT_ARRAY | tag::LONG_ARRAY => 4,
217 tag::LONG | tag::DOUBLE => 8,
218 tag::LIST => 5,
219 _ => 1,
220 }
221}
222
223fn read_list_len(r: &mut Reader<'_>, elem: u8) -> DecodeResult<usize> {
224 let n = r.read_i32()?;
225 if elem == tag::END {
226 return if n <= 0 {
227 Ok(0)
228 } else {
229 Err(DecodeError::NbtEndList)
230 };
231 }
232 if elem > tag::LONG_ARRAY {
233 return Err(DecodeError::InvalidNbtTag(elem));
234 }
235 r.check_count(i64::from(n), min_size(elem))
236}
237
238#[derive(Debug, Clone, PartialEq)]
240pub struct NamedTag {
241 pub name: String,
243 pub tag: Tag,
245}
246
247#[derive(Debug, Clone, PartialEq)]
249#[allow(missing_docs)]
250pub enum Tag {
251 Byte(i8),
252 Short(i16),
253 Int(i32),
254 Long(i64),
255 Float(f32),
256 Double(f64),
257 ByteArray(Bytes),
258 String(String),
259 List(List),
260 Compound(Compound),
261 IntArray(Vec<i32>),
262 LongArray(Vec<i64>),
263}
264
265#[derive(Debug, Clone, PartialEq, Default)]
267pub struct List {
268 pub elem_type: u8,
270 pub items: Vec<Tag>,
272}
273
274#[derive(Debug, Clone, PartialEq, Default)]
276pub struct Compound(pub Vec<(String, Tag)>);
277
278impl Compound {
279 pub fn get(&self, name: &str) -> Option<&Tag> {
281 self.0.iter().find(|(k, _)| k == name).map(|(_, v)| v)
282 }
283}
284
285impl Tag {
286 pub fn type_id(&self) -> u8 {
288 match self {
289 Tag::Byte(_) => tag::BYTE,
290 Tag::Short(_) => tag::SHORT,
291 Tag::Int(_) => tag::INT,
292 Tag::Long(_) => tag::LONG,
293 Tag::Float(_) => tag::FLOAT,
294 Tag::Double(_) => tag::DOUBLE,
295 Tag::ByteArray(_) => tag::BYTE_ARRAY,
296 Tag::String(_) => tag::STRING,
297 Tag::List(_) => tag::LIST,
298 Tag::Compound(_) => tag::COMPOUND,
299 Tag::IntArray(_) => tag::INT_ARRAY,
300 Tag::LongArray(_) => tag::LONG_ARRAY,
301 }
302 }
303
304 pub fn as_compound(&self) -> Option<&Compound> {
306 match self {
307 Tag::Compound(c) => Some(c),
308 _ => None,
309 }
310 }
311}
312
313fn read_payload(r: &mut Reader<'_>, ty: u8, depth: usize) -> DecodeResult<Tag> {
314 Ok(match ty {
315 tag::BYTE => Tag::Byte(r.read_i8()?),
316 tag::SHORT => Tag::Short(r.read_i16()?),
317 tag::INT => Tag::Int(r.read_i32()?),
318 tag::LONG => Tag::Long(r.read_i64()?),
319 tag::FLOAT => Tag::Float(r.read_f32()?),
320 tag::DOUBLE => Tag::Double(r.read_f64()?),
321 tag::BYTE_ARRAY => {
322 let n = read_array_len(r, 1)?;
323 Tag::ByteArray(r.read_bytes(n)?)
324 }
325 tag::INT_ARRAY => {
326 let n = read_array_len(r, 4)?;
327 let s = r.take(n * 4)?;
328 Tag::IntArray(
329 s.as_chunks::<4>()
330 .0
331 .iter()
332 .map(|c| i32::from_be_bytes(*c))
333 .collect(),
334 )
335 }
336 tag::LONG_ARRAY => {
337 let n = read_array_len(r, 8)?;
338 let s = r.take(n * 8)?;
339 Tag::LongArray(
340 s.as_chunks::<8>()
341 .0
342 .iter()
343 .map(|c| i64::from_be_bytes(*c))
344 .collect(),
345 )
346 }
347 tag::STRING => Tag::String(read_mutf8(r)?),
348 tag::LIST => {
349 if depth >= MAX_DEPTH {
350 return Err(DecodeError::NbtTooDeep(MAX_DEPTH));
351 }
352 let elem = r.read_u8()?;
353 let n = read_list_len(r, elem)?;
354 let mut items = Vec::with_capacity(n);
355 for _ in 0..n {
356 items.push(read_payload(r, elem, depth + 1)?);
357 }
358 Tag::List(List {
359 elem_type: elem,
360 items,
361 })
362 }
363 tag::COMPOUND => {
364 if depth >= MAX_DEPTH {
365 return Err(DecodeError::NbtTooDeep(MAX_DEPTH));
366 }
367 let mut entries = Vec::new();
368 loop {
369 let t = r.read_u8()?;
370 if t == tag::END {
371 break;
372 }
373 let name = read_mutf8(r)?;
374 entries.push((name, read_payload(r, t, depth + 1)?));
375 }
376 Tag::Compound(Compound(entries))
377 }
378 other => return Err(DecodeError::InvalidNbtTag(other)),
379 })
380}
381
382impl Encode for NamedTag {
383 fn encode(&self, w: &mut BytesMut) -> EncodeResult {
384 w.put_u8(self.tag.type_id());
385 write_mutf8(w, &self.name)?;
386 write_payload(w, &self.tag, 0)
387 }
388}
389
390fn i32_len(n: usize) -> Result<i32, EncodeError> {
391 i32::try_from(n).map_err(|_| EncodeError::LengthOverflow {
392 len: n,
393 max: i32::MAX as usize,
394 })
395}
396
397fn write_payload(w: &mut BytesMut, t: &Tag, depth: usize) -> EncodeResult {
398 if depth > MAX_DEPTH {
399 return Err(EncodeError::Invalid("NBT nesting too deep"));
400 }
401 match t {
402 Tag::Byte(v) => w.put_i8(*v),
403 Tag::Short(v) => w.put_i16(*v),
404 Tag::Int(v) => w.put_i32(*v),
405 Tag::Long(v) => w.put_i64(*v),
406 Tag::Float(v) => w.put_f32(*v),
407 Tag::Double(v) => w.put_f64(*v),
408 Tag::ByteArray(b) => {
409 w.put_i32(i32_len(b.len())?);
410 w.put_slice(b);
411 }
412 Tag::String(s) => write_mutf8(w, s)?,
413 Tag::List(l) => {
414 w.put_u8(l.elem_type);
415 w.put_i32(i32_len(l.items.len())?);
416 if l.elem_type == tag::END && !l.items.is_empty() {
417 return Err(EncodeError::Invalid("NBT list of TAG_End with elements"));
418 }
419 for item in &l.items {
420 if item.type_id() != l.elem_type {
421 return Err(EncodeError::Invalid("NBT list element of the wrong type"));
422 }
423 write_payload(w, item, depth + 1)?;
424 }
425 }
426 Tag::Compound(c) => {
427 for (k, v) in &c.0 {
428 w.put_u8(v.type_id());
429 write_mutf8(w, k)?;
430 write_payload(w, v, depth + 1)?;
431 }
432 w.put_u8(tag::END);
433 }
434 Tag::IntArray(a) => {
435 w.put_i32(i32_len(a.len())?);
436 for v in a {
437 w.put_i32(*v);
438 }
439 }
440 Tag::LongArray(a) => {
441 w.put_i32(i32_len(a.len())?);
442 for v in a {
443 w.put_i64(*v);
444 }
445 }
446 }
447 Ok(())
448}
449
450fn read_mutf8(r: &mut Reader<'_>) -> DecodeResult<String> {
452 let n = r.read_u16()? as usize;
453 let b = r.take(n)?;
454 decode_mutf8(b)
455}
456
457pub fn decode_mutf8(b: &[u8]) -> DecodeResult<String> {
459 if b.iter().all(|&c| c != 0 && c < 0x80) {
462 return std::str::from_utf8(b)
463 .map(str::to_owned)
464 .map_err(|_| DecodeError::InvalidUtf8);
465 }
466 if !b.iter().any(|&c| c == 0 || c == 0xc0 || c == 0xed)
467 && let Ok(s) = std::str::from_utf8(b)
468 {
469 return Ok(s.to_owned());
470 }
471 let mut units: Vec<u16> = Vec::with_capacity(b.len());
472 let mut i = 0;
473 while i < b.len() {
474 let c = b[i];
475 if c < 0x80 {
476 units.push(u16::from(c));
477 i += 1;
478 } else if c & 0xe0 == 0xc0 {
479 let c2 = *b.get(i + 1).ok_or(DecodeError::InvalidUtf8)?;
480 if c2 & 0xc0 != 0x80 {
481 return Err(DecodeError::InvalidUtf8);
482 }
483 units.push((u16::from(c & 0x1f) << 6) | u16::from(c2 & 0x3f));
484 i += 2;
485 } else if c & 0xf0 == 0xe0 {
486 let c2 = *b.get(i + 1).ok_or(DecodeError::InvalidUtf8)?;
487 let c3 = *b.get(i + 2).ok_or(DecodeError::InvalidUtf8)?;
488 if c2 & 0xc0 != 0x80 || c3 & 0xc0 != 0x80 {
489 return Err(DecodeError::InvalidUtf8);
490 }
491 units.push(
492 (u16::from(c & 0x0f) << 12) | (u16::from(c2 & 0x3f) << 6) | u16::from(c3 & 0x3f),
493 );
494 i += 3;
495 } else {
496 return Err(DecodeError::InvalidUtf8);
497 }
498 }
499 Ok(String::from_utf16_lossy(&units))
500}
501
502fn write_mutf8(w: &mut BytesMut, s: &str) -> EncodeResult {
504 let too_long = |len| EncodeError::LengthOverflow {
505 len,
506 max: u16::MAX as usize,
507 };
508 if s.bytes().all(|b| b != 0 && b < 0xf0) {
510 let n = u16::try_from(s.len()).map_err(|_| too_long(s.len()))?;
511 w.put_u16(n);
512 w.put_slice(s.as_bytes());
513 return Ok(());
514 }
515 let mut out = Vec::with_capacity(s.len() + 8);
516 for u in s.encode_utf16() {
517 match u {
518 0x0001..=0x007f => out.push(u as u8),
519 0x0000 | 0x0080..=0x07ff => {
520 out.push(0xc0 | (u >> 6) as u8);
521 out.push(0x80 | (u & 0x3f) as u8);
522 }
523 _ => {
524 out.push(0xe0 | (u >> 12) as u8);
525 out.push(0x80 | ((u >> 6) & 0x3f) as u8);
526 out.push(0x80 | (u & 0x3f) as u8);
527 }
528 }
529 }
530 let n = u16::try_from(out.len()).map_err(|_| too_long(out.len()))?;
531 w.put_u16(n);
532 w.put_slice(&out);
533 Ok(())
534}
535
536#[cfg(test)]
537mod tests {
538 use super::*;
539
540 const HELLO_WORLD: &[u8] = &[
542 0x0a, 0x00, 0x0b, b'h', b'e', b'l', b'l', b'o', b' ', b'w', b'o', b'r', b'l', b'd', 0x08,
543 0x00, 0x04, b'n', b'a', b'm', b'e', 0x00, 0x09, b'B', b'a', b'n', b'a', b'n', b'r', b'a',
544 b'm', b'a', 0x00,
545 ];
546
547 #[test]
548 fn hello_world() {
549 let b = Bytes::from_static(HELLO_WORLD);
550 let raw = RawNbt::from_bytes(b.clone()).unwrap();
551 let t = raw.parse().unwrap().unwrap();
552 assert_eq!(t.name, "hello world");
553 let c = t.tag.as_compound().unwrap();
554 assert_eq!(c.get("name"), Some(&Tag::String("Bananrama".into())));
555 assert_eq!(RawNbt::from_named(&t).unwrap().as_bytes(), &b);
556 }
557
558 #[test]
559 fn optional_and_end() {
560 let b = Bytes::from_static(&[0x00, 0x01]);
561 let mut r = Reader::new(&b);
562 assert_eq!(RawNbt::read_optional(&mut r), Ok(None));
563 assert_eq!(r.remaining(), 1);
564 let b = Bytes::from_static(&[0x00]);
565 let raw = RawNbt::from_bytes(b).unwrap();
566 assert!(raw.is_end());
567 assert_eq!(raw.parse(), Ok(None));
568 }
569
570 #[test]
571 fn rejects_bad_input() {
572 let b = Bytes::from_static(&[0x0a, 0x00, 0x00, 0x0d, 0x00, 0x00]);
574 assert_eq!(RawNbt::from_bytes(b), Err(DecodeError::InvalidNbtTag(13)));
575 let b = Bytes::from_static(&[0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05]);
577 assert_eq!(RawNbt::from_bytes(b), Err(DecodeError::NbtEndList));
578 let b = Bytes::from_static(&[0x0b, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff]);
580 assert!(matches!(
581 RawNbt::from_bytes(b),
582 Err(DecodeError::LengthTooLarge { .. })
583 ));
584 let mut v = vec![0x09, 0x00, 0x00];
586 for _ in 0..600 {
587 v.extend_from_slice(&[0x09, 0x00, 0x00, 0x00, 0x01]);
588 }
589 let b = Bytes::from(v);
590 assert_eq!(
591 RawNbt::from_bytes(b),
592 Err(DecodeError::NbtTooDeep(MAX_DEPTH))
593 );
594 }
595
596 #[test]
597 fn modified_utf8() {
598 let s = "a\0b\u{e9}\u{1f600}";
599 let mut w = BytesMut::new();
600 write_mutf8(&mut w, s).unwrap();
601 assert_eq!(
603 &w[..],
604 &[
605 0x00, 0x0c, b'a', 0xc0, 0x80, b'b', 0xc3, 0xa9, 0xed, 0xa0, 0xbd, 0xed, 0xb8, 0x80
606 ]
607 );
608 assert_eq!(decode_mutf8(&w[2..]).unwrap(), s);
609 assert_eq!(decode_mutf8(&[0xc3]), Err(DecodeError::InvalidUtf8));
610 assert_eq!(
612 decode_mutf8(&[0xf0, 0x9f, 0x98, 0x80]).unwrap(),
613 "\u{1f600}"
614 );
615 assert_eq!(decode_mutf8(&[0xf8, 0x80]), Err(DecodeError::InvalidUtf8));
616 }
617}