1pub mod basic_data_types;
2pub mod bit_count;
3pub mod button;
4pub mod display;
5mod error;
6pub mod gradient;
7pub mod io_bits;
8pub mod morph_shape;
9pub mod movie;
10pub mod primitives;
11pub mod shape;
12pub mod sound;
13pub mod tags;
14pub mod text;
15
16use crate::movie::emit_swf as write_swf;
17use crate::tags::emit_tag as write_tag;
18use swf_types::{CompressionMethod, Movie, Tag};
19
20pub use error::SwfEmitError;
21
22pub fn emit_swf(value: &Movie, compression_method: CompressionMethod) -> Result<Vec<u8>, SwfEmitError> {
23 let mut swf_writer: Vec<u8> = Vec::new();
24 match compression_method {
25 CompressionMethod::None => crate::movie::emit_uncompressed_swf_to_buf(&mut swf_writer, value)?,
26 _ => write_swf(&mut swf_writer, value, compression_method)?,
27 }
28 Ok(swf_writer)
29}
30
31pub fn emit_tag(value: &Tag, swf_version: u8) -> std::io::Result<Vec<u8>> {
32 let mut tag_writer: Vec<u8> = Vec::new();
33 write_tag(&mut tag_writer, value, swf_version)?;
34 Ok(tag_writer)
35}
36
37#[cfg(test)]
38mod tests {
39 use std::path::Path;
40
41 use ::test_generator::test_expand_paths;
42 use swf_types::Matrix;
43 use swf_types::Rect;
44 use swf_types::{ColorTransformWithAlpha, CompressionMethod, Header, Movie, SwfSignature, Tag};
45
46 use crate::basic_data_types::{emit_color_transform_with_alpha, emit_leb128_u32, emit_matrix, emit_rect};
47 use crate::movie::{emit_header, emit_swf_signature};
48 use crate::primitives::emit_le_f16;
49 use crate::{emit_swf, emit_tag};
50
51 test_expand_paths! { test_emit_movie; "../tests/movies/*/" }
52 fn test_emit_movie(path: &str) {
53 let path: &Path = Path::new(path);
54 let _name = path
55 .components()
56 .last()
57 .unwrap()
58 .as_os_str()
59 .to_str()
60 .expect("Failed to retrieve sample name");
61
62 let ast_path = path.join("ast.json");
63 let ast_file = ::std::fs::File::open(ast_path).expect("Failed to open AST file");
64 let ast_reader = ::std::io::BufReader::new(ast_file);
65 let value: Movie = serde_json::from_reader(ast_reader).expect("Failed to read value");
66
67 const COMPRESSION_METHODS: &[(CompressionMethod, &str)] = &[
68 (CompressionMethod::None, "local-main.rs.swf"),
69 #[cfg(feature="deflate")]
70 (CompressionMethod::Deflate, "local-main-deflate.rs.swf"),
71 #[cfg(feature="lzma")]
72 (CompressionMethod::Lzma, "local-main-lzma.rs.swf"),
73 ];
74
75 for (method, filename) in COMPRESSION_METHODS {
76 let actual_bytes = emit_swf(&value, *method).unwrap();
77
78 let actual_movie_path = path.join(*filename);
79 ::std::fs::write(actual_movie_path, &actual_bytes).expect("Failed to write actual SWF");
80
81 let actual_movie = swf_parser::parse_swf(&actual_bytes).expect("Failed to parse movie");
82
83 assert_eq!(actual_movie, value);
84 }
85 }
86
87 test_expand_paths! { test_emit_tag; "../tests/tags/*/*/" }
88 fn test_emit_tag(path: &str) {
89 let path: &Path = Path::new(path);
90 let name = path
91 .components()
92 .last()
93 .unwrap()
94 .as_os_str()
95 .to_str()
96 .expect("Failed to retrieve sample name");
97
98 let value_path = path.join("value.json");
99 let value_file = ::std::fs::File::open(value_path).expect("Failed to open value file");
100 let value_reader = ::std::io::BufReader::new(value_file);
101 let value = serde_json::from_reader::<_, Tag>(value_reader).expect("Failed to read value");
102
103 let swf_version: u8 = match name {
104 "po2-swf5" => 5,
105 _ => 10,
106 };
107
108 let actual_bytes = emit_tag(&value, swf_version).unwrap();
109
110 let expected_bytes: Vec<u8> = {
111 match ::std::fs::read(path.join("output.bytes")) {
112 Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
113 ::std::fs::read(path.join("input.bytes")).expect("Failed to read expected output (input.bytes)")
114 }
115 r => r.expect("Failed to read expected output (output.bytes)"),
116 }
117 };
118
119 assert_eq!(expected_bytes, actual_bytes);
120 }
121
122 macro_rules! test_various_ref_emitter_impl {
123 ($name:ident, $glob:expr, $emitter:ident, $type:ty) => {
124 test_expand_paths! { $name; $glob }
125 fn $name(path: &str) {
126 let path: &Path = Path::new(path);
127 let _name = path
128 .components()
129 .last()
130 .unwrap()
131 .as_os_str()
132 .to_str()
133 .expect("Failed to retrieve sample name");
134
135 let value_path = path.join("value.json");
136 let value_file = ::std::fs::File::open(value_path).expect("Failed to open value file");
137 let value_reader = ::std::io::BufReader::new(value_file);
138 let value = serde_json::from_reader::<_, $type>(value_reader).expect("Failed to read value");
139
140 let mut actual_bytes = Vec::new();
141 $emitter(&mut actual_bytes, &value).expect("Failed to emit");
142
143 let expected_bytes: Vec<u8> = {
144 match ::std::fs::read(path.join("output.bytes")) {
145 Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
146 ::std::fs::read(path.join("input.bytes")).expect("Failed to read expected output (input.bytes)")
147 }
148 r => r.expect("Failed to read expected output (output.bytes)"),
149 }
150 };
151
152 assert_eq!(expected_bytes, actual_bytes);
153 }
154 };
155 }
156
157 macro_rules! test_various_copy_emitter_impl {
160 ($name:ident, $glob:expr, $emitter:ident, $type:ty) => {
161 test_expand_paths! { $name; $glob }
162 fn $name(path: &str) {
163 let path: &Path = Path::new(path);
164 let _name = path
165 .components()
166 .last()
167 .unwrap()
168 .as_os_str()
169 .to_str()
170 .expect("Failed to retrieve sample name");
171
172 let value_path = path.join("value.json");
173 let value_file = ::std::fs::File::open(value_path).expect("Failed to open value file");
174 let value_reader = ::std::io::BufReader::new(value_file);
175 let value = serde_json::from_reader::<_, $type>(value_reader).expect("Failed to read value");
176
177 let mut actual_bytes = Vec::new();
178 $emitter(&mut actual_bytes, value).expect("Failed to emit");
179
180 let expected_bytes: Vec<u8> = {
181 match ::std::fs::read(path.join("output.bytes")) {
182 Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
183 ::std::fs::read(path.join("input.bytes")).expect("Failed to read expected output (input.bytes)")
184 }
185 r => r.expect("Failed to read expected output (output.bytes)"),
186 }
187 };
188
189 assert_eq!(expected_bytes, actual_bytes);
190 }
191 };
192 }
193
194 test_various_ref_emitter_impl!(
195 test_emit_color_transform_with_alpha,
196 "../tests/various/color-transform-with-alpha/*/",
197 emit_color_transform_with_alpha,
198 ColorTransformWithAlpha
199 );
200
201 test_various_copy_emitter_impl!(test_emit_le_f16, "../tests/various/float16-le/*/", emit_le_f16, f32);
202
203 test_various_ref_emitter_impl!(test_emit_header, "../tests/various/header/*/", emit_header, Header);
204
205 test_various_ref_emitter_impl!(test_emit_matrix, "../tests/various/matrix/*/", emit_matrix, Matrix);
206
207 test_various_ref_emitter_impl!(test_emit_rect, "../tests/various/rect/*/", emit_rect, Rect);
208
209 test_various_ref_emitter_impl!(
210 test_emit_swf_signature,
211 "../tests/various/swf-signature/*/",
212 emit_swf_signature,
213 SwfSignature
214 );
215
216 test_various_copy_emitter_impl!(
217 test_emit_leb128_u32,
218 "../tests/various/uint32-leb128/*/",
219 emit_leb128_u32,
220 u32
221 );
222}