1use std::{
2 borrow::Cow,
3 fmt,
4 io::{self, Read},
5 mem,
6};
7
8use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
9
10#[derive(Debug)]
11pub enum Error {
12 Io(::std::io::Error),
14 Version(u32),
16 Magic([u8; 4]),
18 Length {
19 length: u32,
21 length_read: usize,
23 },
24}
25
26#[derive(Clone, Debug)]
28pub struct Glb<'a> {
29 pub header: Header,
31 pub content: Cow<'a, [u8]>,
33 pub body: Option<Cow<'a, [u8]>>,
35}
36
37#[derive(Copy, Clone, Debug, Default)]
39#[repr(C)]
40pub struct Header {
41 pub magic: [u8; 4],
43 pub version: u32,
45 pub length: u32,
47 pub content_length: u32,
49 pub content_format: u32,
51}
52
53impl Header {
54 fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, Error> {
55 use self::Error::Io;
56 let mut magic = [0; 4];
57 reader.read_exact(&mut magic).map_err(Io)?;
58 if &magic == b"glTF" {
62 Ok(Self {
63 magic,
64 version: reader.read_u32::<LittleEndian>().map_err(Io)?,
65 length: reader.read_u32::<LittleEndian>().map_err(Io)?,
66 content_length: reader.read_u32::<LittleEndian>().map_err(Io)?,
67 content_format: reader.read_u32::<LittleEndian>().map_err(Io)?,
68 })
69 } else {
70 Err(Error::Magic(magic))
71 }
72 }
73
74 fn size_of() -> usize {
75 20
76 }
77}
78
79impl<'a> Glb<'a> {
80 pub fn from_slice(mut data: &'a [u8]) -> Result<Self, crate::GLTF_Error> {
81 let header = Header::from_reader(&mut data)
82 .and_then(|header| {
83 let contents_length = header.length as usize - Header::size_of();
84 if contents_length <= data.len() {
85 Ok(header)
86 } else {
87 Err(Error::Length {
88 length: contents_length as u32,
89 length_read: data.len(),
90 })
91 }
92 })
93 .map_err(crate::GLTF_Error::Binary)?;
94 match header.version {
95 1 => {
96 let content_len = header.content_length;
97 let mut content_buf = vec![0; content_len as usize];
98 if let Err(e) = (&mut data).read_exact(&mut content_buf).map_err(Error::Io) {
99 return Err(crate::GLTF_Error::Binary(e));
100 }
101
102 let body_len = header.length - Header::size_of() as u32 - content_len;
103 let body = if body_len != 0 {
104 let mut body_buf = vec![0; body_len as usize];
105 if let Err(e) = (&mut data).read_exact(&mut body_buf).map_err(Error::Io) {
106 return Err(crate::GLTF_Error::Binary(e));
107 }
108 Some(body_buf)
109 } else {
110 None
111 };
112
113 Ok(Glb {
114 header,
115 content: content_buf.into(),
116 body: body.map(|x| x.into()),
117 })
118 }
119 x => Err(crate::GLTF_Error::Binary(Error::Version(x))),
120 }
121 }
122 pub fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, crate::GLTF_Error> {
123 let header = Header::from_reader(&mut reader).map_err(crate::GLTF_Error::Binary)?;
124 match header.version {
125 1 => {
126 let content_len = header.content_length;
127 let mut content_buf = vec![0; content_len as usize];
128 if let Err(e) = reader.read_exact(&mut content_buf).map_err(Error::Io) {
129 return Err(crate::GLTF_Error::Binary(e));
130 }
131
132 let body_len = header.length - Header::size_of() as u32 - content_len;
133 let body = if body_len != 0 {
134 let mut body_buf = vec![0; body_len as usize];
135 if let Err(e) = reader.read_exact(&mut body_buf).map_err(Error::Io) {
136 return Err(crate::GLTF_Error::Binary(e));
137 }
138 Some(body_buf)
139 } else {
140 None
141 };
142
143 Ok(Glb {
144 header,
145 content: content_buf.to_vec().into(),
146 body: body.map(|x| x.to_vec()).map(|x| x.into()),
147 })
148 }
149 x => Err(crate::GLTF_Error::Binary(Error::Version(x))),
150 }
151 }
152 pub fn to_writer<W: io::Write>(&self, mut writer: W) -> Result<(), crate::GLTF_Error> {
153 {
155 let magic = b"glTF";
156 let version: u32 = 1;
157 let mut length = mem::size_of::<Header>() + self.content.len();
158 align_to_multiple_of_four(&mut length);
159 if let Some(body) = self.body.as_ref() {
160 length += body.len();
161 align_to_multiple_of_four(&mut length);
162 }
163
164 writer.write_all(&magic[..])?;
165 writer.write_u32::<LittleEndian>(version)?;
166 writer.write_u32::<LittleEndian>(length as u32)?;
167 }
168
169 {
171 let mut length = self.content.len();
172 let format: u32 = 0;
173 align_to_multiple_of_four(&mut length);
174 let padding = length - self.content.len();
175
176 writer.write_u32::<LittleEndian>(length as u32)?;
177 writer.write_u32::<LittleEndian>(format)?;
178 writer.write_all(&self.content)?;
179 for _ in 0..padding {
180 writer.write_u8(0x20)?;
181 }
182 }
183
184 if let Some(body) = self.body.as_ref() {
185 let mut length = body.len();
186 align_to_multiple_of_four(&mut length);
187 let padding = length - body.len();
188 writer.write_all(body)?;
189 for _ in 0..padding {
190 writer.write_u8(0)?;
191 }
192 }
193
194 Ok(())
195 }
196}
197
198impl fmt::Display for Error {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 write!(
201 f,
202 "{}",
203 match *self {
204 Error::Version(_) => "unsupported version",
205 Error::Magic(_) => "not glTF magic",
206 Error::Length { .. } => "could not completely read the object",
207 Error::Io(ref e) => return e.fmt(f),
208 }
209 )
210 }
211}
212
213impl ::std::error::Error for Error {}
214
215fn align_to_multiple_of_four(n: &mut usize) {
216 *n = (*n + 3) & !3;
217}