swf: Make avm2 Reader operate directly with byte slices

This commit is contained in:
Mads Marquart 2021-02-10 22:56:17 +01:00 committed by Mike Welsh
parent 73b251d6ec
commit dad21d4398
4 changed files with 103 additions and 96 deletions

View File

@ -1460,7 +1460,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let val = self.context.avm1.pop(); let val = self.context.avm1.pop();
if val.as_bool(self.current_swf_version()) { if val.as_bool(self.current_swf_version()) {
self.seek(jump_offset, reader, data)?; reader.seek(data.as_ref(), jump_offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
@ -1543,7 +1543,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
reader: &mut Reader<'b>, reader: &mut Reader<'b>,
data: &'b SwfSlice, data: &'b SwfSlice,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
self.seek(jump_offset, reader, data)?; reader.seek(data.as_ref(), jump_offset);
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
@ -3008,18 +3008,4 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
} }
fn seek<'b>(
&self,
jump_offset: i16,
reader: &mut Reader<'b>,
data: &'b SwfSlice,
) -> Result<(), Error<'gc>> {
let slice = data.movie.data();
let mut pos = reader.get_ref().as_ptr() as usize - slice.as_ptr() as usize;
pos = (pos as isize + isize::from(jump_offset)) as usize;
pos = pos.min(slice.len());
*reader.get_mut() = &slice[pos as usize..];
Ok(())
}
} }

View File

@ -15,7 +15,6 @@ use crate::avm2::{value, Avm2, Error};
use crate::context::UpdateContext; use crate::context::UpdateContext;
use gc_arena::{Gc, GcCell, MutationContext}; use gc_arena::{Gc, GcCell, MutationContext};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::io::Cursor;
use swf::avm2::read::Reader; use swf::avm2::read::Reader;
use swf::avm2::types::{ use swf::avm2::types::{
Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname, Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname,
@ -507,10 +506,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
let body: Result<_, Error> = method let body: Result<_, Error> = method
.body() .body()
.ok_or_else(|| "Cannot execute non-native method without body".into()); .ok_or_else(|| "Cannot execute non-native method without body".into());
let mut read = Reader::new(Cursor::new(body?.code.as_ref())); let body = body?;
let mut reader = Reader::new(&body.code);
loop { loop {
let result = self.do_next_opcode(method, &mut read); let result = self.do_next_opcode(method, &mut reader, &body.code);
match result { match result {
Ok(FrameControl::Return(value)) => break Ok(value), Ok(FrameControl::Return(value)) => break Ok(value),
Ok(FrameControl::Continue) => {} Ok(FrameControl::Continue) => {}
@ -520,10 +520,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} }
/// Run a single action from a given action reader. /// Run a single action from a given action reader.
fn do_next_opcode( fn do_next_opcode<'b>(
&mut self, &mut self,
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
if self.context.update_start.elapsed() >= self.context.max_execution_duration { if self.context.update_start.elapsed() >= self.context.max_execution_duration {
return Err( return Err(
@ -635,21 +636,21 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Op::SubtractI => self.op_subtract_i(), Op::SubtractI => self.op_subtract_i(),
Op::Swap => self.op_swap(), Op::Swap => self.op_swap(),
Op::URShift => self.op_urshift(), Op::URShift => self.op_urshift(),
Op::Jump { offset } => self.op_jump(offset, reader), Op::Jump { offset } => self.op_jump(offset, reader, full_data),
Op::IfTrue { offset } => self.op_if_true(offset, reader), Op::IfTrue { offset } => self.op_if_true(offset, reader, full_data),
Op::IfFalse { offset } => self.op_if_false(offset, reader), Op::IfFalse { offset } => self.op_if_false(offset, reader, full_data),
Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader), Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader, full_data),
Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader), Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader, full_data),
Op::IfEq { offset } => self.op_if_eq(offset, reader), Op::IfEq { offset } => self.op_if_eq(offset, reader, full_data),
Op::IfNe { offset } => self.op_if_ne(offset, reader), Op::IfNe { offset } => self.op_if_ne(offset, reader, full_data),
Op::IfGe { offset } => self.op_if_ge(offset, reader), Op::IfGe { offset } => self.op_if_ge(offset, reader, full_data),
Op::IfGt { offset } => self.op_if_gt(offset, reader), Op::IfGt { offset } => self.op_if_gt(offset, reader, full_data),
Op::IfLe { offset } => self.op_if_le(offset, reader), Op::IfLe { offset } => self.op_if_le(offset, reader, full_data),
Op::IfLt { offset } => self.op_if_lt(offset, reader), Op::IfLt { offset } => self.op_if_lt(offset, reader, full_data),
Op::IfNge { offset } => self.op_if_nge(offset, reader), Op::IfNge { offset } => self.op_if_nge(offset, reader, full_data),
Op::IfNgt { offset } => self.op_if_ngt(offset, reader), Op::IfNgt { offset } => self.op_if_ngt(offset, reader, full_data),
Op::IfNle { offset } => self.op_if_nle(offset, reader), Op::IfNle { offset } => self.op_if_nle(offset, reader, full_data),
Op::IfNlt { offset } => self.op_if_nlt(offset, reader), Op::IfNlt { offset } => self.op_if_nlt(offset, reader, full_data),
Op::StrictEquals => self.op_strict_equals(), Op::StrictEquals => self.op_strict_equals(),
Op::Equals => self.op_equals(), Op::Equals => self.op_equals(),
Op::GreaterEquals => self.op_greater_equals(), Op::GreaterEquals => self.op_greater_equals(),
@ -1834,219 +1835,234 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_jump( fn op_jump<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_true( fn op_if_true<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().coerce_to_boolean(); let value = self.context.avm2.pop().coerce_to_boolean();
if value { if value {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_false( fn op_if_false<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().coerce_to_boolean(); let value = self.context.avm2.pop().coerce_to_boolean();
if !value { if !value {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_strict_eq( fn op_if_strict_eq<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1 == value2 { if value1 == value2 {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_strict_ne( fn op_if_strict_ne<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1 != value2 { if value1 != value2 {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_eq( fn op_if_eq<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1.abstract_eq(&value2, self)? { if value1.abstract_eq(&value2, self)? {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_ne( fn op_if_ne<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if !value1.abstract_eq(&value2, self)? { if !value1.abstract_eq(&value2, self)? {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_ge( fn op_if_ge<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)? == Some(false) { if value1.abstract_lt(&value2, self)? == Some(false) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_gt( fn op_if_gt<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)? == Some(true) { if value2.abstract_lt(&value1, self)? == Some(true) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_le( fn op_if_le<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)? == Some(false) { if value2.abstract_lt(&value1, self)? == Some(false) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_lt( fn op_if_lt<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)? == Some(true) { if value1.abstract_lt(&value2, self)? == Some(true) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_nge( fn op_if_nge<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)?.unwrap_or(true) { if value1.abstract_lt(&value2, self)?.unwrap_or(true) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_ngt( fn op_if_ngt<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if !value2.abstract_lt(&value1, self)?.unwrap_or(false) { if !value2.abstract_lt(&value1, self)?.unwrap_or(false) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_nle( fn op_if_nle<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)?.unwrap_or(true) { if value2.abstract_lt(&value1, self)?.unwrap_or(true) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_if_nlt( fn op_if_nlt<'b>(
&mut self, &mut self,
offset: i32, offset: i32,
reader: &mut Reader<Cursor<&[u8]>>, reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop(); let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop(); let value1 = self.context.avm2.pop();
if !value1.abstract_lt(&value2, self)?.unwrap_or(false) { if !value1.abstract_lt(&value2, self)?.unwrap_or(false) {
reader.seek(offset as i64)?; reader.seek(full_data, offset);
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)

View File

@ -29,6 +29,13 @@ impl<'a> Reader<'a> {
} }
} }
pub fn seek(&mut self, data: &'a [u8], jump_offset: i16) {
let mut pos = self.input.as_ptr() as usize - data.as_ptr() as usize;
pos = (pos as isize + isize::from(jump_offset)) as usize;
pos = pos.min(data.len());
self.input = &data[pos as usize..];
}
#[inline] #[inline]
pub fn encoding(&self) -> &'static Encoding { pub fn encoding(&self) -> &'static Encoding {
SwfStr::encoding_for_version(self.version) SwfStr::encoding_for_version(self.version)

View File

@ -2,25 +2,23 @@ use crate::avm2::types::*;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::read::SwfReadExt; use crate::read::SwfReadExt;
use byteorder::{LittleEndian, ReadBytesExt}; use byteorder::{LittleEndian, ReadBytesExt};
use std::io::{self, Read, Seek, SeekFrom}; use std::io::{self, Read};
pub struct Reader<R: Read> { pub struct Reader<'a> {
input: R, input: &'a [u8],
}
impl<'a> Reader<'a> {
pub fn new(input: &'a [u8]) -> Self {
Self { input }
} }
impl<R> Reader<R>
where
R: Read + Seek,
{
#[inline] #[inline]
pub fn seek(&mut self, relative_offset: i64) -> std::io::Result<u64> { pub fn seek(&mut self, data: &'a [u8], relative_offset: i32) {
self.input.seek(SeekFrom::Current(relative_offset as i64)) let mut pos = self.input.as_ptr() as usize - data.as_ptr() as usize;
} pos = (pos as isize + relative_offset as isize) as usize;
} pos = pos.min(data.len());
self.input = &data[pos as usize..];
impl<R: Read> Reader<R> {
pub fn new(input: R) -> Reader<R> {
Reader { input }
} }
pub fn read(&mut self) -> Result<AbcFile> { pub fn read(&mut self) -> Result<AbcFile> {
@ -861,7 +859,7 @@ impl<R: Read> Reader<R> {
} }
} }
impl<'a, R: 'a + Read> SwfReadExt for Reader<R> { impl<'a> SwfReadExt for Reader<'a> {
#[inline] #[inline]
fn read_u8(&mut self) -> io::Result<u8> { fn read_u8(&mut self) -> io::Result<u8> {
self.input.read_u8() self.input.read_u8()