binary_io/
nbt.rs

1//! Module for the Named Binary Tag, and ShadeNBT format
2//! This module deals with representing the NBT format as a structure,
3//!  and binary serialization. It does not perform Shade version checking, nor does it parse the Shade or CryptoShade header
4//!
5
6use core::panic;
7
8use crate::data::{DeserializeCopy, Deserializeable, Serializeable};
9
10pub mod array {
11    //!
12    //! Types for NBT_Tag*Array
13    use std::{
14        mem::ManuallyDrop,
15        ops::{Deref, DerefMut, Index, IndexMut},
16        ptr,
17        slice::{self, SliceIndex},
18    };
19    ///
20    /// A type which can store a dynamic, fixed-size array of T
21    #[derive(Clone, Debug)]
22    pub struct NbtArray<T> {
23        inner: Box<[T]>,
24    }
25
26    impl<T> Default for NbtArray<T> {
27        fn default() -> Self {
28            Self {
29                inner: Box::new(<[T; 0]>::default()),
30            }
31        }
32    }
33
34    impl<T> Deref for NbtArray<T> {
35        type Target = [T];
36
37        #[inline]
38        fn deref(&self) -> &Self::Target {
39            self.inner.deref()
40        }
41    }
42
43    impl<T> DerefMut for NbtArray<T> {
44        #[inline]
45        fn deref_mut(&mut self) -> &mut Self::Target {
46            self.inner.deref_mut()
47        }
48    }
49
50    impl<T> From<Vec<T>> for NbtArray<T> {
51        #[inline]
52        fn from(v: Vec<T>) -> Self {
53            Self {
54                inner: v.into_boxed_slice(),
55            }
56        }
57    }
58
59    impl<T> From<Box<[T]>> for NbtArray<T> {
60        #[inline]
61        fn from(v: Box<[T]>) -> Self {
62            Self { inner: v }
63        }
64    }
65
66    impl<T, const N: usize> From<[T; N]> for NbtArray<T> {
67        #[inline]
68        fn from(v: [T; N]) -> Self {
69            Self { inner: Box::new(v) }
70        }
71    }
72
73    impl<T, I: SliceIndex<[T]>> Index<I> for NbtArray<T> {
74        type Output = I::Output;
75
76        #[inline]
77        fn index(&self, index: I) -> &Self::Output {
78            self.inner.index(index)
79        }
80    }
81
82    impl<T, I: SliceIndex<[T]>> IndexMut<I> for NbtArray<T> {
83        #[inline]
84        fn index_mut(&mut self, index: I) -> &mut Self::Output {
85            self.inner.index_mut(index)
86        }
87    }
88
89    ///
90    /// Iterator for NbtArray<T>
91    pub struct IntoIter<T> {
92        inner: Box<[ManuallyDrop<T>]>,
93        position: usize,
94    }
95
96    impl<T> Drop for IntoIter<T> {
97        fn drop(&mut self) {
98            for i in self.position..self.inner.len() {
99                // SAFETY:
100                // from position..len has not been taken. position is incremented first
101                unsafe { ManuallyDrop::drop(&mut self.inner[i]) }
102            }
103        }
104    }
105
106    impl<T> Iterator for IntoIter<T> {
107        type Item = T;
108
109        fn next(&mut self) -> Option<Self::Item> {
110            self.position = self.position.checked_add(1).unwrap();
111            // SAFETY:
112            // position is incremented first, so any item taken here will never be visited again
113            self.inner
114                .get_mut(self.position - 1)
115                .map(|m| unsafe { ManuallyDrop::take(m) })
116        }
117    }
118
119    impl<T> IntoIterator for NbtArray<T> {
120        type Item = T;
121
122        type IntoIter = IntoIter<T>;
123
124        fn into_iter(self) -> Self::IntoIter {
125            let len = self.inner.len();
126            let ptr = Box::into_raw(self.inner).cast::<T>();
127            // SAFETY: the slice is from self.inner: Box<[T]>. ManuallyDrop<T> is transparent over T
128            let inner = unsafe {
129                Box::from_raw(ptr::slice_from_raw_parts_mut(
130                    ptr.cast::<ManuallyDrop<T>>(),
131                    len,
132                ))
133            };
134            IntoIter { inner, position: 0 }
135        }
136    }
137
138    ///
139    /// Iterator over references to elements of an NbtArray
140    pub struct Iter<'a, T: 'a>(slice::Iter<'a, T>);
141
142    impl<'a, T: 'a> Iterator for Iter<'a, T> {
143        type Item = &'a T;
144        fn next(&mut self) -> Option<&'a T> {
145            self.0.next()
146        }
147    }
148
149    ///
150    /// Iterator over mutable references to elements of an NbtArray
151    pub struct IterMut<'a, T: 'a>(slice::IterMut<'a, T>);
152
153    impl<'a, T: 'a> Iterator for IterMut<'a, T> {
154        type Item = &'a mut T;
155        fn next(&mut self) -> Option<&'a mut T> {
156            self.0.next()
157        }
158    }
159
160    impl<T> NbtArray<T> {
161        ///
162        /// Returns an iterator of references to the array elements
163        pub fn iter(&self) -> Iter<T> {
164            Iter(self.inner.iter())
165        }
166        ///
167        /// Returns an iterator of mut references to the array elements
168        pub fn iter_mut(&mut self) -> IterMut<T> {
169            IterMut(self.inner.iter_mut())
170        }
171    }
172
173    impl<'a, T> IntoIterator for &'a NbtArray<T> {
174        type Item = &'a T;
175
176        type IntoIter = Iter<'a, T>;
177
178        fn into_iter(self) -> Self::IntoIter {
179            self.iter()
180        }
181    }
182
183    impl<'a, T> IntoIterator for &'a mut NbtArray<T> {
184        type Item = &'a mut T;
185
186        type IntoIter = IterMut<'a, T>;
187
188        fn into_iter(self) -> Self::IntoIter {
189            self.iter_mut()
190        }
191    }
192}
193
194fake_enum! {
195    #[repr(u8)]
196    #[derive(Default,Hash)]
197    pub enum struct TagType{
198        //! The Type of an NBT Tag
199
200        /// Placeholder Tag at the end of Compounds
201        End = 0,
202        /// TAG_Byte
203        Byte = 1,
204        /// TAG_Short
205        Short = 2,
206        /// TAG_Int
207        Int = 3,
208        /// TAG_Long
209        Long = 4,
210        /// TAG_Float
211        Float = 5,
212        /// TAG_Double
213        Double = 6,
214        /// TAG_ByteArray
215        ByteArray = 7,
216        /// TAG_String
217        String = 8,
218        /// TAG_List
219        List = 9,
220        /// TAG_Compound
221        Compound = 10,
222        /// TAG_IntArray
223        IntArray = 11,
224        /// TAG_LongArray
225        LongArray = 12,
226        /// TAG_FloatArray
227        FloatArray = 13,
228        /// TAG_DoubleArray
229        DoubleArray = 14,
230        /// TAG_UUID
231        Uuid = 15
232    }
233}
234
235impl Serializeable for TagType {
236    fn serialize<W: crate::data::DataOutput + ?Sized>(
237        &self,
238        output: &mut W,
239    ) -> std::io::Result<()> {
240        self.0.serialize(output)
241    }
242}
243
244impl Deserializeable for TagType {
245    fn deserialize<R: crate::data::DataInput + ?Sized>(
246        &mut self,
247        input: &mut R,
248    ) -> std::io::Result<()> {
249        self.0.deserialize(input)
250    }
251}
252
253impl DeserializeCopy for TagType {
254    fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
255        input: &mut R,
256    ) -> std::io::Result<Self> {
257        Ok(Self(DeserializeCopy::deserialize_copy(input)?))
258    }
259}
260
261///
262/// Types for Tag_List
263pub mod list {
264    use std::{fmt::Display, io::ErrorKind};
265
266    use crate::data::{DeserializeCopy, Deserializeable, OutOfRange, Serializeable};
267
268    use super::{NbtTag, TagType};
269
270    ///
271    /// A homogenous list of NBT Tags.
272    /// Each element in the List has the same tag
273    #[derive(Clone, Default, Debug)]
274    pub struct NbtList {
275        tag: TagType,
276        elements: Vec<NbtTag>,
277    }
278
279    ///
280    /// The Error returned when adding a tag with an invalid type
281    #[derive(Debug, Clone)]
282    pub struct WrongTagType {
283        tag: NbtTag,
284        expected: TagType,
285    }
286
287    impl Display for WrongTagType {
288        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289            f.write_fmt(format_args!(
290                "Invalid tag with type {:?} (list elements have type {:?})",
291                &self.tag, &self.expected
292            ))
293        }
294    }
295
296    impl WrongTagType {
297        ///
298        /// Unwraps the tag that was attempted to be inserted
299        pub fn into_tag(self) -> NbtTag {
300            self.tag
301        }
302
303        ///
304        /// Gets the type of tags that can be inserted into the list
305        pub fn expected_tag(&self) -> TagType {
306            self.expected
307        }
308    }
309
310    impl std::error::Error for WrongTagType {}
311
312    impl NbtList {
313        ///
314        /// Creates a new NbtList
315        pub const fn new() -> Self {
316            Self {
317                tag: TagType::End,
318                elements: Vec::new(),
319            }
320        }
321
322        ///
323        /// Attempts to insert tag into
324        pub fn insert(&mut self, tag: NbtTag) -> Result<(), WrongTagType> {
325            if self.elements.is_empty() {
326                self.tag = tag.tag_type();
327                self.elements.push(tag);
328                Ok(())
329            } else if self.tag == tag.tag_type() {
330                self.elements.push(tag);
331                Ok(())
332            } else {
333                Err(WrongTagType {
334                    tag,
335                    expected: self.tag,
336                })
337            }
338        }
339    }
340
341    impl Serializeable for NbtList {
342        fn serialize<W: crate::data::DataOutput + ?Sized>(
343            &self,
344            output: &mut W,
345        ) -> std::io::Result<()> {
346            self.tag.serialize(output)?;
347            let len = self.elements.len();
348            if len > (i32::MAX as usize) {
349                return Err(std::io::Error::new(ErrorKind::InvalidData, OutOfRange(len)));
350            }
351            (len as i32).serialize(output)?;
352            for t in &self.elements {
353                t.serialize(output)?;
354            }
355            Ok(())
356        }
357    }
358    impl Deserializeable for NbtList {
359        fn deserialize<R: crate::data::DataInput + ?Sized>(
360            &mut self,
361            input: &mut R,
362        ) -> std::io::Result<()> {
363            let tt = TagType::deserialize_copy(input)?;
364            let len = i32::deserialize_copy(input)?;
365            if len < 0 {
366                return Err(std::io::Error::new(ErrorKind::InvalidData, OutOfRange(len)));
367            }
368            let mut items = Vec::with_capacity(len as usize);
369            items.resize_with(len as usize, || NbtTag::default_for_tag(tt));
370            for i in &mut items {
371                i.deserialize(input)?;
372            }
373            self.tag = tt;
374            self.elements = items;
375            Ok(())
376        }
377    }
378    impl DeserializeCopy for NbtList {
379        fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
380            input: &mut R,
381        ) -> std::io::Result<Self> {
382            let tt = TagType::deserialize_copy(input)?;
383            let len = i32::deserialize_copy(input)?;
384            if len < 0 {
385                return Err(std::io::Error::new(ErrorKind::InvalidData, OutOfRange(len)));
386            }
387            let mut items = Vec::with_capacity(len as usize);
388            items.resize_with(len as usize, || NbtTag::default_for_tag(tt));
389            for i in &mut items {
390                i.deserialize(input)?;
391            }
392            Ok(Self {
393                tag: tt,
394                elements: items,
395            })
396        }
397    }
398}
399
400///
401/// Types for Tag_Compound
402pub mod compound {
403    use std::{collections::HashMap, io::ErrorKind, ops::Index};
404
405    use crate::data::{DeserializeCopy, Deserializeable, Serializeable};
406
407    use super::{NbtTag, TagType};
408
409    ///
410    /// A Compound NBT Tag, containing multiple, named, unordered, NBT Tags
411    #[derive(Clone, Debug, Default)]
412    pub struct NbtCompound {
413        inner: HashMap<String, NbtTag>,
414    }
415
416    impl NbtCompound {
417        ///
418        /// Creates a new, empty, Compound
419        pub fn new() -> NbtCompound {
420            Self {
421                inner: HashMap::new(),
422            }
423        }
424
425        ///
426        /// Gets the element of the Compound with the given Name
427        pub fn get<S: AsRef<str> + ?Sized>(&self, st: &S) -> Option<&NbtTag> {
428            self.inner.get(st.as_ref())
429        }
430
431        ///
432        /// Gets a mutable reference to the element of the Compound with the given Name
433        pub fn get_mut<S: AsRef<str> + ?Sized>(&mut self, st: &S) -> Option<&mut NbtTag> {
434            self.inner.get_mut(st.as_ref())
435        }
436
437        ///
438        /// Inserts a tag into the Compound if the name is unique, otherwise returns the value.
439        pub fn insert(&mut self, name: String, value: NbtTag) -> Option<NbtTag> {
440            self.inner.insert(name, value)
441        }
442    }
443
444    impl<S: AsRef<str>> Index<S> for NbtCompound {
445        type Output = NbtTag;
446
447        fn index(&self, index: S) -> &Self::Output {
448            &self.inner[index.as_ref()]
449        }
450    }
451
452    impl Serializeable for NbtCompound {
453        fn serialize<W: crate::data::DataOutput + ?Sized>(
454            &self,
455            output: &mut W,
456        ) -> std::io::Result<()> {
457            for (k, v) in &self.inner {
458                let ty = v.tag_type();
459                if TagType::End == ty {
460                    return Err(std::io::Error::new(
461                        ErrorKind::InvalidData,
462                        "Embedded Tag Ends cannot be serialized",
463                    ));
464                }
465                ty.serialize(output)?;
466                k.serialize(output)?;
467                v.serialize(output)?;
468            }
469            TagType::End.serialize(output)
470        }
471    }
472
473    impl Deserializeable for NbtCompound {
474        fn deserialize<R: crate::data::DataInput + ?Sized>(
475            &mut self,
476            input: &mut R,
477        ) -> std::io::Result<()> {
478            self.inner.clear();
479            loop {
480                let ty = TagType::deserialize_copy(input)?;
481                if ty == TagType::End {
482                    return Ok(());
483                }
484                let name = String::deserialize_copy(input)?;
485                let mut tag = NbtTag::default_for_tag(ty);
486                tag.deserialize(input)?;
487                self.inner.insert(name, tag);
488            }
489        }
490    }
491
492    impl DeserializeCopy for NbtCompound {
493        fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
494            input: &mut R,
495        ) -> std::io::Result<Self> {
496            let mut inner = HashMap::new();
497            loop {
498                let ty = TagType::deserialize_copy(input)?;
499                if ty == TagType::End {
500                    return Ok(Self { inner });
501                }
502                let name = String::deserialize_copy(input)?;
503                let mut tag = NbtTag::default_for_tag(ty);
504                tag.deserialize(input)?;
505                inner.insert(name, tag);
506            }
507        }
508    }
509}
510
511///
512/// An NBT Tag
513#[derive(Clone, Debug)]
514pub enum NbtTag {
515    ///
516    /// The end Tag
517    /// Appears at the end of each Compound tag
518    End,
519    ///
520    /// A single byte
521    Byte(u8),
522    ///
523    /// A single short
524    Short(i16),
525    ///
526    /// A single int
527    Int(i32),
528    ///
529    /// A single long
530    Long(i64),
531    ///
532    /// A single float
533    Float(f32),
534    ///
535    /// A single double
536    Double(f64),
537    ///
538    /// An array of bytes
539    ByteArray(array::NbtArray<u8>),
540    ///
541    /// A string
542    String(String),
543    ///
544    /// A list of Tags of the same type
545    List(list::NbtList),
546    ///
547    /// A compound tag
548    Compound(compound::NbtCompound),
549    ///
550    /// An array of ints
551    IntArray(array::NbtArray<i32>),
552    ///
553    /// An array of longs
554    LongArray(array::NbtArray<i64>),
555    ///
556    /// An array of floats
557    FloatArray(array::NbtArray<f32>),
558    ///
559    /// An array of doubles
560    DoubleArray(array::NbtArray<f64>),
561    ///
562    /// A UUID
563    Uuid(crate::uuid::UUID),
564}
565
566impl NbtTag {
567    ///
568    /// Gets the type of the tag
569    pub fn tag_type(&self) -> TagType {
570        match self {
571            Self::End => TagType::End,
572            Self::Byte(_) => TagType::Byte,
573            NbtTag::Short(_) => TagType::Short,
574            NbtTag::Int(_) => TagType::Int,
575            NbtTag::Long(_) => TagType::Long,
576            NbtTag::Float(_) => TagType::Float,
577            NbtTag::Double(_) => TagType::Double,
578            NbtTag::ByteArray(_) => TagType::ByteArray,
579            NbtTag::String(_) => TagType::String,
580            NbtTag::List(_) => TagType::List,
581            NbtTag::Compound(_) => TagType::Compound,
582            NbtTag::IntArray(_) => TagType::IntArray,
583            NbtTag::LongArray(_) => TagType::LongArray,
584            NbtTag::FloatArray(_) => TagType::FloatArray,
585            NbtTag::DoubleArray(_) => TagType::DoubleArray,
586            NbtTag::Uuid(_) => TagType::Uuid,
587        }
588    }
589
590    ///
591    /// Returns a default (empty) value for the given tag type
592    ///
593    /// Panics if TagType is not a valid tag
594    pub fn default_for_tag(ty: TagType) -> Self {
595        match ty {
596            TagType::End => Self::End,
597            TagType::Byte => Self::Byte(0),
598            TagType::Short => Self::Short(0),
599            TagType::Int => Self::Int(0),
600            TagType::Float => Self::Float(0.0),
601            TagType::Double => Self::Double(0.0),
602            TagType::ByteArray => Self::ByteArray(Default::default()),
603            TagType::String => Self::String(Default::default()),
604            TagType::List => Self::List(Default::default()),
605            TagType::Compound => Self::Compound(Default::default()),
606            TagType::IntArray => Self::IntArray(Default::default()),
607            TagType::LongArray => Self::LongArray(Default::default()),
608            TagType::FloatArray => Self::FloatArray(Default::default()),
609            TagType::DoubleArray => Self::DoubleArray(Default::default()),
610            TagType::Uuid => Self::Uuid(Default::default()),
611            _ => panic!("Invalid tag type"),
612        }
613    }
614}
615
616impl Serializeable for NbtTag {
617    fn serialize<W: crate::data::DataOutput + ?Sized>(
618        &self,
619        output: &mut W,
620    ) -> std::io::Result<()> {
621        match self {
622            NbtTag::End => Ok(()),
623            NbtTag::Byte(v) => v.serialize(output),
624            NbtTag::Short(v) => v.serialize(output),
625            NbtTag::Int(v) => v.serialize(output),
626            NbtTag::Long(v) => v.serialize(output),
627            NbtTag::Float(v) => v.serialize(output),
628            NbtTag::Double(v) => v.serialize(output),
629            NbtTag::ByteArray(v) => v.serialize(output),
630            NbtTag::String(v) => v.serialize(output),
631            NbtTag::List(v) => v.serialize(output),
632            NbtTag::Compound(v) => v.serialize(output),
633            NbtTag::IntArray(v) => v.serialize(output),
634            NbtTag::LongArray(v) => v.serialize(output),
635            NbtTag::FloatArray(v) => v.serialize(output),
636            NbtTag::DoubleArray(v) => v.serialize(output),
637            NbtTag::Uuid(v) => v.serialize(output),
638        }
639    }
640}
641
642impl Deserializeable for NbtTag {
643    fn deserialize<W: crate::data::DataInput + ?Sized>(
644        &mut self,
645        output: &mut W,
646    ) -> std::io::Result<()> {
647        match self {
648            NbtTag::End => Ok(()),
649            NbtTag::Byte(v) => v.deserialize(output),
650            NbtTag::Short(v) => v.deserialize(output),
651            NbtTag::Int(v) => v.deserialize(output),
652            NbtTag::Long(v) => v.deserialize(output),
653            NbtTag::Float(v) => v.deserialize(output),
654            NbtTag::Double(v) => v.deserialize(output),
655            NbtTag::ByteArray(v) => v.deserialize(output),
656            NbtTag::String(v) => v.deserialize(output),
657            NbtTag::List(v) => v.deserialize(output),
658            NbtTag::Compound(v) => v.deserialize(output),
659            NbtTag::IntArray(v) => v.deserialize(output),
660            NbtTag::LongArray(v) => v.deserialize(output),
661            NbtTag::FloatArray(v) => v.deserialize(output),
662            NbtTag::DoubleArray(v) => v.deserialize(output),
663            NbtTag::Uuid(v) => v.deserialize(output),
664        }
665    }
666}