1use crate::{
2 error::{Error, Result},
3 string::SwfStr,
4 tag_code::TagCode,
5 types::*,
6};
7use bitstream_io::BitWrite;
8use byteorder::{LittleEndian, WriteBytesExt};
9use std::cmp::max;
10use std::io::{self, Write};
11
12pub fn write_swf<W: Write>(header: &Header, tags: &[Tag<'_>], output: W) -> Result<()> {
37 let mut swf_body = Vec::new();
39 {
40 let mut writer = Writer::new(&mut swf_body, header.version);
41 writer.write_tag_list(tags)?;
43 }
44 write_swf_raw_tags(header, &swf_body, output)
45}
46
47pub fn write_swf_raw_tags<W: Write>(header: &Header, tags: &[u8], mut output: W) -> Result<()> {
50 let signature = match header.compression {
51 Compression::None => b"FWS",
52 Compression::Zlib => b"CWS",
53 Compression::Lzma => b"ZWS",
54 };
55 output.write_all(&signature[..])?;
56 output.write_u8(header.version)?;
57
58 let mut swf_body = Vec::new();
60 {
61 let mut writer = Writer::new(&mut swf_body, header.version);
62
63 writer.write_rectangle(&header.stage_size)?;
64 writer.write_fixed8(header.frame_rate)?;
65 writer.write_u16(header.num_frames)?;
66 }
67 swf_body.extend_from_slice(tags);
68
69 output.write_u32::<LittleEndian>(swf_body.len() as u32 + 8)?;
72
73 match header.compression {
75 Compression::None => output.write_all(&swf_body)?,
76
77 Compression::Zlib => write_zlib_swf(&mut output, &swf_body)?,
78
79 Compression::Lzma => {
80 write_lzma_swf(&mut output, &swf_body)?;
81 }
84 }
85
86 Ok(())
87}
88
89#[cfg(feature = "flate2")]
90fn write_zlib_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
91 use flate2::write::ZlibEncoder;
92 use flate2::Compression;
93 let mut encoder = ZlibEncoder::new(&mut output, Compression::best());
94 encoder.write_all(swf_body)?;
95 encoder.finish()?;
96 Ok(())
97}
98
99#[cfg(not(feature = "flate2"))]
100fn write_zlib_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
101 Err(Error::unsupported(
102 "Support for Zlib compressed SWFs is not enabled.",
103 ))
104}
105
106#[cfg(feature = "lzma")]
107fn write_lzma_swf<W: Write>(mut output: W, mut swf_body: &[u8]) -> Result<()> {
108 let mut data = vec![];
110 lzma_rs::lzma_compress(&mut swf_body, &mut data)?;
111
112 output.write_u32::<LittleEndian>(data.len() as u32 - 13)?; output.write_all(&data[0..5])?; output.write_all(&data[13..])?; Ok(())
118}
119
120#[cfg(not(feature = "lzma"))]
121fn write_lzma_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
122 Err(Error::unsupported(
123 "Support for LZMA compressed SWFs is not enabled.",
124 ))
125}
126
127pub trait SwfWriteExt {
128 fn write_u8(&mut self, n: u8) -> io::Result<()>;
129 fn write_u16(&mut self, n: u16) -> io::Result<()>;
130 fn write_u32(&mut self, n: u32) -> io::Result<()>;
131 fn write_u64(&mut self, n: u64) -> io::Result<()>;
132 fn write_i8(&mut self, n: i8) -> io::Result<()>;
133 fn write_i16(&mut self, n: i16) -> io::Result<()>;
134 fn write_i32(&mut self, n: i32) -> io::Result<()>;
135 fn write_f32(&mut self, n: f32) -> io::Result<()>;
136 fn write_f64(&mut self, n: f64) -> io::Result<()>;
137 fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()>;
138}
139
140pub struct BitWriter<W: Write> {
141 bits: bitstream_io::BitWriter<W, bitstream_io::BigEndian>,
142}
143
144impl<W: Write> BitWriter<W> {
145 #[inline]
146 fn write_bit(&mut self, bit: bool) -> io::Result<()> {
147 self.bits.write_bit(bit)
148 }
149
150 #[inline]
151 fn write_ubits(&mut self, num_bits: u32, n: u32) -> io::Result<()> {
152 if num_bits > 0 {
153 self.bits.write(num_bits, n)
154 } else {
155 Ok(())
156 }
157 }
158
159 #[inline]
160 fn write_sbits(&mut self, num_bits: u32, n: i32) -> io::Result<()> {
161 if num_bits > 0 {
162 self.bits.write_signed(num_bits, n)
163 } else {
164 Ok(())
165 }
166 }
167
168 #[inline]
169 fn write_sbits_fixed8(&mut self, num_bits: u32, n: Fixed8) -> io::Result<()> {
170 self.write_sbits(num_bits, n.get().into())
171 }
172
173 #[inline]
174 fn write_sbits_twips(&mut self, num_bits: u32, twips: Twips) -> io::Result<()> {
175 self.write_sbits(num_bits, twips.get())
176 }
177
178 #[inline]
179 fn write_fbits(&mut self, num_bits: u32, n: Fixed16) -> io::Result<()> {
180 self.write_sbits(num_bits, n.get())
181 }
182
183 #[inline]
184 fn flush(&mut self) -> io::Result<()> {
185 self.bits.byte_align()
186 }
187
188 #[inline]
189 fn writer(&mut self) -> &mut W {
190 let _ = self.bits.flush();
191 self.bits.writer().unwrap()
192 }
193}
194
195impl<W: Write> Drop for BitWriter<W> {
196 #[inline]
197 fn drop(&mut self) {
198 let _ = self.flush();
199 let _ = self.bits.flush();
200 }
201}
202
203struct Writer<W: Write> {
204 pub output: W,
205 pub version: u8,
206}
207
208impl<W: Write> SwfWriteExt for Writer<W> {
209 #[inline]
210 fn write_u8(&mut self, n: u8) -> io::Result<()> {
211 self.output.write_u8(n)
212 }
213
214 #[inline]
215 fn write_u16(&mut self, n: u16) -> io::Result<()> {
216 self.output.write_u16::<LittleEndian>(n)
217 }
218
219 #[inline]
220 fn write_u32(&mut self, n: u32) -> io::Result<()> {
221 self.output.write_u32::<LittleEndian>(n)
222 }
223
224 #[inline]
225 fn write_u64(&mut self, n: u64) -> io::Result<()> {
226 self.output.write_u64::<LittleEndian>(n)
227 }
228
229 #[inline]
230 fn write_i8(&mut self, n: i8) -> io::Result<()> {
231 self.output.write_i8(n)
232 }
233
234 #[inline]
235 fn write_i16(&mut self, n: i16) -> io::Result<()> {
236 self.output.write_i16::<LittleEndian>(n)
237 }
238
239 #[inline]
240 fn write_i32(&mut self, n: i32) -> io::Result<()> {
241 self.output.write_i32::<LittleEndian>(n)
242 }
243
244 #[inline]
245 fn write_f32(&mut self, n: f32) -> io::Result<()> {
246 self.output.write_f32::<LittleEndian>(n)
247 }
248
249 #[inline]
250 fn write_f64(&mut self, n: f64) -> io::Result<()> {
251 self.output.write_f64::<LittleEndian>(n)
252 }
253
254 #[inline]
255 fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()> {
256 self.output.write_all(s.as_bytes())?;
257 self.write_u8(0)
258 }
259}
260
261impl<W: Write> Writer<W> {
262 fn new(output: W, version: u8) -> Self {
263 Self { output, version }
264 }
265
266 #[inline]
267 fn bits(&mut self) -> BitWriter<&mut W> {
268 BitWriter {
269 bits: bitstream_io::BitWriter::new(&mut self.output),
270 }
271 }
272
273 #[inline]
274 fn write_fixed8(&mut self, n: Fixed8) -> io::Result<()> {
275 self.write_i16(n.get())
276 }
277
278 #[inline]
279 fn write_fixed16(&mut self, n: Fixed16) -> io::Result<()> {
280 self.write_i32(n.get())
281 }
282
283 fn write_encoded_u32(&mut self, mut n: u32) -> Result<()> {
284 loop {
285 let mut byte = (n & 0b01111111) as u8;
286 n >>= 7;
287 if n != 0 {
288 byte |= 0b10000000;
289 }
290 self.write_u8(byte)?;
291 if n == 0 {
292 break;
293 }
294 }
295 Ok(())
296 }
297
298 fn write_rectangle(&mut self, rectangle: &Rectangle<Twips>) -> Result<()> {
299 let num_bits = [
300 rectangle.x_min,
301 rectangle.x_max,
302 rectangle.y_min,
303 rectangle.y_max,
304 ]
305 .iter()
306 .map(|x| count_sbits_twips(*x))
307 .max()
308 .unwrap();
309 let mut bits = self.bits();
310 bits.write_ubits(5, num_bits)?;
311 bits.write_sbits_twips(num_bits, rectangle.x_min)?;
312 bits.write_sbits_twips(num_bits, rectangle.x_max)?;
313 bits.write_sbits_twips(num_bits, rectangle.y_min)?;
314 bits.write_sbits_twips(num_bits, rectangle.y_max)?;
315 Ok(())
316 }
317
318 fn write_character_id(&mut self, id: CharacterId) -> Result<()> {
319 self.write_u16(id)?;
320 Ok(())
321 }
322
323 fn write_rgb(&mut self, color: &Color) -> Result<()> {
324 self.write_u8(color.r)?;
325 self.write_u8(color.g)?;
326 self.write_u8(color.b)?;
327 Ok(())
328 }
329
330 fn write_rgba(&mut self, color: &Color) -> Result<()> {
331 self.write_u8(color.r)?;
332 self.write_u8(color.g)?;
333 self.write_u8(color.b)?;
334 self.write_u8(color.a)?;
335 Ok(())
336 }
337
338 fn write_color_transform_no_alpha(&mut self, color_transform: &ColorTransform) -> Result<()> {
339 let has_mult = !color_transform.r_multiply.is_one()
341 || !color_transform.g_multiply.is_one()
342 || !color_transform.b_multiply.is_one();
343 let has_add =
344 color_transform.r_add != 0 || color_transform.g_add != 0 || color_transform.b_add != 0;
345 let multiply = [
346 color_transform.r_multiply,
347 color_transform.g_multiply,
348 color_transform.b_multiply,
349 ];
350 let add = [
351 color_transform.a_add,
352 color_transform.g_add,
353 color_transform.b_add,
354 color_transform.a_add,
355 ];
356 let mut bits = self.bits();
357 bits.write_bit(has_mult)?;
358 bits.write_bit(has_add)?;
359 let mut num_bits = if has_mult {
360 multiply
361 .iter()
362 .map(|n| count_sbits(n.get().into()))
363 .max()
364 .unwrap()
365 } else {
366 0
367 };
368 if has_add {
369 num_bits = max(
370 num_bits,
371 add.iter().map(|n| count_sbits((*n).into())).max().unwrap(),
372 );
373 }
374 bits.write_ubits(4, num_bits)?;
375 if has_mult {
376 bits.write_sbits_fixed8(num_bits, color_transform.r_multiply)?;
377 bits.write_sbits_fixed8(num_bits, color_transform.g_multiply)?;
378 bits.write_sbits_fixed8(num_bits, color_transform.b_multiply)?;
379 }
380 if has_add {
381 bits.write_sbits(num_bits, color_transform.r_add.into())?;
382 bits.write_sbits(num_bits, color_transform.g_add.into())?;
383 bits.write_sbits(num_bits, color_transform.b_add.into())?;
384 }
385 Ok(())
386 }
387
388 fn write_color_transform(&mut self, color_transform: &ColorTransform) -> Result<()> {
389 let has_mult = !color_transform.r_multiply.is_one()
390 || !color_transform.g_multiply.is_one()
391 || !color_transform.b_multiply.is_one()
392 || !color_transform.a_multiply.is_one();
393 let has_add = color_transform.r_add != 0
394 || color_transform.g_add != 0
395 || color_transform.b_add != 0
396 || color_transform.a_add != 0;
397 let multiply = [
398 color_transform.r_multiply,
399 color_transform.g_multiply,
400 color_transform.b_multiply,
401 color_transform.a_multiply,
402 ];
403 let add = [
404 color_transform.r_add,
405 color_transform.g_add,
406 color_transform.b_add,
407 color_transform.a_add,
408 ];
409 let mut bits = self.bits();
410 bits.write_bit(has_add)?;
411 bits.write_bit(has_mult)?;
412 let mut num_bits = if has_mult {
413 multiply
414 .iter()
415 .map(|n| count_sbits(n.get().into()))
416 .max()
417 .unwrap()
418 } else {
419 0
420 };
421 if has_add {
422 num_bits = max(
423 num_bits,
424 add.iter().map(|n| count_sbits((*n).into())).max().unwrap(),
425 );
426 }
427 bits.write_ubits(4, num_bits)?;
428 if has_mult {
429 bits.write_sbits_fixed8(num_bits, color_transform.r_multiply)?;
430 bits.write_sbits_fixed8(num_bits, color_transform.g_multiply)?;
431 bits.write_sbits_fixed8(num_bits, color_transform.b_multiply)?;
432 bits.write_sbits_fixed8(num_bits, color_transform.a_multiply)?;
433 }
434 if has_add {
435 bits.write_sbits(num_bits, color_transform.r_add.into())?;
436 bits.write_sbits(num_bits, color_transform.g_add.into())?;
437 bits.write_sbits(num_bits, color_transform.b_add.into())?;
438 bits.write_sbits(num_bits, color_transform.a_add.into())?;
439 }
440 Ok(())
441 }
442
443 fn write_matrix(&mut self, m: &Matrix) -> Result<()> {
444 let mut bits = self.bits();
445 let has_scale = m.a != Fixed16::ONE || m.d != Fixed16::ONE;
447 bits.write_bit(has_scale)?;
448 if has_scale {
449 let num_bits = max(count_fbits(m.a), count_fbits(m.d));
450 bits.write_ubits(5, num_bits)?;
451 bits.write_fbits(num_bits, m.a)?;
452 bits.write_fbits(num_bits, m.d)?;
453 }
454 let has_rotate_skew = m.b != Fixed16::ZERO || m.c != Fixed16::ZERO;
456 bits.write_bit(has_rotate_skew)?;
457 if has_rotate_skew {
458 let num_bits = max(count_fbits(m.b), count_fbits(m.c));
459 bits.write_ubits(5, num_bits)?;
460 bits.write_fbits(num_bits, m.b)?;
461 bits.write_fbits(num_bits, m.c)?;
462 }
463 let num_bits = max(count_sbits_twips(m.tx), count_sbits_twips(m.ty));
465 bits.write_ubits(5, num_bits)?;
466 bits.write_sbits_twips(num_bits, m.tx)?;
467 bits.write_sbits_twips(num_bits, m.ty)?;
468 Ok(())
469 }
470
471 fn write_language(&mut self, language: Language) -> Result<()> {
472 self.write_u8(language as u8)?;
473 Ok(())
474 }
475
476 fn write_tag(&mut self, tag: &Tag) -> Result<()> {
477 match *tag {
478 Tag::ShowFrame => self.write_tag_header(TagCode::ShowFrame, 0)?,
479
480 Tag::ExportAssets(ref exports) => self.write_export_assets(&exports[..])?,
481
482 Tag::Protect(password) => {
483 if let Some(password_md5) = password {
484 self.write_tag_header(TagCode::Protect, password_md5.len() as u32 + 3)?;
485 self.write_u16(0)?; self.write_string(password_md5)?;
487 } else {
488 self.write_tag_header(TagCode::Protect, 0)?;
489 }
490 }
491
492 #[allow(clippy::unusual_byte_groupings)]
493 Tag::CsmTextSettings(ref settings) => {
494 self.write_tag_header(TagCode::CsmTextSettings, 12)?;
495 self.write_character_id(settings.id)?;
496 self.write_u8(
497 if settings.use_advanced_rendering {
498 0b01_000000
499 } else {
500 0
501 } | ((settings.grid_fit as u8) << 3),
502 )?;
503 self.write_f32(settings.thickness)?;
504 self.write_f32(settings.sharpness)?;
505 self.write_u8(0)?; }
507
508 Tag::DefineBinaryData(ref binary_data) => self.write_define_binary_data(binary_data)?,
509
510 Tag::DefineBits { id, jpeg_data } => {
511 self.write_tag_header(TagCode::DefineBits, jpeg_data.len() as u32 + 2)?;
512 self.write_u16(id)?;
513 self.output.write_all(jpeg_data)?;
514 }
515
516 Tag::DefineBitsJpeg2 { id, jpeg_data } => {
517 self.write_tag_header(TagCode::DefineBitsJpeg2, jpeg_data.len() as u32 + 2)?;
518 self.write_u16(id)?;
519 self.output.write_all(jpeg_data)?;
520 }
521
522 Tag::DefineBitsJpeg3(ref jpeg) => {
523 self.write_tag_header(
524 TagCode::DefineBitsJpeg3,
525 (jpeg.data.len() + jpeg.alpha_data.len() + 6) as u32,
526 )?;
527 self.write_u16(jpeg.id)?;
528 if jpeg.version >= 4 {
529 self.write_fixed8(jpeg.deblocking)?;
530 }
531 self.write_u32(jpeg.data.len() as u32)?;
533 self.output.write_all(jpeg.data)?;
534 self.output.write_all(jpeg.alpha_data)?;
535 }
536
537 Tag::DefineBitsLossless(ref tag) => {
538 let mut length = 7 + tag.data.len();
539 if let BitmapFormat::ColorMap8 { .. } = tag.format {
540 length += 1;
541 }
542 let tag_code = if tag.version == 1 {
544 TagCode::DefineBitsLossless
545 } else {
546 TagCode::DefineBitsLossless2
547 };
548 self.write_tag_header(tag_code, length as u32)?;
549 self.write_character_id(tag.id)?;
550 let format_id = match tag.format {
551 BitmapFormat::ColorMap8 { .. } => 3,
552 BitmapFormat::Rgb15 => 4,
553 BitmapFormat::Rgb32 => 5,
554 };
555 self.write_u8(format_id)?;
556 self.write_u16(tag.width)?;
557 self.write_u16(tag.height)?;
558 if let BitmapFormat::ColorMap8 { num_colors } = tag.format {
559 self.write_u8(num_colors)?;
560 }
561 self.output.write_all(&tag.data)?;
562 }
563
564 Tag::DefineButton(ref button) => self.write_define_button(button)?,
565
566 Tag::DefineButton2(ref button) => self.write_define_button_2(button)?,
567
568 Tag::DefineButtonColorTransform(ref button_color) => {
569 let mut buf = Vec::new();
570 {
571 let mut writer = Writer::new(&mut buf, self.version);
572 writer.write_character_id(button_color.id)?;
573 for color_transform in &button_color.color_transforms {
574 writer.write_color_transform_no_alpha(color_transform)?;
575 }
576 }
577 self.write_tag_header(TagCode::DefineButtonCxform, buf.len() as u32)?;
578 self.output.write_all(&buf)?;
579 }
580
581 Tag::DefineButtonSound(ref button_sounds) => {
582 let mut buf = Vec::new();
583 {
584 let mut writer = Writer::new(&mut buf, self.version);
585 writer.write_u16(button_sounds.id)?;
586 if let Some(ref sound) = button_sounds.over_to_up_sound {
587 writer.write_u16(sound.0)?;
588 writer.write_sound_info(&sound.1)?;
589 } else {
590 writer.write_u16(0)?
591 };
592 if let Some(ref sound) = button_sounds.up_to_over_sound {
593 writer.write_u16(sound.0)?;
594 writer.write_sound_info(&sound.1)?;
595 } else {
596 writer.write_u16(0)?
597 };
598 if let Some(ref sound) = button_sounds.over_to_down_sound {
599 writer.write_u16(sound.0)?;
600 writer.write_sound_info(&sound.1)?;
601 } else {
602 writer.write_u16(0)?
603 };
604 if let Some(ref sound) = button_sounds.down_to_over_sound {
605 writer.write_u16(sound.0)?;
606 writer.write_sound_info(&sound.1)?;
607 } else {
608 writer.write_u16(0)?
609 };
610 }
611 self.write_tag_header(TagCode::DefineButtonSound, buf.len() as u32)?;
612 self.output.write_all(&buf)?;
613 }
614
615 Tag::DefineEditText(ref edit_text) => self.write_define_edit_text(edit_text)?,
616
617 Tag::DefineFont(ref font) => {
618 let num_glyphs = font.glyphs.len();
619 let mut offsets = Vec::with_capacity(num_glyphs);
620 let mut buf = vec![];
621 {
622 let mut writer = Writer::new(&mut buf, self.version);
623 for glyph in &font.glyphs {
624 let offset = num_glyphs * 2 + writer.output.len();
625 offsets.push(offset as u16);
626
627 let mut shape_context = ShapeContext {
630 swf_version: self.version,
631 shape_version: 1,
632 num_fill_bits: 1,
633 num_line_bits: 0,
634 };
635 writer.write_u8(0b0001_0000)?;
636 let mut bits = writer.bits();
637
638 for shape_record in glyph {
639 Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?;
640 }
641 bits.write_ubits(6, 0)?;
643 }
644 }
645
646 let tag_len = (2 + 2 * font.glyphs.len() + buf.len()) as u32;
647 self.write_tag_header(TagCode::DefineFont, tag_len)?;
648 self.write_u16(font.id)?;
649 for offset in offsets {
650 self.write_u16(offset)?;
651 }
652 self.output.write_all(&buf)?;
653 }
654
655 Tag::DefineFont2(ref font) => self.write_define_font_2(font)?,
656 Tag::DefineFont4(ref font) => self.write_define_font_4(font)?,
657
658 #[allow(clippy::unusual_byte_groupings)]
659 Tag::DefineFontAlignZones {
660 id,
661 thickness,
662 ref zones,
663 } => {
664 self.write_tag_header(TagCode::DefineFontAlignZones, 3 + 10 * zones.len() as u32)?;
665 self.write_character_id(id)?;
666 self.write_u8((thickness as u8) << 6)?;
667 for zone in zones {
668 self.write_u8(2)?; self.write_i16(zone.left)?;
670 self.write_i16(zone.width)?;
671 self.write_i16(zone.bottom)?;
672 self.write_i16(zone.height)?;
673 self.write_u8(0b000000_11)?; }
675 }
676
677 Tag::DefineFontInfo(ref font_info) => self.write_define_font_info(font_info)?,
678
679 Tag::DefineFontName {
680 id,
681 name,
682 copyright_info,
683 } => {
684 let len = name.len() + copyright_info.len() + 4;
685 self.write_tag_header(TagCode::DefineFontName, len as u32)?;
686 self.write_character_id(id)?;
687 self.write_string(name)?;
688 self.write_string(copyright_info)?;
689 }
690
691 Tag::DefineMorphShape(ref define_morph_shape) => {
692 self.write_define_morph_shape(define_morph_shape)?
693 }
694
695 Tag::DefineScalingGrid {
696 id,
697 ref splitter_rect,
698 } => {
699 let mut buf = Vec::new();
700 {
701 let mut writer = Writer::new(&mut buf, self.version);
702 writer.write_u16(id)?;
703 writer.write_rectangle(splitter_rect)?;
704 }
705 self.write_tag_header(TagCode::DefineScalingGrid, buf.len() as u32)?;
706 self.output.write_all(&buf)?;
707 }
708
709 Tag::DefineShape(ref shape) => self.write_define_shape(shape)?,
710 Tag::DefineSound(ref sound) => self.write_define_sound(sound)?,
711 Tag::DefineSprite(ref sprite) => self.write_define_sprite(sprite)?,
712 Tag::DefineText(ref text) => self.write_define_text(text, 1)?,
713 Tag::DefineText2(ref text) => self.write_define_text(text, 2)?,
714 Tag::DefineVideoStream(ref video) => self.write_define_video_stream(video)?,
715 Tag::DoAbc(data) => {
716 self.write_tag_header(TagCode::DoAbc, data.len() as u32)?;
717 self.output.write_all(data)?;
718 }
719 Tag::DoAbc2(ref do_abc) => {
720 let len = do_abc.data.len() + do_abc.name.len() + 5;
721 self.write_tag_header(TagCode::DoAbc2, len as u32)?;
722 self.write_u32(do_abc.flags.bits())?;
723 self.write_string(do_abc.name)?;
724 self.output.write_all(do_abc.data)?;
725 }
726 Tag::DoAction(action_data) => {
727 self.write_tag_header(TagCode::DoAction, action_data.len() as u32)?;
728 self.output.write_all(action_data)?;
729 }
730 Tag::DoInitAction { id, action_data } => {
731 self.write_tag_header(TagCode::DoInitAction, action_data.len() as u32 + 2)?;
732 self.write_u16(id)?;
733 self.output.write_all(action_data)?;
734 }
735
736 Tag::EnableDebugger(password_md5) => {
737 let len = password_md5.len() as u32 + 1;
738 if self.version >= 6 {
739 self.write_tag_header(TagCode::EnableDebugger2, len + 2)?;
741 self.write_u16(0)?; } else {
743 self.write_tag_header(TagCode::EnableDebugger, len)?;
744 }
745
746 self.write_string(password_md5)?;
747 }
748
749 Tag::EnableTelemetry { password_hash } => {
750 if !password_hash.is_empty() {
751 self.write_tag_header(TagCode::EnableTelemetry, 34)?;
752 self.write_u16(0)?;
753 self.output.write_all(&password_hash[0..32])?;
754 } else {
755 self.write_tag_header(TagCode::EnableTelemetry, 2)?;
756 self.write_u16(0)?;
757 }
758 }
759
760 Tag::End => self.write_tag_header(TagCode::End, 0)?,
761
762 Tag::ImportAssets { url, ref imports } => {
763 let len = imports.iter().map(|e| e.name.len() as u32 + 3).sum::<u32>()
764 + url.len() as u32
765 + 1
766 + 2;
767 if self.version >= 8 {
769 self.write_tag_header(TagCode::ImportAssets2, len + 2)?;
770 self.write_string(url)?;
771 self.write_u8(1)?;
772 self.write_u8(0)?;
773 } else {
774 self.write_tag_header(TagCode::ImportAssets, len)?;
775 self.write_string(url)?;
776 }
777 self.write_u16(imports.len() as u16)?;
778 for &ExportedAsset { id, name } in imports {
779 self.write_u16(id)?;
780 self.write_string(name)?;
781 }
782 }
783
784 Tag::JpegTables(data) => {
785 self.write_tag_header(TagCode::JpegTables, data.len() as u32)?;
786 self.output.write_all(data)?;
787 }
788
789 Tag::Metadata(metadata) => {
790 self.write_tag_header(TagCode::Metadata, metadata.len() as u32 + 1)?;
791 self.write_string(metadata)?;
792 }
793
794 Tag::SetBackgroundColor(ref color) => {
796 self.write_tag_header(TagCode::SetBackgroundColor, 3)?;
797 self.write_rgb(color)?;
798 }
799
800 Tag::ScriptLimits {
801 max_recursion_depth,
802 timeout_in_seconds,
803 } => {
804 self.write_tag_header(TagCode::ScriptLimits, 4)?;
805 self.write_u16(max_recursion_depth)?;
806 self.write_u16(timeout_in_seconds)?;
807 }
808
809 Tag::SetTabIndex { depth, tab_index } => {
810 self.write_tag_header(TagCode::SetTabIndex, 4)?;
811 self.write_u16(depth)?;
812 self.write_u16(tab_index)?;
813 }
814
815 Tag::PlaceObject(ref place_object) => match place_object.version {
816 1 => self.write_place_object(place_object)?,
817 2 => self.write_place_object_2_or_3(place_object, 2)?,
818 3 => self.write_place_object_2_or_3(place_object, 3)?,
819 4 => self.write_place_object_2_or_3(place_object, 4)?,
820 _ => return Err(Error::invalid_data("Invalid PlaceObject version.")),
821 },
822
823 Tag::RemoveObject(ref remove_object) => {
824 if let Some(id) = remove_object.character_id {
825 self.write_tag_header(TagCode::RemoveObject, 4)?;
826 self.write_u16(id)?;
827 } else {
828 self.write_tag_header(TagCode::RemoveObject2, 2)?;
829 }
830 self.write_u16(remove_object.depth)?;
831 }
832
833 Tag::SoundStreamBlock(data) => {
834 self.write_tag_header(TagCode::SoundStreamBlock, data.len() as u32)?;
835 self.output.write_all(data)?;
836 }
837
838 Tag::SoundStreamHead(ref sound_stream_head) => {
839 self.write_sound_stream_head(sound_stream_head, 1)?;
840 }
841
842 Tag::SoundStreamHead2(ref sound_stream_head) => {
843 self.write_sound_stream_head(sound_stream_head, 2)?;
844 }
845
846 Tag::StartSound(ref start_sound) => {
847 let sound_info = &start_sound.sound_info;
848 let length = 3
849 + if sound_info.in_sample.is_some() { 4 } else { 0 }
850 + if sound_info.out_sample.is_some() {
851 4
852 } else {
853 0
854 }
855 + if sound_info.num_loops > 1 { 2 } else { 0 }
856 + if let Some(ref e) = sound_info.envelope {
857 e.len() as u32 * 8 + 1
858 } else {
859 0
860 };
861 self.write_tag_header(TagCode::StartSound, length)?;
862 self.write_u16(start_sound.id)?;
863 self.write_sound_info(sound_info)?;
864 }
865
866 Tag::StartSound2 {
867 class_name,
868 ref sound_info,
869 } => {
870 let length = class_name.len() as u32
871 + 2
872 + if sound_info.in_sample.is_some() { 4 } else { 0 }
873 + if sound_info.out_sample.is_some() {
874 4
875 } else {
876 0
877 }
878 + if sound_info.num_loops > 1 { 2 } else { 0 }
879 + if let Some(ref e) = sound_info.envelope {
880 e.len() as u32 * 8 + 1
881 } else {
882 0
883 };
884 self.write_tag_header(TagCode::StartSound2, length)?;
885 self.write_string(class_name)?;
886 self.write_sound_info(sound_info)?;
887 }
888
889 Tag::SymbolClass(ref symbols) => {
890 let len = symbols
891 .iter()
892 .map(|e| e.class_name.len() as u32 + 3)
893 .sum::<u32>()
894 + 2;
895 self.write_tag_header(TagCode::SymbolClass, len)?;
896 self.write_u16(symbols.len() as u16)?;
897 for &SymbolClassLink { id, class_name } in symbols {
898 self.write_u16(id)?;
899 self.write_string(class_name)?;
900 }
901 }
902
903 Tag::VideoFrame(ref frame) => {
904 self.write_tag_header(TagCode::VideoFrame, 4 + frame.data.len() as u32)?;
905 self.write_character_id(frame.stream_id)?;
906 self.write_u16(frame.frame_num)?;
907 self.output.write_all(frame.data)?;
908 }
909
910 Tag::FileAttributes(attributes) => {
911 self.write_tag_header(TagCode::FileAttributes, 4)?;
912 self.write_u32(attributes.bits() as u32)?;
913 }
914
915 Tag::FrameLabel(FrameLabel { label, is_anchor }) => {
916 let is_anchor = is_anchor && self.version >= 6;
918 let length = label.len() as u32 + if is_anchor { 2 } else { 1 };
919 self.write_tag_header(TagCode::FrameLabel, length)?;
920 self.write_string(label)?;
921 if is_anchor {
922 self.write_u8(1)?;
923 }
924 }
925
926 Tag::DefineSceneAndFrameLabelData(ref data) => {
927 self.write_define_scene_and_frame_label_data(data)?
928 }
929 Tag::ProductInfo(ref product_info) => self.write_product_info(product_info)?,
930 Tag::DebugId(ref debug_id) => self.write_debug_id(debug_id)?,
931 Tag::NameCharacter(ref name_character) => self.write_name_character(name_character)?,
932 Tag::Unknown { tag_code, data } => {
933 self.write_tag_code_and_length(tag_code, data.len() as u32)?;
934 self.output.write_all(data)?;
935 }
936 }
937 Ok(())
938 }
939
940 fn write_define_button(&mut self, button: &Button) -> Result<()> {
941 let mut buf = Vec::new();
942 {
943 let mut writer = Writer::new(&mut buf, self.version);
944 writer.write_u16(button.id)?;
945 for record in &button.records {
946 writer.write_button_record(record, 1)?;
947 }
948 writer.write_u8(0)?; writer.output.write_all(button.actions[0].action_data)?;
951 }
952 self.write_tag_header(TagCode::DefineButton, buf.len() as u32)?;
953 self.output.write_all(&buf)?;
954 Ok(())
955 }
956
957 fn write_define_button_2(&mut self, button: &Button) -> Result<()> {
958 let mut buf = Vec::new();
959 {
960 let mut writer = Writer::new(&mut buf, self.version);
961 writer.write_u16(button.id)?;
962 let flags = if button.is_track_as_menu { 1 } else { 0 };
963 writer.write_u8(flags)?;
964
965 let mut record_data = Vec::new();
966 {
967 let mut writer_2 = Writer::new(&mut record_data, self.version);
968 for record in &button.records {
969 writer_2.write_button_record(record, 2)?;
970 }
971 writer_2.write_u8(0)?; }
973
974 if button.actions.is_empty() {
976 writer.write_u16(0)?;
977 } else {
978 writer.write_u16(record_data.len() as u16 + 2)?;
979 }
980
981 writer.output.write_all(&record_data)?;
982
983 let mut iter = button.actions.iter().peekable();
984 while let Some(action) = iter.next() {
985 if iter.peek().is_some() {
986 let length = action.action_data.len() as u16 + 4;
987 writer.write_u16(length)?;
988 } else {
989 writer.write_u16(0)?;
990 }
991 let flags = action.conditions.bits();
992 writer.write_u16(flags)?;
993 writer.output.write_all(action.action_data)?;
994 }
995 }
996 self.write_tag_header(TagCode::DefineButton2, buf.len() as u32)?;
997 self.output.write_all(&buf)?;
998 Ok(())
999 }
1000
1001 fn write_define_morph_shape(&mut self, data: &DefineMorphShape) -> Result<()> {
1002 if data.start.fill_styles.len() != data.end.fill_styles.len()
1003 || data.start.line_styles.len() != data.end.line_styles.len()
1004 {
1005 return Err(Error::invalid_data(
1006 "Start and end state of a morph shape must have the same number of styles.",
1007 ));
1008 }
1009
1010 let num_fill_styles = data.start.fill_styles.len();
1011 let num_line_styles = data.start.line_styles.len();
1012 let num_fill_bits = count_ubits(num_fill_styles as u32) as u8;
1013 let num_line_bits = count_ubits(num_line_styles as u32) as u8;
1014
1015 let mut start_buf = Vec::new();
1017 {
1018 let mut writer = Writer::new(&mut start_buf, self.version);
1019
1020 if num_fill_styles >= 0xff {
1023 writer.write_u8(0xff)?;
1024 writer.write_u16(num_fill_styles as u16)?;
1025 } else {
1026 writer.write_u8(num_fill_styles as u8)?;
1027 }
1028 for (start, end) in data
1029 .start
1030 .fill_styles
1031 .iter()
1032 .zip(data.end.fill_styles.iter())
1033 {
1034 writer.write_morph_fill_style(start, end)?;
1035 }
1036
1037 if num_line_styles >= 0xff {
1038 writer.write_u8(0xff)?;
1039 writer.write_u16(num_line_styles as u16)?;
1040 } else {
1041 writer.write_u8(num_line_styles as u8)?;
1042 }
1043 for (start, end) in data
1044 .start
1045 .line_styles
1046 .iter()
1047 .zip(data.end.line_styles.iter())
1048 {
1049 writer.write_morph_line_style(start, end, data.version)?;
1050 }
1051
1052 writer.write_u8((num_fill_bits << 4) | (num_line_bits & 0b1111))?;
1054
1055 let mut shape_context = ShapeContext {
1056 swf_version: self.version,
1057 shape_version: 1,
1058 num_fill_bits,
1059 num_line_bits,
1060 };
1061 let mut bits = writer.bits();
1062 for shape_record in &data.start.shape {
1063 Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?;
1064 }
1065 bits.write_ubits(6, 0)?;
1067 }
1068
1069 let mut buf = Vec::new();
1070 {
1071 let mut writer = Writer::new(&mut buf, self.version);
1072 writer.write_character_id(data.id)?;
1073 writer.write_rectangle(&data.start.shape_bounds)?;
1074 writer.write_rectangle(&data.end.shape_bounds)?;
1075 if data.version >= 2 {
1076 writer.write_rectangle(&data.start.edge_bounds)?;
1077 writer.write_rectangle(&data.end.edge_bounds)?;
1078 writer.write_u8(data.flags.bits())?;
1079 }
1080
1081 writer.write_u32(start_buf.len() as u32)?;
1083
1084 writer.output.write_all(&start_buf)?;
1085
1086 writer.write_u8(0)?; let mut shape_context = ShapeContext {
1089 swf_version: self.version,
1090 shape_version: 1,
1091 num_fill_bits,
1092 num_line_bits,
1093 };
1094 let mut bits = writer.bits();
1095 for shape_record in &data.end.shape {
1096 Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?;
1097 }
1098 bits.write_ubits(6, 0)?;
1100 }
1101
1102 let tag_code = if data.version == 1 {
1103 TagCode::DefineMorphShape
1104 } else {
1105 TagCode::DefineMorphShape2
1106 };
1107 self.write_tag_header(tag_code, buf.len() as u32)?;
1108 self.output.write_all(&buf)?;
1109 Ok(())
1110 }
1111
1112 fn write_morph_fill_style(&mut self, start: &FillStyle, end: &FillStyle) -> Result<()> {
1113 match (start, end) {
1114 (FillStyle::Color(start_color), FillStyle::Color(end_color)) => {
1115 self.write_u8(0x00)?; self.write_rgba(start_color)?;
1117 self.write_rgba(end_color)?;
1118 }
1119
1120 (
1121 FillStyle::LinearGradient(start_gradient),
1122 FillStyle::LinearGradient(end_gradient),
1123 ) => {
1124 self.write_u8(0x10)?; self.write_morph_gradient(start_gradient, end_gradient)?;
1126 }
1127
1128 (
1129 FillStyle::RadialGradient(start_gradient),
1130 FillStyle::RadialGradient(end_gradient),
1131 ) => {
1132 self.write_u8(0x12)?; self.write_morph_gradient(start_gradient, end_gradient)?;
1134 }
1135
1136 (
1137 FillStyle::FocalGradient {
1138 gradient: start_gradient,
1139 focal_point: start_focal_point,
1140 },
1141 FillStyle::FocalGradient {
1142 gradient: end_gradient,
1143 focal_point: end_focal_point,
1144 },
1145 ) => {
1146 self.write_u8(0x13)?; self.write_morph_gradient(start_gradient, end_gradient)?;
1148 self.write_fixed8(*start_focal_point)?;
1149 self.write_fixed8(*end_focal_point)?;
1150 }
1151
1152 (
1153 &FillStyle::Bitmap {
1154 id,
1155 matrix: ref start_matrix,
1156 is_smoothed,
1157 is_repeating,
1158 },
1159 &FillStyle::Bitmap {
1160 id: end_id,
1161 matrix: ref end_matrix,
1162 is_smoothed: end_is_smoothed,
1163 is_repeating: end_is_repeating,
1164 },
1165 ) if id == end_id && is_smoothed == end_is_smoothed
1166 || is_repeating == end_is_repeating =>
1167 {
1168 let fill_style_type = match (is_smoothed, is_repeating) {
1169 (true, true) => 0x40,
1170 (true, false) => 0x41,
1171 (false, true) => 0x42,
1172 (false, false) => 0x43,
1173 };
1174 self.write_u8(fill_style_type)?;
1175 self.write_u16(id)?;
1176 self.write_matrix(start_matrix)?;
1177 self.write_matrix(end_matrix)?;
1178 }
1179
1180 _ => {
1181 return Err(Error::invalid_data(
1182 "Morph start and end fill styles must be the same variant.",
1183 ))
1184 }
1185 }
1186 Ok(())
1187 }
1188
1189 fn write_morph_gradient(&mut self, start: &Gradient, end: &Gradient) -> Result<()> {
1190 self.write_matrix(&start.matrix)?;
1191 self.write_matrix(&end.matrix)?;
1192 if start.records.len() != end.records.len() {
1193 return Err(Error::invalid_data(
1194 "Morph start and end gradient must have the same amount of records.",
1195 ));
1196 }
1197 self.write_gradient_flags(start)?;
1198 for (start_record, end_record) in start.records.iter().zip(end.records.iter()) {
1199 self.write_u8(start_record.ratio)?;
1200 self.write_rgba(&start_record.color)?;
1201 self.write_u8(end_record.ratio)?;
1202 self.write_rgba(&end_record.color)?;
1203 }
1204 Ok(())
1205 }
1206
1207 fn write_morph_line_style(
1208 &mut self,
1209 start: &LineStyle,
1210 end: &LineStyle,
1211 shape_version: u8,
1212 ) -> Result<()> {
1213 if shape_version < 2 {
1214 self.write_u16(start.width.get() as u16)?;
1216 self.write_u16(end.width.get() as u16)?;
1217 match (&start.fill_style, &end.fill_style) {
1218 (FillStyle::Color(start), FillStyle::Color(end)) => {
1219 self.write_rgba(start)?;
1220 self.write_rgba(end)?;
1221 }
1222 _ => {
1223 return Err(Error::invalid_data(
1224 "Complex line styles can only be used in DefineMorphShape2 tags",
1225 ));
1226 }
1227 }
1228 } else {
1229 if start.flags != end.flags {
1230 return Err(Error::invalid_data(
1231 "Morph start and end line styles must have the same join parameters.",
1232 ));
1233 }
1234
1235 self.write_u16(start.width.get() as u16)?;
1237 self.write_u16(end.width.get() as u16)?;
1238
1239 self.write_u16(start.flags.bits())?;
1241 if let LineJoinStyle::Miter(miter_factor) = start.join_style() {
1242 self.write_fixed8(miter_factor)?;
1243 }
1244 if start.flags.contains(LineStyleFlag::HAS_FILL) {
1245 self.write_morph_fill_style(&start.fill_style, &end.fill_style)?;
1246 } else {
1247 match (&start.fill_style, &end.fill_style) {
1248 (FillStyle::Color(start), FillStyle::Color(end)) => {
1249 self.write_rgba(start)?;
1250 self.write_rgba(end)?;
1251 }
1252 _ => {
1253 return Err(Error::invalid_data("Unexpected line fill style fill type"));
1254 }
1255 }
1256 }
1257 }
1258 Ok(())
1259 }
1260
1261 fn write_define_scene_and_frame_label_data(
1262 &mut self,
1263 data: &DefineSceneAndFrameLabelData,
1264 ) -> Result<()> {
1265 let mut buf = Vec::with_capacity((data.scenes.len() + data.frame_labels.len()) * 4);
1266 {
1267 let mut writer = Writer::new(&mut buf, self.version);
1268 writer.write_encoded_u32(data.scenes.len() as u32)?;
1269 for scene in &data.scenes {
1270 writer.write_encoded_u32(scene.frame_num)?;
1271 writer.write_string(scene.label)?;
1272 }
1273 writer.write_encoded_u32(data.frame_labels.len() as u32)?;
1274 for frame_label in &data.frame_labels {
1275 writer.write_encoded_u32(frame_label.frame_num)?;
1276 writer.write_string(frame_label.label)?;
1277 }
1278 }
1279 self.write_tag_header(TagCode::DefineSceneAndFrameLabelData, buf.len() as u32)?;
1280 self.output.write_all(&buf)?;
1281 Ok(())
1282 }
1283
1284 fn write_define_shape(&mut self, shape: &Shape) -> Result<()> {
1285 let mut buf = Vec::new();
1286 {
1287 let mut writer = Writer::new(&mut buf, self.version);
1288 writer.write_u16(shape.id)?;
1289 writer.write_rectangle(&shape.shape_bounds)?;
1290 if shape.version >= 4 {
1291 writer.write_rectangle(&shape.edge_bounds)?;
1292 writer.write_u8(shape.flags.bits())?;
1293 }
1294
1295 let (num_fill_bits, num_line_bits) =
1296 writer.write_shape_styles(&shape.styles, shape.version)?;
1297 let mut shape_context = ShapeContext {
1298 swf_version: self.version,
1299 shape_version: shape.version,
1300 num_fill_bits,
1301 num_line_bits,
1302 };
1303 let mut bits = writer.bits();
1304 for shape_record in &shape.shape {
1305 Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?;
1306 }
1307 bits.write_ubits(6, 0)?;
1309 }
1310
1311 let tag_code = match shape.version {
1312 1 => TagCode::DefineShape,
1313 2 => TagCode::DefineShape2,
1314 3 => TagCode::DefineShape3,
1315 4 => TagCode::DefineShape4,
1316 _ => return Err(Error::invalid_data("Invalid DefineShape version.")),
1317 };
1318 self.write_tag_header(tag_code, buf.len() as u32)?;
1319 self.output.write_all(&buf)?;
1320 Ok(())
1321 }
1322
1323 fn write_define_sound(&mut self, sound: &Sound) -> Result<()> {
1324 self.write_tag_header(TagCode::DefineSound, 7 + sound.data.len() as u32)?;
1325 self.write_u16(sound.id)?;
1326 self.write_sound_format(&sound.format)?;
1327 self.write_u32(sound.num_samples)?;
1328 self.output.write_all(sound.data)?;
1329 Ok(())
1330 }
1331
1332 fn write_define_sprite(&mut self, sprite: &Sprite) -> Result<()> {
1333 let mut buf = Vec::new();
1334 {
1335 let mut writer = Writer::new(&mut buf, self.version);
1336 writer.write_u16(sprite.id)?;
1337 writer.write_u16(sprite.num_frames)?;
1338 writer.write_tag_list(&sprite.tags)?;
1339 };
1340 self.write_tag_header(TagCode::DefineSprite, buf.len() as u32)?;
1341 self.output.write_all(&buf)?;
1342 Ok(())
1343 }
1344
1345 fn write_export_assets(&mut self, exports: &[ExportedAsset]) -> Result<()> {
1346 let len = exports.iter().map(|e| e.name.len() as u32 + 1).sum::<u32>()
1347 + exports.len() as u32 * 2
1348 + 2;
1349 self.write_tag_header(TagCode::ExportAssets, len)?;
1350 self.write_u16(exports.len() as u16)?;
1351 for &ExportedAsset { id, name } in exports {
1352 self.write_u16(id)?;
1353 self.write_string(name)?;
1354 }
1355 Ok(())
1356 }
1357
1358 fn write_button_record(&mut self, record: &ButtonRecord, tag_version: u8) -> Result<()> {
1359 let flags = if record.blend_mode != BlendMode::Normal {
1361 0b10_0000
1362 } else {
1363 0
1364 } | if !record.filters.is_empty() {
1365 0b1_0000
1366 } else {
1367 0
1368 } | record.states.bits();
1369 self.write_u8(flags)?;
1370 self.write_u16(record.id)?;
1371 self.write_u16(record.depth)?;
1372 self.write_matrix(&record.matrix)?;
1373 if tag_version >= 2 {
1374 self.write_color_transform(&record.color_transform)?;
1375 if !record.filters.is_empty() {
1376 self.write_u8(record.filters.len() as u8)?;
1377 for filter in &record.filters {
1378 self.write_filter(filter)?;
1379 }
1380 }
1381 if record.blend_mode != BlendMode::Normal {
1382 self.write_blend_mode(record.blend_mode)?;
1383 }
1384 }
1385 Ok(())
1386 }
1387
1388 fn write_blend_mode(&mut self, blend_mode: BlendMode) -> Result<()> {
1389 self.write_u8(blend_mode as u8)?;
1390 Ok(())
1391 }
1392
1393 fn write_shape_styles(&mut self, styles: &ShapeStyles, shape_version: u8) -> Result<(u8, u8)> {
1394 if styles.fill_styles.len() >= 0xff {
1396 self.write_u8(0xff)?;
1397 self.write_u16(styles.fill_styles.len() as u16)?;
1398 } else {
1399 self.write_u8(styles.fill_styles.len() as u8)?;
1400 }
1401 for fill_style in &styles.fill_styles {
1402 self.write_fill_style(fill_style, shape_version)?;
1403 }
1404
1405 if styles.line_styles.len() >= 0xff {
1406 self.write_u8(0xff)?;
1407 self.write_u16(styles.line_styles.len() as u16)?;
1408 } else {
1409 self.write_u8(styles.line_styles.len() as u8)?;
1410 }
1411 for line_style in &styles.line_styles {
1412 self.write_line_style(line_style, shape_version)?;
1413 }
1414
1415 let num_fill_bits = count_ubits(styles.fill_styles.len() as u32) as u8;
1416 let num_line_bits = count_ubits(styles.line_styles.len() as u32) as u8;
1417 self.write_u8((num_fill_bits << 4) | (num_line_bits & 0b1111))?;
1418
1419 Ok((num_fill_bits, num_line_bits))
1420 }
1421
1422 fn write_shape_record<T: Write>(
1423 record: &ShapeRecord,
1424 bits: &mut BitWriter<T>,
1425 context: &mut ShapeContext,
1426 ) -> Result<()> {
1427 match record {
1428 ShapeRecord::StraightEdge { delta } => {
1429 bits.write_ubits(2, 0b11)?; let num_bits = count_sbits_twips(delta.dx)
1432 .max(count_sbits_twips(delta.dy))
1433 .max(2);
1434 let is_axis_aligned = delta.dx == Twips::ZERO || delta.dy == Twips::ZERO;
1435 bits.write_ubits(4, num_bits - 2)?;
1436 bits.write_bit(!is_axis_aligned)?;
1437 let is_vertical = is_axis_aligned && delta.dx == Twips::ZERO;
1438 if is_axis_aligned {
1439 bits.write_bit(is_vertical)?;
1440 }
1441 if !is_axis_aligned || !is_vertical {
1442 bits.write_sbits_twips(num_bits, delta.dx)?;
1443 }
1444 if !is_axis_aligned || is_vertical {
1445 bits.write_sbits_twips(num_bits, delta.dy)?;
1446 }
1447 }
1448 ShapeRecord::CurvedEdge {
1449 control_delta,
1450 anchor_delta,
1451 } => {
1452 bits.write_ubits(2, 0b10)?; let num_bits = count_sbits_twips(control_delta.dx)
1454 .max(count_sbits_twips(control_delta.dy))
1455 .max(count_sbits_twips(anchor_delta.dx))
1456 .max(count_sbits_twips(anchor_delta.dy))
1457 .max(2);
1458 bits.write_ubits(4, num_bits - 2)?;
1459 bits.write_sbits_twips(num_bits, control_delta.dx)?;
1460 bits.write_sbits_twips(num_bits, control_delta.dy)?;
1461 bits.write_sbits_twips(num_bits, anchor_delta.dx)?;
1462 bits.write_sbits_twips(num_bits, anchor_delta.dy)?;
1463 }
1464 ShapeRecord::StyleChange(style_change) => {
1465 bits.write_bit(false)?; let num_fill_bits = context.num_fill_bits.into();
1467 let num_line_bits = context.num_line_bits.into();
1468 let mut flags = ShapeRecordFlag::empty();
1469 flags.set(ShapeRecordFlag::MOVE_TO, style_change.move_to.is_some());
1470 flags.set(
1471 ShapeRecordFlag::FILL_STYLE_0,
1472 style_change.fill_style_0.is_some(),
1473 );
1474 flags.set(
1475 ShapeRecordFlag::FILL_STYLE_1,
1476 style_change.fill_style_1.is_some(),
1477 );
1478 flags.set(
1479 ShapeRecordFlag::LINE_STYLE,
1480 style_change.line_style.is_some(),
1481 );
1482 flags.set(
1483 ShapeRecordFlag::NEW_STYLES,
1484 style_change.new_styles.is_some(),
1485 );
1486 bits.write_ubits(5, flags.bits().into())?;
1487 if let Some(move_to) = &style_change.move_to {
1488 let num_bits = count_sbits_twips(move_to.x).max(count_sbits_twips(move_to.y));
1489 bits.write_ubits(5, num_bits)?;
1490 bits.write_sbits_twips(num_bits, move_to.x)?;
1491 bits.write_sbits_twips(num_bits, move_to.y)?;
1492 }
1493 if let Some(fill_style_index) = style_change.fill_style_0 {
1494 bits.write_ubits(num_fill_bits, fill_style_index)?;
1495 }
1496 if let Some(fill_style_index) = style_change.fill_style_1 {
1497 bits.write_ubits(num_fill_bits, fill_style_index)?;
1498 }
1499 if let Some(line_style_index) = style_change.line_style {
1500 bits.write_ubits(num_line_bits, line_style_index)?;
1501 }
1502 if let Some(ref new_styles) = style_change.new_styles {
1503 if context.shape_version < 2 {
1504 return Err(Error::invalid_data(
1505 "Only DefineShape2 and higher may change styles.",
1506 ));
1507 }
1508 bits.flush()?;
1509 let mut writer = Writer::new(bits.writer(), context.swf_version);
1510 let (num_fill_bits, num_line_bits) =
1511 writer.write_shape_styles(new_styles, context.shape_version)?;
1512 context.num_fill_bits = num_fill_bits;
1513 context.num_line_bits = num_line_bits;
1514 }
1515 }
1516 }
1517 Ok(())
1518 }
1519
1520 fn write_fill_style(&mut self, fill_style: &FillStyle, shape_version: u8) -> Result<()> {
1521 match *fill_style {
1522 FillStyle::Color(ref color) => {
1523 self.write_u8(0x00)?; if shape_version >= 3 {
1525 self.write_rgba(color)?
1526 } else {
1527 self.write_rgb(color)?;
1528 }
1529 }
1530
1531 FillStyle::LinearGradient(ref gradient) => {
1532 self.write_u8(0x10)?; self.write_gradient(gradient, shape_version)?;
1534 }
1535
1536 FillStyle::RadialGradient(ref gradient) => {
1537 self.write_u8(0x12)?; self.write_gradient(gradient, shape_version)?;
1539 }
1540
1541 FillStyle::FocalGradient {
1542 ref gradient,
1543 focal_point,
1544 } => {
1545 self.write_u8(0x13)?; self.write_gradient(gradient, shape_version)?;
1547 self.write_fixed8(focal_point)?;
1548 }
1549
1550 FillStyle::Bitmap {
1551 id,
1552 ref matrix,
1553 is_smoothed,
1554 is_repeating,
1555 } => {
1556 let fill_style_type = match (is_smoothed || self.version < 8, is_repeating) {
1559 (true, true) => 0x40,
1560 (true, false) => 0x41,
1561 (false, true) => 0x42,
1562 (false, false) => 0x43,
1563 };
1564 self.write_u8(fill_style_type)?;
1565 self.write_u16(id)?;
1566 self.write_matrix(matrix)?;
1567 }
1568 }
1569 Ok(())
1570 }
1571
1572 fn write_line_style(&mut self, line_style: &LineStyle, shape_version: u8) -> Result<()> {
1573 self.write_u16(line_style.width.get() as u16)?;
1575 if shape_version >= 4 {
1576 self.write_u16(line_style.flags.bits())?;
1578 if let LineJoinStyle::Miter(miter_factor) = line_style.join_style() {
1579 self.write_fixed8(miter_factor)?;
1580 }
1581 if line_style.flags.contains(LineStyleFlag::HAS_FILL) {
1582 self.write_fill_style(&line_style.fill_style, shape_version)?;
1583 } else if let FillStyle::Color(color) = &line_style.fill_style {
1584 self.write_rgba(color)?;
1585 } else {
1586 return Err(Error::invalid_data("Unexpected line style fill type"));
1587 }
1588 } else {
1589 let color = if let FillStyle::Color(color) = &line_style.fill_style {
1591 color
1592 } else {
1593 return Err(Error::invalid_data(
1594 "Complex line styles can only be used in DefineShape4 tags",
1595 ));
1596 };
1597 if shape_version >= 3 {
1598 self.write_rgba(color)?
1599 } else {
1600 self.write_rgb(color)?
1601 }
1602 }
1603 Ok(())
1604 }
1605
1606 fn write_gradient(&mut self, gradient: &Gradient, shape_version: u8) -> Result<()> {
1607 self.write_matrix(&gradient.matrix)?;
1608 self.write_gradient_flags(gradient)?;
1609 for record in &gradient.records {
1610 self.write_u8(record.ratio)?;
1611 if shape_version >= 3 {
1612 self.write_rgba(&record.color)?;
1613 } else {
1614 self.write_rgb(&record.color)?;
1615 }
1616 }
1617 Ok(())
1618 }
1619
1620 fn write_gradient_flags(&mut self, gradient: &Gradient) -> Result<()> {
1621 let flags = ((gradient.spread as u8) << 6)
1622 | ((gradient.interpolation as u8) << 4)
1623 | ((gradient.records.len() as u8) & 0b1111);
1624 self.write_u8(flags)?;
1625 Ok(())
1626 }
1627
1628 fn write_place_object(&mut self, place_object: &PlaceObject) -> Result<()> {
1629 let mut buf = Vec::new();
1631 {
1632 let mut writer = Writer::new(&mut buf, self.version);
1633 if let PlaceObjectAction::Place(character_id) = place_object.action {
1634 writer.write_u16(character_id)?;
1635 } else {
1636 return Err(Error::invalid_data(
1637 "PlaceObject version 1 can only use a Place action.",
1638 ));
1639 }
1640 writer.write_u16(place_object.depth)?;
1641 if let Some(ref matrix) = place_object.matrix {
1642 writer.write_matrix(matrix)?;
1643 } else {
1644 writer.write_matrix(&Matrix::IDENTITY)?;
1645 }
1646 if let Some(ref color_transform) = place_object.color_transform {
1647 writer.write_color_transform_no_alpha(color_transform)?;
1648 }
1649 }
1650 self.write_tag_header(TagCode::PlaceObject, buf.len() as u32)?;
1651 self.output.write_all(&buf)?;
1652 Ok(())
1653 }
1654
1655 fn write_place_object_2_or_3(
1656 &mut self,
1657 place_object: &PlaceObject,
1658 place_object_version: u8,
1659 ) -> Result<()> {
1660 let mut buf = Vec::new();
1661 {
1662 let mut writer = Writer::new(&mut buf, self.version);
1664
1665 let mut flags = PlaceFlag::empty();
1666 flags.set(
1667 PlaceFlag::MOVE,
1668 matches!(
1669 place_object.action,
1670 PlaceObjectAction::Modify | PlaceObjectAction::Replace(_)
1671 ),
1672 );
1673 flags.set(
1674 PlaceFlag::HAS_CHARACTER,
1675 matches!(
1676 place_object.action,
1677 PlaceObjectAction::Place(_) | PlaceObjectAction::Replace(_)
1678 ),
1679 );
1680 flags.set(PlaceFlag::HAS_MATRIX, place_object.matrix.is_some());
1681 flags.set(
1682 PlaceFlag::HAS_COLOR_TRANSFORM,
1683 place_object.color_transform.is_some(),
1684 );
1685 flags.set(PlaceFlag::HAS_RATIO, place_object.ratio.is_some());
1686 flags.set(PlaceFlag::HAS_NAME, place_object.name.is_some());
1687 flags.set(PlaceFlag::HAS_CLIP_DEPTH, place_object.clip_depth.is_some());
1688 flags.set(
1689 PlaceFlag::HAS_CLIP_ACTIONS,
1690 place_object.clip_actions.is_some(),
1691 );
1692
1693 if place_object_version >= 3 {
1694 flags.set(PlaceFlag::HAS_FILTER_LIST, place_object.filters.is_some());
1695 flags.set(PlaceFlag::HAS_BLEND_MODE, place_object.blend_mode.is_some());
1696 flags.set(
1697 PlaceFlag::HAS_CACHE_AS_BITMAP,
1698 place_object.is_bitmap_cached.is_some(),
1699 );
1700 flags.set(PlaceFlag::HAS_CLASS_NAME, place_object.class_name.is_some());
1701 flags.set(PlaceFlag::HAS_IMAGE, place_object.has_image);
1702 flags.set(PlaceFlag::HAS_VISIBLE, place_object.is_visible.is_some());
1703 flags.set(
1704 PlaceFlag::OPAQUE_BACKGROUND,
1705 place_object.background_color.is_some(),
1706 );
1707 writer.write_u16(flags.bits())?;
1708 } else {
1709 writer.write_u8(flags.bits() as u8)?;
1710 }
1711
1712 writer.write_u16(place_object.depth)?;
1713
1714 if place_object_version >= 3 {
1715 if let Some(class_name) = place_object.class_name {
1716 writer.write_string(class_name)?;
1717 }
1718 }
1719
1720 match place_object.action {
1721 PlaceObjectAction::Place(character_id)
1722 | PlaceObjectAction::Replace(character_id) => writer.write_u16(character_id)?,
1723 PlaceObjectAction::Modify => (),
1724 }
1725 if let Some(ref matrix) = place_object.matrix {
1726 writer.write_matrix(matrix)?;
1727 };
1728 if let Some(ref color_transform) = place_object.color_transform {
1729 writer.write_color_transform(color_transform)?;
1730 };
1731 if let Some(ratio) = place_object.ratio {
1732 writer.write_u16(ratio)?;
1733 }
1734 if let Some(name) = place_object.name {
1735 writer.write_string(name)?;
1736 };
1737 if let Some(clip_depth) = place_object.clip_depth {
1738 writer.write_u16(clip_depth)?;
1739 }
1740
1741 if place_object_version >= 3 {
1742 if let Some(filters) = &place_object.filters {
1743 writer.write_u8(filters.len() as u8)?;
1744 for filter in filters {
1745 writer.write_filter(filter)?;
1746 }
1747 }
1748
1749 if let Some(blend_mode) = place_object.blend_mode {
1750 writer.write_blend_mode(blend_mode)?;
1751 }
1752
1753 if let Some(is_bitmap_cached) = place_object.is_bitmap_cached {
1754 writer.write_u8(if is_bitmap_cached { 1 } else { 0 })?;
1755 }
1756
1757 if let Some(is_visible) = place_object.is_visible {
1758 writer.write_u8(if is_visible { 1 } else { 0 })?;
1759 }
1760
1761 if let Some(ref background_color) = place_object.background_color {
1762 writer.write_rgba(background_color)?;
1763 }
1764 }
1765
1766 if let Some(clip_actions) = &place_object.clip_actions {
1767 writer.write_clip_actions(clip_actions)?;
1768 }
1769
1770 if place_object_version >= 4 {
1772 if let Some(data) = place_object.amf_data {
1773 writer.output.write_all(data)?;
1774 }
1775 }
1776 }
1777 let tag_code = match place_object_version {
1778 2 => TagCode::PlaceObject2,
1779 3 => TagCode::PlaceObject3,
1780 4 => TagCode::PlaceObject4,
1781 _ => return Err(Error::invalid_data("Invalid PlaceObject version.")),
1782 };
1783 self.write_tag_header(tag_code, buf.len() as u32)?;
1784 self.output.write_all(&buf)?;
1785 Ok(())
1786 }
1787
1788 fn write_drop_shadow_filter(&mut self, filter: &DropShadowFilter) -> Result<()> {
1789 self.write_rgba(&filter.color)?;
1790 self.write_fixed16(filter.blur_x)?;
1791 self.write_fixed16(filter.blur_y)?;
1792 self.write_fixed16(filter.angle)?;
1793 self.write_fixed16(filter.distance)?;
1794 self.write_fixed8(filter.strength)?;
1795 self.write_u8(filter.flags.bits())?;
1796 Ok(())
1797 }
1798
1799 fn write_blur_filter(&mut self, filter: &BlurFilter) -> Result<()> {
1800 self.write_fixed16(filter.blur_x)?;
1801 self.write_fixed16(filter.blur_y)?;
1802 self.write_u8(filter.flags.bits())?;
1803 Ok(())
1804 }
1805
1806 fn write_glow_filter(&mut self, filter: &GlowFilter) -> Result<()> {
1807 self.write_rgba(&filter.color)?;
1808 self.write_fixed16(filter.blur_x)?;
1809 self.write_fixed16(filter.blur_y)?;
1810 self.write_fixed8(filter.strength)?;
1811 self.write_u8(filter.flags.bits())?;
1812 Ok(())
1813 }
1814
1815 fn write_bevel_filter(&mut self, filter: &BevelFilter) -> Result<()> {
1816 self.write_rgba(&filter.highlight_color)?;
1818 self.write_rgba(&filter.shadow_color)?;
1819 self.write_fixed16(filter.blur_x)?;
1820 self.write_fixed16(filter.blur_y)?;
1821 self.write_fixed16(filter.angle)?;
1822 self.write_fixed16(filter.distance)?;
1823 self.write_fixed8(filter.strength)?;
1824 self.write_u8(filter.flags.bits())?;
1825 Ok(())
1826 }
1827
1828 fn write_gradient_filter(&mut self, filter: &GradientFilter) -> Result<()> {
1829 self.write_u8(filter.colors.len() as u8)?;
1830 for gradient_record in &filter.colors {
1831 self.write_rgba(&gradient_record.color)?;
1832 }
1833 for gradient_record in &filter.colors {
1834 self.write_u8(gradient_record.ratio)?;
1835 }
1836 self.write_fixed16(filter.blur_x)?;
1837 self.write_fixed16(filter.blur_y)?;
1838 self.write_fixed16(filter.angle)?;
1839 self.write_fixed16(filter.distance)?;
1840 self.write_fixed8(filter.strength)?;
1841 self.write_u8(filter.flags.bits())?;
1842 Ok(())
1843 }
1844
1845 fn write_convolution_filter(&mut self, filter: &ConvolutionFilter) -> Result<()> {
1846 self.write_u8(filter.num_matrix_cols)?;
1847 self.write_u8(filter.num_matrix_rows)?;
1848 self.write_f32(filter.divisor)?;
1849 self.write_f32(filter.bias)?;
1850 for val in &filter.matrix {
1851 self.write_f32(*val)?;
1852 }
1853 self.write_rgba(&filter.default_color)?;
1854 self.write_u8(filter.flags.bits())?;
1855 Ok(())
1856 }
1857
1858 fn write_color_matrix_filter(&mut self, filter: &ColorMatrixFilter) -> Result<()> {
1859 for m in filter.matrix {
1860 self.write_f32(m)?;
1861 }
1862 Ok(())
1863 }
1864
1865 fn write_filter(&mut self, filter: &Filter) -> Result<()> {
1866 match filter {
1867 Filter::DropShadowFilter(filter) => {
1868 self.write_u8(0)?;
1869 self.write_drop_shadow_filter(filter)
1870 }
1871 Filter::BlurFilter(filter) => {
1872 self.write_u8(1)?;
1873 self.write_blur_filter(filter)
1874 }
1875 Filter::GlowFilter(filter) => {
1876 self.write_u8(2)?;
1877 self.write_glow_filter(filter)
1878 }
1879 Filter::BevelFilter(filter) => {
1880 self.write_u8(3)?;
1881 self.write_bevel_filter(filter)
1882 }
1883 Filter::GradientGlowFilter(filter) => {
1884 self.write_u8(4)?;
1885 self.write_gradient_filter(filter)
1886 }
1887 Filter::ConvolutionFilter(filter) => {
1888 self.write_u8(5)?;
1889 self.write_convolution_filter(filter)
1890 }
1891 Filter::ColorMatrixFilter(filter) => {
1892 self.write_u8(6)?;
1893 self.write_color_matrix_filter(filter)
1894 }
1895 Filter::GradientBevelFilter(filter) => {
1896 self.write_u8(7)?;
1897 self.write_gradient_filter(filter)
1898 }
1899 }
1900 }
1901
1902 fn write_clip_actions(&mut self, clip_actions: &[ClipAction]) -> Result<()> {
1903 self.write_u16(0)?; {
1905 let mut all_events = ClipEventFlag::empty();
1906 for action in clip_actions {
1907 all_events |= action.events;
1908 }
1909 self.write_clip_event_flags(all_events)?;
1910 }
1911 for action in clip_actions {
1912 self.write_clip_event_flags(action.events)?;
1913 let action_length =
1914 action.action_data.len() as u32 + if action.key_code.is_some() { 1 } else { 0 };
1915 self.write_u32(action_length)?;
1916 if let Some(k) = action.key_code {
1917 self.write_u8(k)?;
1918 }
1919 self.output.write_all(action.action_data)?;
1920 }
1921 if self.version <= 5 {
1922 self.write_u16(0)?;
1923 } else {
1924 self.write_u32(0)?;
1925 }
1926 Ok(())
1927 }
1928
1929 fn write_clip_event_flags(&mut self, clip_events: ClipEventFlag) -> Result<()> {
1930 let bits = clip_events.bits();
1932 if self.version >= 6 {
1933 self.write_u32(bits)?;
1934 } else {
1935 self.write_u16((bits as u8).into())?;
1936 }
1937 Ok(())
1938 }
1939
1940 fn write_sound_stream_head(
1941 &mut self,
1942 stream_head: &SoundStreamHead,
1943 version: u8,
1944 ) -> Result<()> {
1945 let tag_code = if version >= 2 {
1946 TagCode::SoundStreamHead2
1947 } else {
1948 TagCode::SoundStreamHead
1949 };
1950 let length = if stream_head.stream_format.compression == AudioCompression::Mp3 {
1952 6
1953 } else {
1954 4
1955 };
1956 self.write_tag_header(tag_code, length)?;
1957 self.write_sound_format(&stream_head.playback_format)?;
1958 self.write_sound_format(&stream_head.stream_format)?;
1959 self.write_u16(stream_head.num_samples_per_block)?;
1960 if stream_head.stream_format.compression == AudioCompression::Mp3 {
1961 self.write_i16(stream_head.latency_seek)?;
1962 }
1963 Ok(())
1964 }
1965
1966 fn write_sound_format(&mut self, sound_format: &SoundFormat) -> Result<()> {
1967 let mut bits = self.bits();
1968 bits.write_ubits(4, sound_format.compression as u32)?;
1969 bits.write_ubits(
1970 2,
1971 match sound_format.sample_rate {
1972 5512 => 0,
1973 11025 => 1,
1974 22050 => 2,
1975 44100 => 3,
1976 _ => return Err(Error::invalid_data("Invalid sample rate.")),
1977 },
1978 )?;
1979 bits.write_bit(sound_format.is_16_bit)?;
1980 bits.write_bit(sound_format.is_stereo)?;
1981 Ok(())
1982 }
1983
1984 fn write_sound_info(&mut self, sound_info: &SoundInfo) -> Result<()> {
1985 let flags = ((sound_info.event as u8) << 4)
1986 | if sound_info.in_sample.is_some() {
1987 0b1
1988 } else {
1989 0
1990 }
1991 | if sound_info.out_sample.is_some() {
1992 0b10
1993 } else {
1994 0
1995 }
1996 | if sound_info.num_loops > 1 { 0b100 } else { 0 }
1997 | if sound_info.envelope.is_some() {
1998 0b1000
1999 } else {
2000 0
2001 };
2002 self.write_u8(flags)?;
2003 if let Some(n) = sound_info.in_sample {
2004 self.write_u32(n)?;
2005 }
2006 if let Some(n) = sound_info.out_sample {
2007 self.write_u32(n)?;
2008 }
2009 if sound_info.num_loops > 1 {
2010 self.write_u16(sound_info.num_loops)?;
2011 }
2012 if let Some(ref envelope) = sound_info.envelope {
2013 self.write_u8(envelope.len() as u8)?;
2014 for point in envelope {
2015 self.write_u32(point.sample)?;
2016 self.write_u16((point.left_volume * 32768f32) as u16)?;
2017 self.write_u16((point.right_volume * 32768f32) as u16)?;
2018 }
2019 }
2020 Ok(())
2021 }
2022
2023 fn write_define_font_2(&mut self, font: &Font) -> Result<()> {
2024 let mut buf = Vec::new();
2025 {
2026 let num_glyphs = font.glyphs.len();
2027
2028 let mut offsets = Vec::with_capacity(num_glyphs);
2034 let mut has_wide_offsets = false;
2035 let has_wide_codes = !font.flags.contains(FontFlag::IS_ANSI);
2036 let mut shape_buf = Vec::new();
2037 {
2038 let mut shape_writer = Writer::new(&mut shape_buf, self.version);
2039
2040 let mut shape_context = ShapeContext {
2042 swf_version: self.version,
2043 shape_version: 1,
2044 num_fill_bits: 1,
2045 num_line_bits: 0,
2046 };
2047 for glyph in &font.glyphs {
2048 let offset = shape_writer.output.len();
2050 offsets.push(offset);
2051 if offset > 0xFFFF {
2052 has_wide_offsets = true;
2053 }
2054
2055 shape_writer.write_u8(0b0001_0000)?;
2056 let mut bits = shape_writer.bits();
2057 for shape_record in &glyph.shape_records {
2058 Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?;
2059 }
2060 bits.write_ubits(6, 0)?;
2062 }
2063 }
2064
2065 let mut writer = Writer::new(&mut buf, self.version);
2066 writer.write_character_id(font.id)?;
2067 writer.write_u8(font.flags.bits())?;
2068 writer.write_language(font.language)?;
2069 writer.write_u8(font.name.len() as u8)?;
2070 writer.output.write_all(font.name.as_bytes())?;
2071 writer.write_u16(num_glyphs as u16)?;
2072
2073 if num_glyphs > 0 {
2075 let init_offset = if has_wide_offsets {
2077 num_glyphs * 4 + 4
2078 } else {
2079 num_glyphs * 2 + 2
2080 };
2081
2082 for offset in offsets {
2084 if has_wide_offsets {
2085 writer.write_u32((offset + init_offset) as u32)?;
2086 } else {
2087 writer.write_u16((offset + init_offset) as u16)?;
2088 }
2089 }
2090
2091 let code_table_offset =
2093 (num_glyphs + 1) * if has_wide_offsets { 4 } else { 2 } + shape_buf.len();
2094 if has_wide_offsets {
2095 writer.write_u32(code_table_offset as u32)?;
2096 } else {
2097 writer.write_u16(code_table_offset as u16)?;
2098 }
2099
2100 writer.output.write_all(&shape_buf)?;
2101
2102 for glyph in &font.glyphs {
2104 if has_wide_codes {
2105 writer.write_u16(glyph.code)?;
2106 } else {
2107 writer.write_u8(glyph.code as u8)?;
2108 }
2109 }
2110 }
2111
2112 if let Some(ref layout) = font.layout {
2113 writer.write_u16(layout.ascent)?;
2114 writer.write_u16(layout.descent)?;
2115 writer.write_i16(layout.leading)?;
2116 for glyph in &font.glyphs {
2117 writer.write_i16(glyph.advance)?;
2118 }
2119 for glyph in &font.glyphs {
2120 writer.write_rectangle(
2121 glyph
2122 .bounds
2123 .as_ref()
2124 .ok_or_else(|| Error::invalid_data("glyph.bounds cannot be None"))?,
2125 )?;
2126 }
2127 writer.write_u16(layout.kerning.len() as u16)?;
2128 for kerning_record in &layout.kerning {
2129 writer.write_kerning_record(kerning_record, has_wide_codes)?;
2130 }
2131 }
2132 }
2133
2134 let tag_code = if font.version == 2 {
2135 TagCode::DefineFont2
2136 } else {
2137 TagCode::DefineFont3
2138 };
2139 self.write_tag_header(tag_code, buf.len() as u32)?;
2140 self.output.write_all(&buf)?;
2141 Ok(())
2142 }
2143
2144 fn write_define_font_4(&mut self, font: &Font4) -> Result<()> {
2145 let mut tag_len = 4 + font.name.len();
2146 if let Some(data) = font.data {
2147 tag_len += data.len()
2148 };
2149 self.write_tag_header(TagCode::DefineFont4, tag_len as u32)?;
2150 self.write_character_id(font.id)?;
2151 self.write_u8(
2152 if font.data.is_some() { 0b100 } else { 0 }
2153 | if font.is_italic { 0b10 } else { 0 }
2154 | if font.is_bold { 0b1 } else { 0 },
2155 )?;
2156 self.write_string(font.name)?;
2157 if let Some(data) = font.data {
2158 self.output.write_all(data)?;
2159 }
2160 Ok(())
2161 }
2162
2163 fn write_define_font_info(&mut self, font_info: &FontInfo) -> Result<()> {
2164 let use_wide_codes = self.version >= 6
2165 || font_info.version >= 2
2166 || font_info.flags.contains(FontInfoFlag::HAS_WIDE_CODES);
2167
2168 let len = font_info.name.len()
2169 + if use_wide_codes { 2 } else { 1 } * font_info.code_table.len()
2170 + if font_info.version >= 2 { 1 } else { 0 }
2171 + 4;
2172
2173 let tag_id = if font_info.version == 1 {
2174 TagCode::DefineFontInfo
2175 } else {
2176 TagCode::DefineFontInfo2
2177 };
2178 self.write_tag_header(tag_id, len as u32)?;
2179 self.write_u16(font_info.id)?;
2180
2181 self.write_u8(font_info.name.len() as u8)?;
2183 self.output.write_all(font_info.name.as_bytes())?;
2184
2185 let mut flags = font_info.flags;
2186 flags.set(FontInfoFlag::HAS_WIDE_CODES, use_wide_codes);
2187 self.write_u8(flags.bits())?;
2188
2189 if font_info.version >= 2 {
2191 self.write_language(font_info.language)?;
2192 }
2193 for &code in &font_info.code_table {
2194 if use_wide_codes {
2195 self.write_u16(code)?;
2196 } else {
2197 self.write_u8(code as u8)?;
2198 }
2199 }
2200 Ok(())
2201 }
2202
2203 fn write_kerning_record(
2204 &mut self,
2205 kerning: &KerningRecord,
2206 has_wide_codes: bool,
2207 ) -> Result<()> {
2208 if has_wide_codes {
2209 self.write_u16(kerning.left_code)?;
2210 self.write_u16(kerning.right_code)?;
2211 } else {
2212 self.write_u8(kerning.left_code as u8)?;
2213 self.write_u8(kerning.right_code as u8)?;
2214 }
2215 self.write_i16(kerning.adjustment.get() as i16)?; Ok(())
2217 }
2218
2219 fn write_define_binary_data(&mut self, binary_data: &DefineBinaryData) -> Result<()> {
2220 self.write_tag_header(TagCode::DefineBinaryData, binary_data.data.len() as u32 + 6)?;
2221 self.write_u16(binary_data.id)?;
2222 self.write_u32(0)?; self.output.write_all(binary_data.data)?;
2224 Ok(())
2225 }
2226
2227 fn write_define_text(&mut self, text: &Text, version: u8) -> Result<()> {
2228 let mut buf = Vec::new();
2229 {
2230 let mut writer = Writer::new(&mut buf, self.version);
2231 writer.write_character_id(text.id)?;
2232 writer.write_rectangle(&text.bounds)?;
2233 writer.write_matrix(&text.matrix)?;
2234 let num_glyph_bits = text
2235 .records
2236 .iter()
2237 .flat_map(|r| r.glyphs.iter().map(|g| count_ubits(g.index)))
2238 .max()
2239 .unwrap_or(0);
2240 let num_advance_bits = text
2241 .records
2242 .iter()
2243 .flat_map(|r| r.glyphs.iter().map(|g| count_sbits(g.advance)))
2244 .max()
2245 .unwrap_or(0);
2246 writer.write_u8(num_glyph_bits as u8)?;
2247 writer.write_u8(num_advance_bits as u8)?;
2248
2249 for record in &text.records {
2250 let flags = 0b10000000
2251 | if record.font_id.is_some() { 0b1000 } else { 0 }
2252 | if record.color.is_some() { 0b100 } else { 0 }
2253 | if record.y_offset.is_some() { 0b10 } else { 0 }
2254 | if record.x_offset.is_some() { 0b1 } else { 0 };
2255 writer.write_u8(flags)?;
2256 if let Some(id) = record.font_id {
2257 writer.write_character_id(id)?;
2258 }
2259 if let Some(ref color) = record.color {
2260 if version == 1 {
2261 writer.write_rgb(color)?;
2262 } else {
2263 writer.write_rgba(color)?;
2264 }
2265 }
2266 if let Some(x) = record.x_offset {
2267 writer.write_i16(x.get() as i16)?; }
2269 if let Some(y) = record.y_offset {
2270 writer.write_i16(y.get() as i16)?;
2271 }
2272 if let Some(height) = record.height {
2273 writer.write_u16(height.get() as u16)?;
2274 }
2275 writer.write_u8(record.glyphs.len() as u8)?;
2276 let mut bits = writer.bits();
2277 for glyph in &record.glyphs {
2278 bits.write_ubits(num_glyph_bits, glyph.index)?;
2279 bits.write_sbits(num_advance_bits, glyph.advance)?;
2280 }
2281 }
2282 writer.write_u8(0)?; }
2284 if version == 1 {
2285 self.write_tag_header(TagCode::DefineText, buf.len() as u32)?;
2286 } else {
2287 self.write_tag_header(TagCode::DefineText2, buf.len() as u32)?;
2288 }
2289 self.output.write_all(&buf)?;
2290 Ok(())
2291 }
2292
2293 fn write_define_edit_text(&mut self, edit_text: &EditText) -> Result<()> {
2294 let mut buf = Vec::new();
2295 {
2296 let mut writer = Writer::new(&mut buf, self.version);
2297 writer.write_character_id(edit_text.id)?;
2298 writer.write_rectangle(&edit_text.bounds)?;
2299 writer.write_u16(edit_text.flags.bits())?;
2300
2301 if let Some(font_id) = edit_text.font_id() {
2302 writer.write_character_id(font_id)?;
2303 }
2304
2305 if let Some(class) = edit_text.font_class() {
2307 writer.write_string(class)?;
2308 }
2309
2310 if let Some(height) = edit_text.height() {
2311 writer.write_u16(height.get() as u16)?
2312 }
2313
2314 if let Some(color) = edit_text.color() {
2315 writer.write_rgba(color)?
2316 }
2317
2318 if let Some(len) = edit_text.max_length() {
2319 writer.write_u16(len)?;
2320 }
2321
2322 if let Some(layout) = edit_text.layout() {
2323 writer.write_u8(layout.align as u8)?;
2324 writer.write_u16(layout.left_margin.get() as u16)?; writer.write_u16(layout.right_margin.get() as u16)?;
2326 writer.write_u16(layout.indent.get() as u16)?;
2327 writer.write_i16(layout.leading.get() as i16)?;
2328 }
2329
2330 writer.write_string(edit_text.variable_name)?;
2331
2332 if let Some(text) = edit_text.initial_text() {
2333 writer.write_string(text)?;
2334 }
2335 }
2336
2337 self.write_tag_header(TagCode::DefineEditText, buf.len() as u32)?;
2338 self.output.write_all(&buf)?;
2339 Ok(())
2340 }
2341
2342 fn write_define_video_stream(&mut self, video: &DefineVideoStream) -> Result<()> {
2343 self.write_tag_header(TagCode::DefineVideoStream, 10)?;
2344 self.write_character_id(video.id)?;
2345 self.write_u16(video.num_frames)?;
2346 self.write_u16(video.width)?;
2347 self.write_u16(video.height)?;
2348 self.write_u8(((video.deblocking as u8) << 1) | if video.is_smoothed { 0b1 } else { 0 })?;
2349 self.write_u8(video.codec as u8)?;
2350 Ok(())
2351 }
2352
2353 fn write_product_info(&mut self, product_info: &ProductInfo) -> Result<()> {
2354 self.write_tag_header(TagCode::ProductInfo, 26)?;
2355 self.write_u32(product_info.product_id)?;
2356 self.write_u32(product_info.edition)?;
2357 self.write_u8(product_info.major_version)?;
2358 self.write_u8(product_info.minor_version)?;
2359 self.write_u64(product_info.build_number)?;
2360 self.write_u64(product_info.compilation_date)?;
2361 Ok(())
2362 }
2363
2364 fn write_debug_id(&mut self, debug_id: &DebugId) -> Result<()> {
2365 self.write_tag_header(TagCode::DebugId, debug_id.len() as u32)?;
2366 self.output.write_all(debug_id)?;
2367 Ok(())
2368 }
2369
2370 fn write_name_character(&mut self, name_character: &NameCharacter) -> Result<()> {
2371 self.write_tag_header(TagCode::NameCharacter, 3 + name_character.name.len() as u32)?;
2372 self.write_character_id(name_character.id)?;
2373 self.write_string(name_character.name)?;
2374 Ok(())
2375 }
2376
2377 fn write_tag_header(&mut self, tag_code: TagCode, length: u32) -> Result<()> {
2378 self.write_tag_code_and_length(tag_code as u16, length)
2379 }
2380
2381 fn write_tag_code_and_length(&mut self, tag_code: u16, length: u32) -> Result<()> {
2382 let mut tag_code_and_length = tag_code << 6;
2384 if length < 0b111111 {
2385 tag_code_and_length |= length as u16;
2386 self.write_u16(tag_code_and_length)?;
2387 } else {
2388 tag_code_and_length |= 0b111111;
2389 self.write_u16(tag_code_and_length)?;
2390 self.write_u32(length)?;
2391 }
2392 Ok(())
2393 }
2394
2395 fn write_tag_list(&mut self, tags: &[Tag]) -> Result<()> {
2396 for tag in tags {
2398 self.write_tag(tag)?;
2399 }
2400 self.write_tag(&Tag::End)?;
2402 Ok(())
2403 }
2404}
2405
2406fn count_ubits(n: u32) -> u32 {
2407 32 - n.leading_zeros()
2408}
2409
2410fn count_sbits(n: i32) -> u32 {
2411 if n == 0 {
2412 0
2413 } else if n == -1 {
2414 1
2415 } else if n < 0 {
2416 count_ubits((!n) as u32) + 1
2417 } else {
2418 count_ubits(n as u32) + 1
2419 }
2420}
2421
2422fn count_sbits_twips(n: Twips) -> u32 {
2423 count_sbits(n.get())
2424}
2425
2426fn count_fbits(n: Fixed16) -> u32 {
2427 count_sbits(n.get())
2428}
2429
2430#[cfg(test)]
2431#[allow(clippy::unusual_byte_groupings)]
2432mod tests {
2433 use super::*;
2434 use crate::test_data;
2435
2436 #[test]
2437 fn write_swfs() {
2438 fn write_dummy_swf(compression: Compression) -> Result<()> {
2439 let mut buf = Vec::new();
2440 let header = Header {
2441 compression,
2442 version: 13,
2443 stage_size: Rectangle {
2444 x_min: Twips::ZERO,
2445 x_max: Twips::from_pixels(640.0),
2446 y_min: Twips::ZERO,
2447 y_max: Twips::from_pixels(480.0),
2448 },
2449 frame_rate: Fixed8::from_f32(60.0),
2450 num_frames: 1,
2451 };
2452 write_swf(&header, &[], &mut buf)?;
2453 Ok(())
2454 }
2455 assert!(
2456 write_dummy_swf(Compression::None).is_ok(),
2457 "Failed to write uncompressed SWF."
2458 );
2459 assert!(
2460 write_dummy_swf(Compression::Zlib).is_ok(),
2461 "Failed to write zlib SWF."
2462 );
2463 if cfg!(feature = "lzma") {
2464 assert!(
2465 write_dummy_swf(Compression::Lzma).is_ok(),
2466 "Failed to write LZMA SWF."
2467 );
2468 }
2469 }
2470
2471 #[test]
2472 fn write_fixed8() {
2473 let mut buf = Vec::new();
2474 {
2475 let mut writer = Writer::new(&mut buf, 1);
2476 writer.write_fixed8(Fixed8::ZERO).unwrap();
2477 writer.write_fixed8(Fixed8::ONE).unwrap();
2478 writer.write_fixed8(Fixed8::from_f32(6.5)).unwrap();
2479 writer.write_fixed8(Fixed8::from_f32(-20.75)).unwrap();
2480 }
2481 assert_eq!(
2482 buf,
2483 [
2484 0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b10000000, 0b00000110, 0b01000000,
2485 0b11101011
2486 ]
2487 );
2488 }
2489
2490 #[test]
2491 fn write_encoded_u32() {
2492 fn write_to_buf(n: u32) -> Vec<u8> {
2493 let mut buf = Vec::new();
2494 {
2495 let mut writer = Writer::new(&mut buf, 1);
2496 writer.write_encoded_u32(n).unwrap();
2497 }
2498 buf
2499 }
2500
2501 assert_eq!(write_to_buf(0), [0]);
2502 assert_eq!(write_to_buf(2), [2]);
2503 assert_eq!(write_to_buf(129), [0b1_0000001, 0b0_0000001]);
2504 assert_eq!(
2505 write_to_buf(0b1100111_0000001_0000001),
2506 [0b1_0000001, 0b1_0000001, 0b0_1100111]
2507 );
2508 assert_eq!(
2509 write_to_buf(0b1111_0000000_0000000_0000000_0000000u32),
2510 [
2511 0b1_0000000,
2512 0b1_0000000,
2513 0b1_0000000,
2514 0b1_0000000,
2515 0b0000_1111
2516 ]
2517 );
2518 }
2519
2520 #[test]
2521 fn write_bit() {
2522 let out_bits = [
2523 false, true, false, true, false, true, false, true, false, false, true, false, false,
2524 true, false, true,
2525 ];
2526 let mut buf = Vec::new();
2527 {
2528 let mut writer = Writer::new(&mut buf, 1);
2529 let mut bits = writer.bits();
2530 for b in &out_bits {
2531 bits.write_bit(*b).unwrap();
2532 }
2533 }
2534 assert_eq!(buf, [0b01010101, 0b00100101]);
2535 }
2536
2537 #[test]
2538 fn write_ubits() {
2539 let num_bits = 2;
2540 let nums = [1, 1, 1, 1, 0, 2, 1, 1];
2541 let mut buf = Vec::new();
2542 {
2543 let mut writer = Writer::new(&mut buf, 1);
2544 let mut bits = writer.bits();
2545 for n in &nums {
2546 bits.write_ubits(num_bits, *n).unwrap();
2547 }
2548 }
2549 assert_eq!(buf, [0b01010101, 0b00100101]);
2550 }
2551
2552 #[test]
2553 fn write_sbits() {
2554 let num_bits = 2;
2555 let nums = [1, 1, 1, 1, 0, -2, 1, 1];
2556 let mut buf = Vec::new();
2557 {
2558 let mut writer = Writer::new(&mut buf, 1);
2559 let mut bits = writer.bits();
2560 for n in &nums {
2561 bits.write_sbits(num_bits, *n).unwrap();
2562 }
2563 }
2564 assert_eq!(buf, [0b01010101, 0b00100101]);
2565 }
2566
2567 #[test]
2568 fn write_fbits() {
2569 let num_bits = 18;
2570 let nums = [1.0, -1.0];
2571 let mut buf = Vec::new();
2572 {
2573 let mut writer = Writer::new(&mut buf, 1);
2574 let mut bits = writer.bits();
2575 for n in &nums {
2576 bits.write_fbits(num_bits, Fixed16::from_f32(*n)).unwrap();
2577 }
2578 }
2579 assert_eq!(
2580 buf,
2581 [
2582 0b01_000000,
2583 0b00000000,
2584 0b00_11_0000,
2585 0b00000000,
2586 0b0000_0000
2587 ]
2588 );
2589 }
2590
2591 #[test]
2592 fn count_ubits() {
2593 assert_eq!(super::count_ubits(0), 0);
2594 assert_eq!(super::count_ubits(1u32), 1);
2595 assert_eq!(super::count_ubits(2u32), 2);
2596 assert_eq!(super::count_ubits(0b_00111101_00000000u32), 14);
2597 }
2598
2599 #[test]
2600 fn count_sbits() {
2601 assert_eq!(super::count_sbits(0), 0);
2602 assert_eq!(super::count_sbits(1), 2);
2603 assert_eq!(super::count_sbits(2), 3);
2604 assert_eq!(super::count_sbits(0b_00111101_00000000), 15);
2605
2606 assert_eq!(super::count_sbits(-1), 1);
2607 assert_eq!(super::count_sbits(-2), 2);
2608 assert_eq!(super::count_sbits(-0b_00110101_01010101), 15);
2609 }
2610
2611 #[test]
2612 fn write_c_string() {
2613 {
2614 let mut buf = Vec::new();
2615 {
2616 let mut writer = Writer::new(&mut buf, 1);
2618 writer.write_string("Hello!".into()).unwrap();
2619 }
2620 assert_eq!(buf, "Hello!\0".bytes().collect::<Vec<_>>());
2621 }
2622
2623 {
2624 let mut buf = Vec::new();
2625 {
2626 let mut writer = Writer::new(&mut buf, 1);
2628 writer.write_string("😀😂!🐼".into()).unwrap();
2629 }
2630 assert_eq!(buf, "😀😂!🐼\0".bytes().collect::<Vec<_>>());
2631 }
2632 }
2633
2634 #[test]
2635 fn write_rectangle_zero() {
2636 let rectangle = Rectangle {
2637 x_min: Twips::ZERO,
2638 y_min: Twips::ZERO,
2639 x_max: Twips::ZERO,
2640 y_max: Twips::ZERO,
2641 };
2642 let mut buf = Vec::new();
2643 {
2644 let mut writer = Writer::new(&mut buf, 1);
2645 writer.write_rectangle(&rectangle).unwrap();
2646 }
2647 assert_eq!(buf, [0]);
2648 }
2649
2650 #[test]
2651 fn write_rectangle_signed() {
2652 let rectangle = Rectangle {
2653 x_min: -Twips::ONE_PX,
2654 x_max: Twips::ONE_PX,
2655 y_min: -Twips::ONE_PX,
2656 y_max: Twips::ONE_PX,
2657 };
2658 let mut buf = Vec::new();
2659 {
2660 let mut writer = Writer::new(&mut buf, 1);
2661 writer.write_rectangle(&rectangle).unwrap();
2662 }
2663 assert_eq!(buf, [0b_00110_101, 0b100_01010, 0b0_101100_0, 0b_10100_000]);
2664 }
2665
2666 #[test]
2667 fn write_color() {
2668 {
2669 let color = Color {
2670 r: 1,
2671 g: 128,
2672 b: 255,
2673 a: 255,
2674 };
2675 let mut buf = Vec::new();
2676 {
2677 let mut writer = Writer::new(&mut buf, 1);
2678 writer.write_rgb(&color).unwrap();
2679 }
2680 assert_eq!(buf, [1, 128, 255]);
2681 }
2682 {
2683 let color = Color {
2684 r: 1,
2685 g: 2,
2686 b: 3,
2687 a: 11,
2688 };
2689 let mut buf = Vec::new();
2690 {
2691 let mut writer = Writer::new(&mut buf, 1);
2692 writer.write_rgba(&color).unwrap();
2693 }
2694 assert_eq!(buf, [1, 2, 3, 11]);
2695 }
2696 }
2697
2698 #[test]
2699 fn write_matrix() {
2700 fn write_to_buf(m: &Matrix) -> Vec<u8> {
2701 let mut buf = Vec::new();
2702 {
2703 let mut writer = Writer::new(&mut buf, 1);
2704 writer.write_matrix(m).unwrap();
2705 }
2706 buf
2707 }
2708
2709 let m = Matrix::IDENTITY;
2710 assert_eq!(write_to_buf(&m), [0]);
2711 }
2712
2713 #[test]
2714 fn write_tags() {
2715 for (swf_version, tag, expected_tag_bytes) in test_data::tag_tests() {
2716 let mut written_tag_bytes = Vec::new();
2717 Writer::new(&mut written_tag_bytes, swf_version)
2718 .write_tag(&tag)
2719 .unwrap();
2720 assert_eq!(
2721 written_tag_bytes, expected_tag_bytes,
2722 "Error reading tag.\nTag:\n{tag:?}\n\nWrote:\n{written_tag_bytes:?}\n\nExpected:\n{expected_tag_bytes:?}",
2723 );
2724 }
2725 }
2726
2727 #[test]
2728 fn write_tag_to_buf_list() {
2729 {
2730 let mut buf = Vec::new();
2731 {
2732 let mut writer = Writer::new(&mut buf, 1);
2733 writer.write_tag_list(&[]).unwrap();
2734 }
2735 assert_eq!(buf, [0, 0]);
2736 }
2737 {
2738 let mut buf = Vec::new();
2739 {
2740 let mut writer = Writer::new(&mut buf, 1);
2741 writer.write_tag_list(&[Tag::ShowFrame]).unwrap();
2742 }
2743 assert_eq!(buf, [0b01_000000, 0b00000000, 0, 0]);
2744 }
2745 {
2746 let mut buf = Vec::new();
2747 {
2748 let mut writer = Writer::new(&mut buf, 1);
2749 writer
2750 .write_tag_list(&[
2751 Tag::Unknown {
2752 tag_code: 512,
2753 data: &[0; 100],
2754 },
2755 Tag::ShowFrame,
2756 ])
2757 .unwrap();
2758 }
2759 let mut expected = vec![0b00_111111, 0b10000000, 100, 0, 0, 0];
2760 expected.extend_from_slice(&[0; 100]);
2761 expected.extend_from_slice(&[0b01_000000, 0b00000000, 0, 0]);
2762 assert_eq!(buf, expected);
2763 }
2764 }
2765
2766 #[test]
2767 fn write_font_3() {
2768 use crate::read::Reader;
2769
2770 let font = Font {
2771 version: 3,
2772 id: 1,
2773 name: SwfStr::from_bytes(b"font"),
2774 language: Language::Unknown,
2775 layout: None,
2776 glyphs: vec![Glyph {
2777 shape_records: vec![
2778 ShapeRecord::StraightEdge {
2779 delta: PointDelta::new(Twips::ONE_PX, -Twips::ONE_PX),
2780 },
2781 ShapeRecord::CurvedEdge {
2782 control_delta: PointDelta::new(Twips::ONE_PX, Twips::ONE_PX),
2783 anchor_delta: PointDelta::new(Twips::ONE_PX, -Twips::ONE_PX),
2784 },
2785 ShapeRecord::StraightEdge {
2786 delta: PointDelta::new(Twips::ZERO, Twips::ZERO),
2787 },
2788 ShapeRecord::CurvedEdge {
2789 control_delta: PointDelta::new(Twips::ZERO, Twips::ZERO),
2790 anchor_delta: PointDelta::new(Twips::ZERO, Twips::ZERO),
2791 },
2792 ],
2793 code: 1,
2794 advance: 0,
2795 bounds: None,
2796 }],
2797 flags: FontFlag::empty(),
2798 };
2799
2800 let mut buf = Vec::new();
2801 let mut writer = Writer::new(&mut buf, 13);
2802 writer.write_define_font_2(&font).unwrap();
2803
2804 let mut reader = Reader::new(&buf, 13);
2805 let tag = reader.read_tag().unwrap();
2806
2807 assert_eq!(tag, Tag::DefineFont2(Box::new(font)));
2808 }
2809
2810 #[test]
2811 fn write_define_button_2() {
2812 use crate::read::Reader;
2813
2814 let button = Button {
2815 id: 3,
2816 is_track_as_menu: false,
2817 records: vec![ButtonRecord {
2818 states: ButtonState::UP
2819 | ButtonState::OVER
2820 | ButtonState::DOWN
2821 | ButtonState::HIT_TEST,
2822 id: 2,
2823 depth: 1,
2824 matrix: Matrix::translate(Twips::from_pixels(2.0), Twips::from_pixels(3.0)),
2825 color_transform: ColorTransform::default(),
2826 filters: vec![],
2827 blend_mode: BlendMode::Normal,
2828 }],
2829 actions: vec![],
2830 };
2831
2832 let mut buf = Vec::new();
2833 let mut writer = Writer::new(&mut buf, 15);
2834 writer.write_define_button_2(&button).unwrap();
2835
2836 let mut reader = Reader::new(&buf, 15);
2837 let tag = reader.read_tag().unwrap();
2838
2839 assert_eq!(tag, Tag::DefineButton2(Box::new(button)));
2840 }
2841
2842 #[test]
2843 fn write_define_button_2_with_keycode() {
2844 use crate::read::Reader;
2845
2846 let button = Button {
2847 id: 3,
2848 is_track_as_menu: false,
2849 records: vec![ButtonRecord {
2850 states: ButtonState::UP
2851 | ButtonState::OVER
2852 | ButtonState::DOWN
2853 | ButtonState::HIT_TEST,
2854 id: 2,
2855 depth: 1,
2856 matrix: Matrix::translate(Twips::from_pixels(2.0), Twips::from_pixels(3.0)),
2857 color_transform: ColorTransform::default(),
2858 filters: vec![],
2859 blend_mode: BlendMode::Normal,
2860 }],
2861 actions: vec![ButtonAction {
2862 conditions: ButtonActionCondition::from_key_code(18),
2863 action_data: &[
2864 150, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 104, 105, 115, 0, 28, 150, 12,
2865 0, 0, 116, 97, 98, 72, 97, 110, 100, 108, 101, 114, 0, 82, 23, 0,
2866 ],
2867 }],
2868 };
2869
2870 let mut buf = Vec::new();
2871 let mut writer = Writer::new(&mut buf, 15);
2872 writer.write_define_button_2(&button).unwrap();
2873
2874 let mut reader = Reader::new(&buf, 15);
2875 let tag = reader.read_tag().unwrap();
2876
2877 assert_eq!(tag, Tag::DefineButton2(Box::new(button)));
2878 }
2879
2880 #[test]
2881 fn write_bevel_filter() {
2882 use crate::read::Reader;
2883
2884 let filter = Filter::BevelFilter(Box::new(BevelFilter {
2885 shadow_color: Color {
2886 r: 111,
2887 g: 222,
2888 b: 33,
2889 a: 4,
2890 },
2891 highlight_color: Color {
2892 r: 10,
2893 g: 20,
2894 b: 30,
2895 a: 40,
2896 },
2897 blur_x: Fixed16::from_f32(3.1),
2898 blur_y: Fixed16::from_f32(5.5),
2899 angle: Fixed16::from_f32(180.0),
2900 distance: Fixed16::from_f32(10.8),
2901 strength: Fixed8::from_f32(3.1),
2902 flags: BevelFilterFlags::COMPOSITE_SOURCE
2903 | BevelFilterFlags::ON_TOP
2904 | BevelFilterFlags::from_passes(2),
2905 }));
2906
2907 let mut buf = Vec::new();
2908 let mut writer = Writer::new(&mut buf, 15);
2909 writer.write_filter(&filter).unwrap();
2910
2911 let mut reader = Reader::new(&buf, 15);
2912 let reread = reader.read_filter().unwrap();
2913
2914 assert_eq!(reread, filter);
2915 }
2916
2917 #[test]
2918 fn write_define_text_2() {
2919 use crate::read::Reader;
2920
2921 let text = Text {
2922 id: 60,
2923 bounds: Rectangle {
2924 x_min: Twips::new(2),
2925 x_max: Twips::new(559),
2926 y_min: Twips::new(-4),
2927 y_max: Twips::new(76),
2928 },
2929 matrix: Matrix {
2930 a: Fixed16::ONE,
2931 b: Fixed16::ZERO,
2932 c: Fixed16::ZERO,
2933 d: Fixed16::ONE,
2934 tx: Twips::ZERO,
2935 ty: Twips::ZERO,
2936 },
2937 records: vec![TextRecord {
2938 font_id: Some(57),
2939 color: Some(Color {
2940 r: 112,
2941 g: 103,
2942 b: 5,
2943 a: 69,
2944 }),
2945 x_offset: None,
2946 y_offset: Some(Twips::new(76)),
2947 height: Some(Twips::new(100)),
2948 glyphs: vec![
2949 GlyphEntry {
2950 index: 13,
2951 advance: 32,
2952 },
2953 GlyphEntry {
2954 index: 2,
2955 advance: 38,
2956 },
2957 GlyphEntry {
2958 index: 8,
2959 advance: 41,
2960 },
2961 GlyphEntry {
2962 index: 6,
2963 advance: 18,
2964 },
2965 GlyphEntry {
2966 index: 7,
2967 advance: 33,
2968 },
2969 GlyphEntry {
2970 index: 7,
2971 advance: 33,
2972 },
2973 GlyphEntry {
2974 index: 2,
2975 advance: 38,
2976 },
2977 GlyphEntry {
2978 index: 0,
2979 advance: 19,
2980 },
2981 GlyphEntry {
2982 index: 6,
2983 advance: 18,
2984 },
2985 GlyphEntry {
2986 index: 3,
2987 advance: 35,
2988 },
2989 GlyphEntry {
2990 index: 4,
2991 advance: 37,
2992 },
2993 GlyphEntry {
2994 index: 0,
2995 advance: 19,
2996 },
2997 GlyphEntry {
2998 index: 1,
2999 advance: 23,
3000 },
3001 GlyphEntry {
3002 index: 0,
3003 advance: 19,
3004 },
3005 GlyphEntry {
3006 index: 7,
3007 advance: 33,
3008 },
3009 GlyphEntry {
3010 index: 5,
3011 advance: 39,
3012 },
3013 GlyphEntry {
3014 index: 10,
3015 advance: 40,
3016 },
3017 ],
3018 }],
3019 };
3020
3021 let mut buf = Vec::new();
3022 let mut writer = Writer::new(&mut buf, 4);
3023 writer.write_define_text(&text, 2).unwrap();
3024
3025 let mut reader = Reader::new(&buf, 4);
3026 let reread = reader.read_tag().unwrap();
3027
3028 assert_eq!(reread, Tag::DefineText2(Box::new(text)));
3029 }
3030
3031 #[test]
3032 fn write_define_font_info() {
3033 use crate::read::Reader;
3034
3035 let font_info = FontInfo {
3036 id: 1,
3037 version: 1,
3038 name: SwfStr::from_bytes(b"Schauer"),
3039 flags: FontInfoFlag::HAS_WIDE_CODES | FontInfoFlag::IS_BOLD,
3040 language: Language::Unknown,
3041 code_table: vec![
3042 80, 108, 97, 121, 32, 109, 111, 118, 105, 101, 53, 48, 54, 75, 103, 115, 116, 74,
3043 65, 67, 83, 86, 71, 84, 89, 76, 69, 42, 104, 46, 73, 100, 87, 107, 110, 102, 117,
3044 99, 114, 63, 79, 39, 119, 44, 112, 33, 120, 72, 122, 58, 77, 45, 98, 40, 41, 70,
3045 ],
3046 };
3047
3048 let mut buf = Vec::new();
3049 let mut writer = Writer::new(&mut buf, 4);
3050 writer.write_define_font_info(&font_info).unwrap();
3051
3052 let mut reader = Reader::new(&buf, 4);
3053 let reread = reader.read_tag().unwrap();
3054
3055 assert_eq!(reread, Tag::DefineFontInfo(Box::new(font_info)));
3056 }
3057}