181 lines
6.0 KiB
Rust
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(())
|
|
}
|