ruffle/scanner/src/execute.rs

181 lines
6.0 KiB
Rust

//! Child/executor process impls
use crate::cli_options::ExecuteReportOpt;
use crate::file_results::{AvmType, FileResults, Step};
use crate::logging::{ScanLogBackend, ThreadLocalScanLogger, LOCAL_LOGGER};
use ruffle_core::backend::navigator::{NullExecutor, NullNavigatorBackend};
use ruffle_core::limits::ExecutionLimit;
use ruffle_core::swf::{decompress_swf, parse_swf};
use ruffle_core::tag_utils::SwfMovie;
use ruffle_core::PlayerBuilder;
use sha2::{Digest, Sha256};
use std::io::{stdout, Write};
use std::panic::catch_unwind;
use std::path::Path;
use std::time::{Duration, Instant};
fn execute_swf(file: &Path) {
let base_path = file.parent().unwrap();
let executor = NullExecutor::new();
let movie = SwfMovie::from_path(file, None).unwrap();
let frame_time = 1000.0 / movie.frame_rate().to_f64();
let player = PlayerBuilder::new()
.with_log(ScanLogBackend::new())
.with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor).unwrap())
.with_max_execution_duration(Duration::from_secs(300))
.with_movie(movie)
.build();
player.lock().unwrap().preload(&mut ExecutionLimit::none());
player.lock().unwrap().run_frame();
player.lock().unwrap().update_timers(frame_time);
//executor.poll_all().unwrap();
}
fn checkpoint<W: Write>(
file_result: &mut FileResults,
start: &Instant,
writer: &mut csv::Writer<W>,
) -> Result<(), std::io::Error> {
let has_error = file_result.error.is_some();
file_result.testing_time = start.elapsed().as_millis();
writer.serialize(file_result).unwrap();
if has_error {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Error encountered, test terminated",
))
} else {
Ok(())
}
}
pub fn execute_report_main(execute_report_opt: ExecuteReportOpt) -> Result<(), std::io::Error> {
ThreadLocalScanLogger::init();
let start = Instant::now();
let file_path = execute_report_opt.input_path;
let name = file_path
.file_name()
.expect("Valid file name in input path")
.to_string_lossy()
.into_owned();
LOCAL_LOGGER.with(|log_buffer| {
log_buffer.borrow_mut().truncate(0);
});
let mut file_result = FileResults::new(&name);
let stdout = stdout();
let mut writer = csv::Writer::from_writer(stdout.lock());
checkpoint(&mut file_result, &start, &mut writer)?;
file_result.progress = Step::Read;
let data = match std::fs::read(&file_path) {
Ok(data) => data,
Err(e) => {
file_result.error = Some(format!("File error: {e}"));
checkpoint(&mut file_result, &start, &mut writer)?;
return Ok(());
}
};
file_result.compressed_len = Some(data.len());
let mut hash = Sha256::new();
hash.update(&data[..]);
file_result.hash = hash.finalize().to_vec();
checkpoint(&mut file_result, &start, &mut writer)?;
file_result.progress = Step::Decompress;
let swf_buf = match decompress_swf(&data[..]) {
Ok(swf_buf) => swf_buf,
Err(e) => {
file_result.error = Some(e.to_string());
checkpoint(&mut file_result, &start, &mut writer)?;
return Ok(());
}
};
checkpoint(&mut file_result, &start, &mut writer)?;
file_result.progress = Step::Parse;
match catch_unwind(|| parse_swf(&swf_buf)) {
Ok(swf) => match swf {
Ok(swf) => {
let stage_width = swf.header.stage_size().width().to_pixels();
let stage_height = swf.header.stage_size().height().to_pixels();
file_result.uncompressed_len = Some(swf.header.uncompressed_len());
file_result.compression = Some(swf.header.compression().into());
file_result.version = Some(swf.header.version());
file_result.stage_size = Some(format!("{stage_width}x{stage_height}"));
file_result.frame_rate = Some(swf.header.frame_rate().into());
file_result.num_frames = Some(swf.header.num_frames());
file_result.use_direct_blit = Some(swf.header.use_direct_blit());
file_result.use_gpu = Some(swf.header.use_gpu());
file_result.use_network_sandbox = Some(swf.header.use_network_sandbox());
file_result.vm_type = Some(match swf.header.is_action_script_3() {
true => AvmType::Avm2,
false => AvmType::Avm1,
});
}
Err(e) => {
file_result.error = Some(format!("Parse error: {e}"));
checkpoint(&mut file_result, &start, &mut writer)?;
}
},
Err(e) => match e.downcast::<String>() {
Ok(e) => {
file_result.error = Some(format!("PANIC: {e}"));
checkpoint(&mut file_result, &start, &mut writer)?;
}
Err(_) => {
file_result.error = Some("PANIC".to_string());
checkpoint(&mut file_result, &start, &mut writer)?;
}
},
};
checkpoint(&mut file_result, &start, &mut writer)?;
file_result.progress = Step::Execute;
//Run one frame of the movie in Ruffle.
if let Err(e) = catch_unwind(|| execute_swf(&file_path)) {
match e.downcast::<String>() {
Ok(e) => {
file_result.error = Some(format!("PANIC: {e}"));
checkpoint(&mut file_result, &start, &mut writer)?;
}
Err(_) => {
file_result.error = Some("PANIC".to_string());
checkpoint(&mut file_result, &start, &mut writer)?;
}
}
}
let errors = LOCAL_LOGGER.with(|log_buffer| {
log_buffer.borrow_mut().dedup();
log_buffer.borrow_mut().join("\n")
});
if !errors.is_empty() {
file_result.error = Some(errors);
} else {
file_result.progress = Step::Complete;
}
checkpoint(&mut file_result, &start, &mut writer)?;
Ok(())
}