1use crate::Map;
2use std::fmt;
3use std::io;
4use std::ops::Index;
5
6use byteorder::WriteBytesExt;
7use flate2::read::{GzDecoder, ZlibDecoder};
8use flate2::write::{GzEncoder, ZlibEncoder};
9use flate2::Compression;
10
11use error::{Error, Result};
12use raw;
13use value::Value;
14
15#[derive(Clone, Debug, Default, PartialEq)]
39pub struct Blob {
40 title: String,
41 content: Map<String, Value>,
42}
43
44impl Blob {
45 pub fn new() -> Blob {
47 Blob {
48 title: "".to_string(),
49 content: Map::new(),
50 }
51 }
52
53 pub fn named<S>(name: S) -> Blob
55 where
56 S: Into<String>,
57 {
58 Blob {
59 title: name.into(),
60 content: Map::new(),
61 }
62 }
63
64 pub fn from_reader<R>(src: &mut R) -> Result<Blob>
66 where
67 R: io::Read,
68 {
69 let (tag, title) = raw::emit_next_header(src)?;
70 if tag != 0x0a {
74 return Err(Error::NoRootCompound);
75 }
76 let content = Value::from_reader(tag, src)?;
77 match content {
78 Value::Compound(map) => Ok(Blob {
79 title,
80 content: map,
81 }),
82 _ => Err(Error::NoRootCompound),
83 }
84 }
85
86 pub fn from_gzip_reader<R>(src: &mut R) -> Result<Blob>
89 where
90 R: io::Read,
91 {
92 let mut data = GzDecoder::new(src);
94 Blob::from_reader(&mut data)
95 }
96
97 pub fn from_zlib_reader<R>(src: &mut R) -> Result<Blob>
100 where
101 R: io::Read,
102 {
103 Blob::from_reader(&mut ZlibDecoder::new(src))
104 }
105
106 pub fn to_writer<W>(&self, mut dst: &mut W) -> Result<()>
109 where
110 W: io::Write,
111 {
112 dst.write_u8(0x0a)?;
113 raw::write_bare_string(&mut dst, &self.title)?;
114 for (name, ref nbt) in self.content.iter() {
115 dst.write_u8(nbt.id())?;
116 raw::write_bare_string(&mut dst, name)?;
117 nbt.to_writer(&mut dst)?;
118 }
119 raw::close_nbt(&mut dst)
120 }
121
122 pub fn to_gzip_writer<W>(&self, dst: &mut W) -> Result<()>
125 where
126 W: io::Write,
127 {
128 self.to_writer(&mut GzEncoder::new(dst, Compression::default()))
129 }
130
131 pub fn to_zlib_writer<W>(&self, dst: &mut W) -> Result<()>
134 where
135 W: io::Write,
136 {
137 self.to_writer(&mut ZlibEncoder::new(dst, Compression::default()))
138 }
139
140 pub fn insert<S, V>(&mut self, name: S, value: V) -> Result<()>
148 where
149 S: Into<String>,
150 V: Into<Value>,
151 {
152 let nvalue = value.into();
155 if let Value::List(ref vals) = nvalue {
156 if !vals.is_empty() {
157 let first_id = vals[0].id();
158 for nbt in vals {
159 if nbt.id() != first_id {
160 return Err(Error::HeterogeneousList);
161 }
162 }
163 }
164 }
165 self.content.insert(name.into(), nvalue);
166 Ok(())
167 }
168
169 pub fn get<S>(&self, name: S) -> Option<&Value>
171 where
172 S: Into<&'static str>,
173 {
174 self.content.get(name.into())
175 }
176
177 pub fn len_bytes(&self) -> usize {
179 4 + self.title.len()
181 + self
182 .content
183 .iter()
184 .map(Value::size_of_compound_entry)
185 .sum::<usize>()
186 }
187}
188
189impl<'a> Index<&'a str> for Blob {
190 type Output = Value;
191
192 fn index<'b>(&'b self, s: &'a str) -> &'b Value {
193 self.content.get(s).unwrap()
194 }
195}
196
197impl fmt::Display for Blob {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 write!(
200 f,
201 "TAG_Compound(\"{}\"): {} entry(ies)\n{{\n",
202 self.title,
203 self.content.len()
204 )?;
205 for (name, tag) in self.content.iter() {
206 write!(f, " {}(\"{}\"): ", tag.tag_name(), name)?;
207 tag.print(f, 2)?;
208 writeln!(f)?;
209 }
210 write!(f, "}}")
211 }
212}
213
214#[cfg(feature = "serde")]
215use serde::{self, ser::SerializeMap};
216
217#[cfg(feature = "serde")]
218impl serde::Serialize for Blob {
219 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
220 where
221 S: serde::ser::Serializer,
222 {
223 let mut state = serializer.serialize_map(Some(self.content.len()))?;
225 for (k, v) in &self.content {
226 state.serialize_entry(&k, &v)?;
227 }
228 state.end()
229 }
230}
231
232#[cfg(feature = "serde")]
233impl<'de> serde::Deserialize<'de> for Blob {
234 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
235 where
236 D: serde::de::Deserializer<'de>,
237 {
238 let map: Map<String, Value> = serde::de::Deserialize::deserialize(deserializer)?;
240 Ok(Blob {
241 title: "".to_string(),
242 content: map,
243 })
244 }
245}