1#![warn(missing_docs)]
15
16extern crate byteorder;
17extern crate flate2;
18extern crate lzma;
19extern crate bit_range;
20
21mod decoded_swf;
22mod error;
23
24use std::fs::File;
25use std::path::Path;
26
27pub use decoded_swf::DecodedSwf;
28pub use error::Error;
29
30use byteorder::{LittleEndian, ReadBytesExt};
31use bit_range::BitRange;
32
33#[derive(Copy, Clone, PartialEq, Debug)]
42pub enum Signature {
43 Uncompressed,
45 ZlibCompressed,
47 LzmaCompressed
49}
50
51#[derive(Copy, Clone, PartialEq, Debug)]
54pub struct SwfHeaders {
55 signature: Signature,
56 version: u8,
57 file_length: u32,
58 width: u32,
59 height: u32,
60 frame_rate: u16,
61 frame_count: u16
62}
63
64impl SwfHeaders {
65 pub fn open<T: AsRef<Path>>(path: T) -> Result<(Self, DecodedSwf), Error> {
75 Self::read_from(try!(File::open(path)))
76 }
77
78 pub fn read_from(mut file: File) -> Result<(Self, DecodedSwf), Error> {
97 let sig = match try!(file.read_u8()) as char {
111 'F' => Signature::Uncompressed,
112 'C' => Signature::ZlibCompressed,
113 'Z' => Signature::LzmaCompressed,
114 _ => return Err(Error::NotSwf)
115 };
116
117 match (try!(file.read_u8()), try!(file.read_u8())) {
119 (0x57, 0x53) => {},
120 _ => return Err(Error::NotSwf)
121 }
122
123 let version = try!(file.read_u8());
125 let file_length = try!(file.read_u32::<LittleEndian>());
127
128 let mut decoded = try!(DecodedSwf::decompress(file, sig));
131
132 let (width, height) = try!(parse_rect(&mut decoded));
134
135 let frame_rate_lower = try!(decoded.read_u8());
138 let frame_rate_upper = try!(decoded.read_u8());
139 if frame_rate_lower != 0 {
140 panic!("swf_headers: Decimal points in frame rates not yet supported");
141 }
142 let frame_rate = frame_rate_upper as u16;
143
144 let frame_count = try!(decoded.read_u16::<LittleEndian>());
145
146 Ok((SwfHeaders {
147 signature: sig,
148 version: version,
149 file_length: file_length,
150 width: width,
151 height: height,
152 frame_rate: frame_rate,
153 frame_count: frame_count
154 }, decoded))
155 }
156 pub fn signature(&self) -> Signature {
158 self.signature
159 }
160 pub fn version(&self) -> u8 {
162 self.version
163 }
164 pub fn file_length(&self) -> u32 {
166 self.file_length
167 }
168 pub fn dimensions_twips(&self) -> (u32, u32) {
170 (self.width, self.height)
171 }
172 pub fn dimensions(&self) -> (u32, u32) {
174 (self.width / 20, self.height / 20)
175 }
176 pub fn frame_rate(&self) -> u16 {
178 self.frame_rate
179 }
180 pub fn frame_count(&self) -> u16 {
182 self.frame_count
183 }
184}
185
186fn parse_rect<T: ReadBytesExt>(file: &mut T) -> Result<(u32, u32), Error> {
187 let first_byte = try!(file.read_u8());
188 let nbits = ((first_byte >> 3) & 0b0001_1111) as u32;
189 let nbytes = (5 + nbits * 4) / 8; let mut bytes = Vec::new();
192 bytes.push(first_byte);
193
194 for _ in 0..nbytes {
195 bytes.push(try!(file.read_u8()));
196 }
197
198 let width = bytes.get_bit_range(5+nbits..5+nbits*2);
199 let height = bytes.get_bit_range(5+nbits*3..5+nbits*4);
200
201 Ok((width, height))
202}
203
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
212 fn test_245() {
213 let (headers, _) = SwfHeaders::open("tests/245.swf").unwrap();
214 assert_eq!(headers.signature(), Signature::ZlibCompressed);
215 assert_eq!(headers.version(), 9);
216 assert_eq!(headers.file_length(), 849486);
217 assert_eq!(headers.dimensions_twips(), (6000, 6000));
218 assert_eq!(headers.dimensions(), (300, 300));
219 assert_eq!(headers.frame_rate(), 30);
220 assert_eq!(headers.frame_count(), 1);
221 }
222
223 #[test]
224 fn test_902() {
225 let (headers, _) = SwfHeaders::open("tests/902.swf").unwrap();
226 assert_eq!(headers.signature(), Signature::ZlibCompressed);
227 assert_eq!(headers.version(), 9);
228 assert_eq!(headers.file_length(), 2032206);
229 assert_eq!(headers.dimensions_twips(), (6000, 6000));
230 assert_eq!(headers.dimensions(), (300, 300));
231 assert_eq!(headers.frame_rate(), 30);
232 assert_eq!(headers.frame_count(), 1);
233 }
234
235 #[test]
236 fn test_submachine_1() {
237 let (headers, _) = SwfHeaders::open("tests/submachine_1.swf").unwrap();
238 assert_eq!(headers.signature(), Signature::ZlibCompressed);
239 assert_eq!(headers.version(), 9);
240 assert_eq!(headers.file_length(), 1781964);
241 assert_eq!(headers.dimensions_twips(), (8000, 8500));
242 assert_eq!(headers.dimensions(), (400, 425));
243 assert_eq!(headers.frame_rate(), 25);
244 assert_eq!(headers.frame_count(), 29);
245 }
246
247 #[test]
248 fn test_colourshift() {
249 let (headers, _) = SwfHeaders::open("tests/colourshift.swf").unwrap();
250 assert_eq!(headers.signature(), Signature::ZlibCompressed);
251 assert_eq!(headers.version(), 9);
252 assert_eq!(headers.file_length(), 189029);
253 assert_eq!(headers.dimensions_twips(), (12800, 9600));
254 assert_eq!(headers.dimensions(), (640, 480));
255 assert_eq!(headers.frame_rate(), 30);
256 assert_eq!(headers.frame_count(), 1);
257 }
258}