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>> {
let val = self.context.avm1.pop();
if val.as_bool(self.current_swf_version()) {
self.seek(jump_offset, reader, data)?;
reader.seek(data.as_ref(), jump_offset);
}
Ok(FrameControl::Continue)
}
@ -1543,7 +1543,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
reader: &mut Reader<'b>,
data: &'b SwfSlice,
) -> Result<FrameControl<'gc>, Error<'gc>> {
self.seek(jump_offset, reader, data)?;
reader.seek(data.as_ref(), jump_offset);
Ok(FrameControl::Continue)
}
@ -3008,18 +3008,4 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
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 gc_arena::{Gc, GcCell, MutationContext};
use smallvec::SmallVec;
use std::io::Cursor;
use swf::avm2::read::Reader;
use swf::avm2::types::{
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
.body()
.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 {
let result = self.do_next_opcode(method, &mut read);
let result = self.do_next_opcode(method, &mut reader, &body.code);
match result {
Ok(FrameControl::Return(value)) => break Ok(value),
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.
fn do_next_opcode(
fn do_next_opcode<'b>(
&mut self,
method: Gc<'gc, BytecodeMethod<'gc>>,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
if self.context.update_start.elapsed() >= self.context.max_execution_duration {
return Err(
@ -635,21 +636,21 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Op::SubtractI => self.op_subtract_i(),
Op::Swap => self.op_swap(),
Op::URShift => self.op_urshift(),
Op::Jump { offset } => self.op_jump(offset, reader),
Op::IfTrue { offset } => self.op_if_true(offset, reader),
Op::IfFalse { offset } => self.op_if_false(offset, reader),
Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader),
Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader),
Op::IfEq { offset } => self.op_if_eq(offset, reader),
Op::IfNe { offset } => self.op_if_ne(offset, reader),
Op::IfGe { offset } => self.op_if_ge(offset, reader),
Op::IfGt { offset } => self.op_if_gt(offset, reader),
Op::IfLe { offset } => self.op_if_le(offset, reader),
Op::IfLt { offset } => self.op_if_lt(offset, reader),
Op::IfNge { offset } => self.op_if_nge(offset, reader),
Op::IfNgt { offset } => self.op_if_ngt(offset, reader),
Op::IfNle { offset } => self.op_if_nle(offset, reader),
Op::IfNlt { offset } => self.op_if_nlt(offset, reader),
Op::Jump { offset } => self.op_jump(offset, reader, full_data),
Op::IfTrue { offset } => self.op_if_true(offset, reader, full_data),
Op::IfFalse { offset } => self.op_if_false(offset, reader, full_data),
Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader, full_data),
Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader, full_data),
Op::IfEq { offset } => self.op_if_eq(offset, reader, full_data),
Op::IfNe { offset } => self.op_if_ne(offset, reader, full_data),
Op::IfGe { offset } => self.op_if_ge(offset, reader, full_data),
Op::IfGt { offset } => self.op_if_gt(offset, reader, full_data),
Op::IfLe { offset } => self.op_if_le(offset, reader, full_data),
Op::IfLt { offset } => self.op_if_lt(offset, reader, full_data),
Op::IfNge { offset } => self.op_if_nge(offset, reader, full_data),
Op::IfNgt { offset } => self.op_if_ngt(offset, reader, full_data),
Op::IfNle { offset } => self.op_if_nle(offset, reader, full_data),
Op::IfNlt { offset } => self.op_if_nlt(offset, reader, full_data),
Op::StrictEquals => self.op_strict_equals(),
Op::Equals => self.op_equals(),
Op::GreaterEquals => self.op_greater_equals(),
@ -1834,219 +1835,234 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Ok(FrameControl::Continue)
}
fn op_jump(
fn op_jump<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
Ok(FrameControl::Continue)
}
fn op_if_true(
fn op_if_true<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().coerce_to_boolean();
if value {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_false(
fn op_if_false<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().coerce_to_boolean();
if !value {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_strict_eq(
fn op_if_strict_eq<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1 == value2 {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_strict_ne(
fn op_if_strict_ne<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1 != value2 {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_eq(
fn op_if_eq<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1.abstract_eq(&value2, self)? {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_ne(
fn op_if_ne<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if !value1.abstract_eq(&value2, self)? {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_ge(
fn op_if_ge<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)? == Some(false) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_gt(
fn op_if_gt<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)? == Some(true) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_le(
fn op_if_le<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)? == Some(false) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_lt(
fn op_if_lt<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)? == Some(true) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_nge(
fn op_if_nge<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value1.abstract_lt(&value2, self)?.unwrap_or(true) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_ngt(
fn op_if_ngt<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if !value2.abstract_lt(&value1, self)?.unwrap_or(false) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_nle(
fn op_if_nle<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if value2.abstract_lt(&value1, self)?.unwrap_or(true) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
Ok(FrameControl::Continue)
}
fn op_if_nlt(
fn op_if_nlt<'b>(
&mut self,
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
reader: &mut Reader<'b>,
full_data: &'b [u8],
) -> Result<FrameControl<'gc>, Error> {
let value2 = self.context.avm2.pop();
let value1 = self.context.avm2.pop();
if !value1.abstract_lt(&value2, self)?.unwrap_or(false) {
reader.seek(offset as i64)?;
reader.seek(full_data, offset);
}
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]
pub fn encoding(&self) -> &'static Encoding {
SwfStr::encoding_for_version(self.version)

View File

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