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