aboutsummaryrefslogtreecommitdiff
path: root/azalea-nbt/src/encode.rs
blob: 2347bbf3a0064ce5315fe5d798b8488556b92e49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::Error;
use crate::Tag;
use byteorder::{WriteBytesExt, BE};
use flate2::write::{GzEncoder, ZlibEncoder};
use std::io::Write;

impl Tag {
    pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> {
        match self {
            Tag::End => {}
            Tag::Byte(value) => writer.write_i8(*value).map_err(|_| Error::WriteError)?,
            Tag::Short(value) => writer
                .write_i16::<BE>(*value)
                .map_err(|_| Error::WriteError)?,
            Tag::Int(value) => writer
                .write_i32::<BE>(*value)
                .map_err(|_| Error::WriteError)?,
            Tag::Long(value) => writer
                .write_i64::<BE>(*value)
                .map_err(|_| Error::WriteError)?,
            Tag::Float(value) => writer
                .write_f32::<BE>(*value)
                .map_err(|_| Error::WriteError)?,
            Tag::Double(value) => writer
                .write_f64::<BE>(*value)
                .map_err(|_| Error::WriteError)?,
            Tag::ByteArray(value) => {
                writer
                    .write_i32::<BE>(value.len() as i32)
                    .map_err(|_| Error::WriteError)?;
                for byte in value {
                    writer.write_i8(*byte).map_err(|_| Error::WriteError)?;
                }
            }
            Tag::String(value) => {
                writer
                    .write_i16::<BE>(value.len() as i16)
                    .map_err(|_| Error::WriteError)?;
                writer
                    .write_all(value.as_bytes())
                    .map_err(|_| Error::WriteError)?;
            }
            Tag::List(value) => {
                // we just get the type from the first item, or default the type to END
                let type_id = value.first().map(|f| f.id()).unwrap_or(0);
                writer.write_u8(type_id).map_err(|_| Error::WriteError)?;
                writer
                    .write_i32::<BE>(value.len() as i32)
                    .map_err(|_| Error::WriteError)?;
                for tag in value {
                    tag.write_without_end(writer)?;
                }
            }
            Tag::Compound(value) => {
                for (key, tag) in value {
                    writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
                    Tag::String(key.clone()).write_without_end(writer)?;
                    tag.write_without_end(writer)?;
                }
                writer
                    .write_u8(Tag::End.id())
                    .map_err(|_| Error::WriteError)?;
            }
            Tag::IntArray(value) => {
                writer
                    .write_i32::<BE>(value.len() as i32)
                    .map_err(|_| Error::WriteError)?;
                for int in value {
                    writer
                        .write_i32::<BE>(*int)
                        .map_err(|_| Error::WriteError)?;
                }
            }
            Tag::LongArray(value) => {
                writer
                    .write_i32::<BE>(value.len() as i32)
                    .map_err(|_| Error::WriteError)?;
                for long in value {
                    writer
                        .write_i64::<BE>(*long)
                        .map_err(|_| Error::WriteError)?;
                }
            }
        }

        Ok(())
    }

    pub fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
        match self {
            Tag::Compound(value) => {
                for (key, tag) in value {
                    writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
                    Tag::String(key.clone()).write_without_end(writer)?;
                    tag.write_without_end(writer)?;
                }
                Ok(())
            }
            _ => Err(Error::InvalidTag),
        }
    }

    pub fn write_zlib(&self, writer: &mut impl Write) -> Result<(), Error> {
        let mut encoder = ZlibEncoder::new(writer, flate2::Compression::default());
        self.write(&mut encoder)
    }

    pub fn write_gzip(&self, writer: &mut impl Write) -> Result<(), Error> {
        let mut encoder = GzEncoder::new(writer, flate2::Compression::default());
        self.write(&mut encoder)
    }
}