1use super::marker;
2use super::Value;
3use crate::Pair;
4use byteorder::{BigEndian, WriteBytesExt};
5use std::io;
6use std::time;
7
8#[derive(Debug)]
10pub struct Encoder<W> {
11 inner: W,
12}
13impl<W> Encoder<W> {
14 pub fn into_inner(self) -> W {
16 self.inner
17 }
18 pub fn inner(&self) -> &W {
20 &self.inner
21 }
22 pub fn inner_mut(&mut self) -> &mut W {
24 &mut self.inner
25 }
26}
27impl<W> Encoder<W>
28where
29 W: io::Write,
30{
31 pub fn new(inner: W) -> Self {
33 Encoder { inner }
34 }
35
36 pub fn encode(&mut self, value: &Value) -> io::Result<()> {
38 match *value {
39 Value::Undefined => self.encode_undefined(),
40 Value::Null => self.encode_null(),
41 Value::Boolean(x) => self.encode_boolean(x),
42 Value::Integer(x) => self.encode_integer(x),
43 Value::Double(x) => self.encode_double(x),
44 Value::String(ref x) => self.encode_string(x),
45 Value::XmlDocument(ref x) => self.encode_xml_document(x),
46 Value::Date { unix_time } => self.encode_date(unix_time),
47 Value::Array {
48 ref assoc_entries,
49 ref dense_entries,
50 } => self.encode_array(assoc_entries, dense_entries),
51 Value::Object {
52 ref class_name,
53 sealed_count,
54 ref entries,
55 } => self.encode_object(class_name, sealed_count, entries),
56 Value::Xml(ref x) => self.encode_xml(x),
57 Value::ByteArray(ref x) => self.encode_byte_array(x),
58 Value::IntVector {
59 is_fixed,
60 ref entries,
61 } => self.encode_int_vector(is_fixed, entries),
62 Value::UintVector {
63 is_fixed,
64 ref entries,
65 } => self.encode_uint_vector(is_fixed, entries),
66 Value::DoubleVector {
67 is_fixed,
68 ref entries,
69 } => self.encode_double_vector(is_fixed, entries),
70 Value::ObjectVector {
71 ref class_name,
72 is_fixed,
73 ref entries,
74 } => self.encode_object_vector(class_name, is_fixed, entries),
75 Value::Dictionary {
76 is_weak,
77 ref entries,
78 } => self.encode_dictionary(is_weak, entries),
79 }
80 }
81
82 fn encode_undefined(&mut self) -> io::Result<()> {
83 self.inner.write_u8(marker::UNDEFINED)?;
84 Ok(())
85 }
86 fn encode_null(&mut self) -> io::Result<()> {
87 self.inner.write_u8(marker::NULL)?;
88 Ok(())
89 }
90 fn encode_boolean(&mut self, b: bool) -> io::Result<()> {
91 if b {
92 self.inner.write_u8(marker::TRUE)?;
93 } else {
94 self.inner.write_u8(marker::FALSE)?;
95 }
96 Ok(())
97 }
98 fn encode_integer(&mut self, i: i32) -> io::Result<()> {
99 self.inner.write_u8(marker::INTEGER)?;
100 let u29 = if i >= 0 {
101 i as u32
102 } else {
103 ((1 << 29) + i) as u32
104 };
105 self.encode_u29(u29)?;
106 Ok(())
107 }
108 fn encode_double(&mut self, d: f64) -> io::Result<()> {
109 self.inner.write_u8(marker::DOUBLE)?;
110 self.inner.write_f64::<BigEndian>(d)?;
111 Ok(())
112 }
113 fn encode_string(&mut self, s: &str) -> io::Result<()> {
114 self.inner.write_u8(marker::STRING)?;
115 self.encode_utf8(s)?;
116 Ok(())
117 }
118 fn encode_xml_document(&mut self, xml: &str) -> io::Result<()> {
119 self.inner.write_u8(marker::XML_DOC)?;
120 self.encode_utf8(xml)?;
121 Ok(())
122 }
123 fn encode_date(&mut self, unix_time: time::Duration) -> io::Result<()> {
124 let millis = unix_time.as_secs() * 1000 + (unix_time.subsec_nanos() as u64) / 1_000_000;
125 self.inner.write_u8(marker::DATE)?;
126 self.encode_size(0)?;
127 self.inner.write_f64::<BigEndian>(millis as f64)?;
128 Ok(())
129 }
130 fn encode_array(&mut self, assoc: &[Pair<String, Value>], dense: &[Value]) -> io::Result<()> {
131 self.inner.write_u8(marker::ARRAY)?;
132 self.encode_size(dense.len())?;
133 self.encode_pairs(assoc)?;
134 dense
135 .iter()
136 .map(|v| self.encode(v))
137 .collect::<io::Result<Vec<_>>>()?;
138 Ok(())
139 }
140 fn encode_object(
141 &mut self,
142 class_name: &Option<String>,
143 sealed_count: usize,
144 entries: &[Pair<String, Value>],
145 ) -> io::Result<()> {
146 self.inner.write_u8(marker::OBJECT)?;
147 self.encode_trait(class_name, sealed_count, entries)?;
148 for e in entries.iter().take(sealed_count) {
149 self.encode(&e.value)?;
150 }
151 if entries.len() > sealed_count {
152 self.encode_pairs(&entries[sealed_count..])?;
153 }
154 Ok(())
155 }
156 fn encode_xml(&mut self, xml: &str) -> io::Result<()> {
157 self.inner.write_u8(marker::XML)?;
158 self.encode_utf8(xml)?;
159 Ok(())
160 }
161 fn encode_byte_array(&mut self, bytes: &[u8]) -> io::Result<()> {
162 self.inner.write_u8(marker::BYTE_ARRAY)?;
163 self.encode_size(bytes.len())?;
164 self.inner.write_all(bytes)?;
165 Ok(())
166 }
167 fn encode_int_vector(&mut self, is_fixed: bool, vec: &[i32]) -> io::Result<()> {
168 self.inner.write_u8(marker::VECTOR_INT)?;
169 self.encode_size(vec.len())?;
170 self.inner.write_u8(is_fixed as u8)?;
171 for &x in vec {
172 self.inner.write_i32::<BigEndian>(x)?;
173 }
174 Ok(())
175 }
176 fn encode_uint_vector(&mut self, is_fixed: bool, vec: &[u32]) -> io::Result<()> {
177 self.inner.write_u8(marker::VECTOR_UINT)?;
178 self.encode_size(vec.len())?;
179 self.inner.write_u8(is_fixed as u8)?;
180 for &x in vec {
181 self.inner.write_u32::<BigEndian>(x)?;
182 }
183 Ok(())
184 }
185 fn encode_double_vector(&mut self, is_fixed: bool, vec: &[f64]) -> io::Result<()> {
186 self.inner.write_u8(marker::VECTOR_DOUBLE)?;
187 self.encode_size(vec.len())?;
188 self.inner.write_u8(is_fixed as u8)?;
189 for &x in vec {
190 self.inner.write_f64::<BigEndian>(x)?;
191 }
192 Ok(())
193 }
194 fn encode_object_vector(
195 &mut self,
196 class_name: &Option<String>,
197 is_fixed: bool,
198 vec: &[Value],
199 ) -> io::Result<()> {
200 self.inner.write_u8(marker::VECTOR_OBJECT)?;
201 self.encode_size(vec.len())?;
202 self.inner.write_u8(is_fixed as u8)?;
203 self.encode_utf8(class_name.as_ref().map_or("*", |s| s))?;
204 for x in vec {
205 self.encode(x)?;
206 }
207 Ok(())
208 }
209 fn encode_dictionary(
210 &mut self,
211 is_weak: bool,
212 entries: &[Pair<Value, Value>],
213 ) -> io::Result<()> {
214 self.inner.write_u8(marker::DICTIONARY)?;
215 self.encode_size(entries.len())?;
216 self.inner.write_u8(is_weak as u8)?;
217 for e in entries {
218 self.encode(&e.key)?;
219 self.encode(&e.value)?;
220 }
221 Ok(())
222 }
223 fn encode_trait(
224 &mut self,
225 class_name: &Option<String>,
226 sealed_count: usize,
227 entries: &[Pair<String, Value>],
228 ) -> io::Result<()> {
229 assert!(sealed_count <= entries.len());
230 let not_reference = 1;
231 let is_externalizable = false as usize;
232 let is_dynamic = (sealed_count < entries.len()) as usize;
233 let u28 =
234 (sealed_count << 3) | (is_dynamic << 2) | (is_externalizable << 1) | not_reference;
235 self.encode_size(u28)?;
236
237 let class_name = class_name.as_ref().map_or("", |s| s);
238 self.encode_utf8(class_name)?;
239 for e in entries.iter().take(sealed_count) {
240 self.encode_utf8(&e.key)?;
241 }
242 Ok(())
243 }
244 fn encode_size(&mut self, size: usize) -> io::Result<()> {
245 assert!(size < (1 << 28));
246 let not_reference = 1;
247 self.encode_u29(((size << 1) | not_reference) as u32)
248 }
249 #[allow(clippy::zero_prefixed_literal, clippy::identity_op)]
250 fn encode_u29(&mut self, u29: u32) -> io::Result<()> {
251 if u29 < 0x80 {
252 self.inner.write_u8(u29 as u8)?;
253 } else if u29 < 0x4000 {
254 let b1 = ((u29 >> 0) & 0b0111_1111) as u8;
255 let b2 = ((u29 >> 7) | 0b1000_0000) as u8;
256 for b in &[b2, b1] {
257 self.inner.write_u8(*b)?;
258 }
259 } else if u29 < 0x20_0000 {
260 let b1 = ((u29 >> 00) & 0b0111_1111) as u8;
261 let b2 = ((u29 >> 07) | 0b1000_0000) as u8;
262 let b3 = ((u29 >> 14) | 0b1000_0000) as u8;
263 for b in &[b3, b2, b1] {
264 self.inner.write_u8(*b)?;
265 }
266 } else if u29 < 0x4000_0000 {
267 let b1 = ((u29 >> 00) & 0b1111_1111) as u8;
268 let b2 = ((u29 >> 08) | 0b1000_0000) as u8;
269 let b3 = ((u29 >> 15) | 0b1000_0000) as u8;
270 let b4 = ((u29 >> 22) | 0b1000_0000) as u8;
271 for b in &[b4, b3, b2, b1] {
272 self.inner.write_u8(*b)?;
273 }
274 } else {
275 panic!("Too large number: {}", u29);
276 }
277 Ok(())
278 }
279 pub fn encode_utf8(&mut self, s: &str) -> io::Result<()> {
284 self.encode_size(s.len())?;
285 self.inner.write_all(s.as_bytes())?;
286 Ok(())
287 }
288 fn encode_pairs(&mut self, pairs: &[Pair<String, Value>]) -> io::Result<()> {
289 for p in pairs {
290 self.encode_utf8(&p.key)?;
291 self.encode(&p.value)?;
292 }
293 self.encode_utf8("")?;
294 Ok(())
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::super::Value;
301 use crate::Pair;
302 use std::time;
303
304 macro_rules! encode_eq {
305 ($value:expr, $file:expr) => {{
306 let expected = include_bytes!(concat!("../testdata/", $file));
307 let mut buf = Vec::new();
308 $value.write_to(&mut buf).unwrap();
309 assert_eq!(buf, &expected[..]);
310 }};
311 }
312 macro_rules! encode_and_decode {
313 ($value:expr) => {{
314 let v = $value;
315 let mut buf = Vec::new();
316 v.write_to(&mut buf).unwrap();
317 assert_eq!(v, Value::read_from(&mut &buf[..]).unwrap());
318 }};
319 }
320
321 #[test]
322 fn encodes_undefined() {
323 encode_eq!(Value::Undefined, "amf3-undefined.bin");
324 }
325 #[test]
326 fn encodes_null() {
327 encode_eq!(Value::Null, "amf3-null.bin");
328 }
329 #[test]
330 fn encodes_boolean() {
331 encode_eq!(Value::Boolean(true), "amf3-true.bin");
332 encode_eq!(Value::Boolean(false), "amf3-false.bin");
333 }
334 #[test]
335 fn encodes_integer() {
336 encode_eq!(Value::Integer(0), "amf3-0.bin");
337 encode_eq!(Value::Integer(0b1000_0000), "amf3-integer-2byte.bin");
338 encode_eq!(
339 Value::Integer(0b100_0000_0000_0000),
340 "amf3-integer-3byte.bin"
341 );
342 encode_eq!(Value::Integer(-0x1000_0000), "amf3-min.bin");
343 encode_eq!(Value::Integer(0xFFF_FFFF), "amf3-max.bin");
344 }
345 #[test]
346 fn encodes_double() {
347 encode_eq!(Value::Double(3.5), "amf3-float.bin");
348 encode_eq!(Value::Double(2f64.powf(1000f64)), "amf3-bignum.bin");
349 encode_eq!(Value::Double(-0x1000_0001 as f64), "amf3-large-min.bin");
350 encode_eq!(Value::Double(268_435_456_f64), "amf3-large-max.bin");
351 }
352 #[test]
353 fn encodes_string() {
354 encode_eq!(s("String . String"), "amf3-string.bin");
355 encode_eq!(
356 dense_array(&[i(5), s("Shift テスト"), s("UTF テスト"), i(5)][..]),
357 "amf3-complex-encoded-string-array.bin"
358 );
359 }
360 #[test]
361 fn encodes_array() {
362 encode_eq!(
363 dense_array(&[i(1), i(2), i(3), i(4), i(5)][..]),
364 "amf3-primitive-array.bin"
365 );
366 encode_and_decode!(Value::Array {
367 assoc_entries: [("2", s("bar3")), ("foo", s("bar")), ("asdf", s("fdsa"))]
368 .iter()
369 .map(|e| pair(e.0, e.1.clone()))
370 .collect(),
371 dense_entries: vec![s("bar"), s("bar1"), s("bar2")],
372 });
373 }
374 #[test]
375 fn encodes_object() {
376 encode_eq!(
377 typed_obj(
378 "org.amf.ASClass",
379 &[("foo", s("bar")), ("baz", Value::Null)][..]
380 ),
381 "amf3-typed-object.bin"
382 );
383 encode_eq!(
384 obj(&[("foo", s("bar")), ("answer", i(42))][..]),
385 "amf3-hash.bin"
386 );
387 }
388 #[test]
389 fn encodes_xml_doc() {
390 encode_eq!(
391 Value::XmlDocument("<parent><child prop=\"test\" /></parent>".to_string()),
392 "amf3-xml-doc.bin"
393 );
394 }
395 #[test]
396 fn encodes_xml() {
397 let xml = Value::Xml("<parent><child prop=\"test\"/></parent>".to_string());
398 encode_eq!(xml, "amf3-xml.bin");
399 }
400 #[test]
401 fn encodes_byte_array() {
402 encode_eq!(
403 Value::ByteArray(vec![
404 0, 3, 227, 129, 147, 227, 130, 140, 116, 101, 115, 116, 64
405 ]),
406 "amf3-byte-array.bin"
407 );
408 }
409 #[test]
410 fn encodes_date() {
411 let d = Value::Date {
412 unix_time: time::Duration::from_secs(0),
413 };
414 encode_eq!(d, "amf3-date.bin");
415 }
416 #[test]
417 fn encodes_dictionary() {
418 let entries = vec![
419 (s("bar"), s("asdf1")),
420 (
421 typed_obj(
422 "org.amf.ASClass",
423 &[("foo", s("baz")), ("baz", Value::Null)][..],
424 ),
425 s("asdf2"),
426 ),
427 ];
428 encode_and_decode!(dic(&entries));
429 encode_eq!(dic(&[][..]), "amf3-empty-dictionary.bin");
430 }
431 #[test]
432 fn encodes_vector() {
433 encode_eq!(
434 Value::IntVector {
435 is_fixed: false,
436 entries: vec![4, -20, 12],
437 },
438 "amf3-vector-int.bin"
439 );
440
441 encode_eq!(
442 Value::UintVector {
443 is_fixed: false,
444 entries: vec![4, 20, 12],
445 },
446 "amf3-vector-uint.bin"
447 );
448
449 encode_eq!(
450 Value::DoubleVector {
451 is_fixed: false,
452 entries: vec![4.3, -20.6],
453 },
454 "amf3-vector-double.bin"
455 );
456
457 let objects = vec![
458 typed_obj(
459 "org.amf.ASClass",
460 &[("foo", s("foo")), ("baz", Value::Null)][..],
461 ),
462 typed_obj(
463 "org.amf.ASClass",
464 &[("foo", s("bar")), ("baz", Value::Null)][..],
465 ),
466 typed_obj(
467 "org.amf.ASClass",
468 &[("foo", s("baz")), ("baz", Value::Null)][..],
469 ),
470 ];
471 encode_and_decode!(Value::ObjectVector {
472 class_name: Some("org.amf.ASClass".to_string()),
473 is_fixed: false,
474 entries: objects,
475 });
476 }
477
478 fn i(i: i32) -> Value {
479 Value::Integer(i)
480 }
481 fn s(s: &str) -> Value {
482 Value::String(s.to_string())
483 }
484 fn pair(key: &str, value: Value) -> Pair<String, Value> {
485 Pair {
486 key: key.to_string(),
487 value,
488 }
489 }
490 fn dense_array(entries: &[Value]) -> Value {
491 Value::Array {
492 assoc_entries: Vec::new(),
493 dense_entries: entries.to_vec(),
494 }
495 }
496 fn dic(entries: &[(Value, Value)]) -> Value {
497 Value::Dictionary {
498 is_weak: false,
499 entries: entries
500 .iter()
501 .map(|e| Pair {
502 key: e.0.clone(),
503 value: e.1.clone(),
504 })
505 .collect(),
506 }
507 }
508 fn obj(entries: &[(&str, Value)]) -> Value {
509 Value::Object {
510 class_name: None,
511 sealed_count: 0,
512 entries: entries.iter().map(|e| pair(e.0, e.1.clone())).collect(),
513 }
514 }
515 fn typed_obj(class: &str, entries: &[(&str, Value)]) -> Value {
516 Value::Object {
517 class_name: Some(class.to_string()),
518 sealed_count: entries.len(),
519 entries: entries.iter().map(|e| pair(e.0, e.1.clone())).collect(),
520 }
521 }
522}