ruffle/core/src/avm2/bytearray.rs

333 lines
11 KiB
Rust
Raw Normal View History

2021-03-05 23:01:02 +00:00
use crate::avm2::Error;
use flate2::read::*;
use flate2::Compression;
use gc_arena::Collect;
use std::cmp;
use std::convert::{TryFrom, TryInto};
use std::io;
use std::io::prelude::*;
#[derive(Clone, Collect, Debug)]
#[collect(no_drop)]
pub enum Endian {
Big,
Little,
}
#[derive(Clone, Collect, Debug)]
#[collect(no_drop)]
pub struct ByteArrayStorage {
/// Underlying ByteArray
bytes: Vec<u8>,
// The current position to read/write from
position: usize,
/// This represents what endian to use while reading data.
endian: Endian,
}
impl ByteArrayStorage {
/// Create a new ByteArrayStorage
pub fn new() -> ByteArrayStorage {
ByteArrayStorage {
bytes: Vec::new(),
position: 0,
endian: Endian::Big,
}
}
/// Write a byte at next position in the bytearray
pub fn write_byte(&mut self, byte: u8) {
let bytes_len = self.bytes.len();
// Allocate space for the byte
self.position += 1;
if self.position > bytes_len {
self.bytes.resize(self.position, 0);
}
self.bytes[self.position - 1] = byte;
}
/// Write bytes at next position in bytearray (This function is similar to whats in std::io::Cursor)
pub fn write_bytes(&mut self, buf: &[u8]) {
// Make sure the internal buffer is as least as big as where we
// currently are
let len = self.bytes.len();
if len < self.position {
// use `resize` so that the zero filling is as efficient as possible
self.bytes.resize(self.position, 0);
}
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let space = self.bytes.len() - self.position;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
self.bytes[self.position..self.position + left.len()].copy_from_slice(left);
self.bytes.extend_from_slice(right);
}
// Bump us forward
self.position += buf.len();
}
// Write bytes at an offset, ignoring the current position
pub fn write_bytes_at(&mut self, buf: &[u8], offset: usize) {
// Make sure the internal buffer is as least as big as where we
// currently are
let len = self.bytes.len();
if len < offset {
// use `resize` so that the zero filling is as efficient as possible
self.bytes.resize(offset, 0);
}
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let space = self.bytes.len() - offset;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
self.bytes[offset..offset + left.len()].copy_from_slice(left);
self.bytes.extend_from_slice(right);
}
}
pub fn clear(&mut self) {
self.bytes.clear();
// According to docs, this is where the bytearray should free resources
self.bytes.shrink_to_fit();
self.position = 0;
}
// Returns the bytearray compressed with zlib
pub fn zlib_compress(&mut self) -> io::Result<Vec<u8>> {
let mut buffer = Vec::new();
let mut compresser = ZlibEncoder::new(&*self.bytes, Compression::fast());
compresser.read_to_end(&mut buffer)?;
Ok(buffer)
}
// Returns the bytearray compressed with deflate
pub fn deflate_compress(&mut self) -> io::Result<Vec<u8>> {
let mut buffer = Vec::new();
let mut compresser = DeflateEncoder::new(&*self.bytes, Compression::fast());
compresser.read_to_end(&mut buffer)?;
Ok(buffer)
}
// Returns the bytearray decompressed with zlib
pub fn zlib_decompress(&mut self) -> io::Result<Vec<u8>> {
let mut buffer = Vec::new();
let mut compresser = ZlibDecoder::new(&*self.bytes);
compresser.read_to_end(&mut buffer)?;
Ok(buffer)
}
// Returns the bytearray decompressed with deflate
pub fn deflate_decompress(&mut self) -> io::Result<Vec<u8>> {
let mut buffer = Vec::new();
let mut compresser = DeflateDecoder::new(&*self.bytes);
compresser.read_to_end(&mut buffer)?;
Ok(buffer)
}
/// Set a new length for the bytearray
pub fn set_length(&mut self, new_len: usize) {
self.bytes.resize(new_len, 0);
}
// Reads exactly an amount of data
pub fn read_exact(&mut self, amnt: usize) -> Result<&[u8], Error> {
if self.position + amnt > self.bytes.len() {
return Err("EOFError: Reached EOF".into());
}
let val = Ok(&self.bytes[self.position..self.position + amnt]);
self.position += amnt;
val
}
pub fn read_utf(&mut self) -> Result<String, Error> {
let len = self.read_unsigned_short()?;
let val = String::from_utf8_lossy(self.read_exact(len as usize)?);
Ok(val.into_owned())
}
// Reads a i16 from the buffer
pub fn read_short(&mut self) -> Result<i16, Error> {
Ok(match self.endian {
Endian::Big => i16::from_be_bytes(self.read_exact(2)?.try_into().unwrap()),
Endian::Little => i16::from_le_bytes(self.read_exact(2)?.try_into().unwrap()),
})
}
// Reads a u16 from the buffer
pub fn read_unsigned_short(&mut self) -> Result<u16, Error> {
Ok(match self.endian {
Endian::Big => u16::from_be_bytes(self.read_exact(2)?.try_into().unwrap()),
Endian::Little => u16::from_le_bytes(self.read_exact(2)?.try_into().unwrap()),
})
}
// Reads a f64 from the buffer
pub fn read_double(&mut self) -> Result<f64, Error> {
Ok(match self.endian {
Endian::Big => f64::from_be_bytes(self.read_exact(8)?.try_into().unwrap()),
Endian::Little => f64::from_le_bytes(self.read_exact(8)?.try_into().unwrap()),
})
}
// Reads a f32 from the buffer
pub fn read_float(&mut self) -> Result<f32, Error> {
Ok(match self.endian {
Endian::Big => f32::from_be_bytes(self.read_exact(4)?.try_into().unwrap()),
Endian::Little => f32::from_le_bytes(self.read_exact(4)?.try_into().unwrap()),
})
}
// Reads a i32 from the buffer
pub fn read_int(&mut self) -> Result<i32, Error> {
Ok(match self.endian {
Endian::Big => i32::from_be_bytes(self.read_exact(4)?.try_into().unwrap()),
Endian::Little => i32::from_le_bytes(self.read_exact(4)?.try_into().unwrap()),
})
}
// Reads a u32 from the buffer
pub fn read_unsigned_int(&mut self) -> Result<u32, Error> {
Ok(match self.endian {
Endian::Big => u32::from_be_bytes(self.read_exact(4)?.try_into().unwrap()),
Endian::Little => u32::from_le_bytes(self.read_exact(4)?.try_into().unwrap()),
})
}
// Reads byte from buffer, returns false if zero, otherwise true
pub fn read_boolean(&mut self) -> Result<bool, Error> {
Ok(*self.read_exact(1)?.first().unwrap() != 0)
}
// Reads a i8 from the buffer
pub fn read_byte(&mut self) -> Result<i8, Error> {
Ok(match self.endian {
Endian::Big => i8::from_be_bytes(self.read_exact(1)?.try_into().unwrap()),
Endian::Little => i8::from_le_bytes(self.read_exact(1)?.try_into().unwrap()),
})
}
// Reads a u8 from the buffer
pub fn read_unsigned_byte(&mut self) -> Result<u8, Error> {
Ok(match self.endian {
Endian::Big => u8::from_be_bytes(self.read_exact(1)?.try_into().unwrap()),
Endian::Little => u8::from_le_bytes(self.read_exact(1)?.try_into().unwrap()),
})
}
// Writes a f32 to the buffer
pub fn write_float(&mut self, val: f32) {
let float_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&float_bytes);
}
// Writes a f64 to the buffer
pub fn write_double(&mut self, val: f64) {
let double_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&double_bytes);
}
// Writes a 1 byte to the buffer, either 1 or 0
pub fn write_boolean(&mut self, val: bool) {
self.write_bytes(&[val as u8; 1]);
}
// Writes a i32 to the buffer
pub fn write_int(&mut self, val: i32) {
let int_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&int_bytes);
}
// Writes a u32 to the buffer
pub fn write_unsigned_int(&mut self, val: u32) {
let uint_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&uint_bytes);
}
// Writes a i16 to the buffer
pub fn write_short(&mut self, val: i16) {
let short_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&short_bytes);
}
// Writes a u16 to the buffer
pub fn write_unsigned_short(&mut self, val: u16) {
let ushort_bytes = match self.endian {
Endian::Big => val.to_be_bytes(),
Endian::Little => val.to_le_bytes(),
};
self.write_bytes(&ushort_bytes);
}
// Writes a UTF String into the buffer, with its length as a prefix
pub fn write_utf(&mut self, utf_string: &str) -> Result<(), Error> {
if let Ok(str_size) = u16::try_from(utf_string.len()) {
self.write_unsigned_short(str_size);
self.write_bytes(utf_string.as_bytes());
} else {
return Err("RangeError: UTF String length must fit into a short".into());
}
Ok(())
}
pub fn get(&self, item: usize) -> Option<u8> {
self.bytes.get(item).copied()
}
pub fn set(&mut self, item: usize, value: u8) {
if self.bytes.len() < (item + 1) {
self.bytes.resize(item + 1, 0)
}
*self.bytes.get_mut(item).unwrap() = value;
}
pub fn delete(&mut self, item: usize) {
if let Some(i) = self.bytes.get_mut(item) {
*i = 0;
}
}
pub fn bytes(&self) -> &Vec<u8> {
&self.bytes
}
pub fn position(&self) -> usize {
self.position
}
pub fn set_position(&mut self, pos: usize) {
self.position = pos;
}
pub fn add_position(&mut self, amnt: usize) {
self.position += amnt;
}
pub fn endian(&self) -> &Endian {
&self.endian
}
pub fn set_endian(&mut self, new_endian: Endian) {
self.endian = new_endian;
}
}