Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
309 lines
6.7 KiB
C++
309 lines
6.7 KiB
C++
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
#include "avmplus.h"
|
|
|
|
namespace avmplus
|
|
{
|
|
//
|
|
// DataIOBase
|
|
//
|
|
|
|
void DataIOBase::ThrowEOFError()
|
|
{
|
|
toplevel()->throwEOFError(kEOFError);
|
|
}
|
|
|
|
void DataIOBase::ThrowMemoryError()
|
|
{
|
|
toplevel()->throwMemoryError(kOutOfMemoryError);
|
|
}
|
|
|
|
void DataIOBase::ThrowRangeError()
|
|
{
|
|
toplevel()->throwRangeError(kParamRangeError);
|
|
}
|
|
|
|
//
|
|
// DataInput
|
|
//
|
|
|
|
bool DataInput::ReadBoolean()
|
|
{
|
|
uint8_t value;
|
|
Read(&value, 1);
|
|
return value != 0;
|
|
}
|
|
|
|
uint8_t DataInput::ReadU8()
|
|
{
|
|
uint8_t value;
|
|
Read(&value, 1);
|
|
return value;
|
|
}
|
|
|
|
uint16_t DataInput::ReadU16()
|
|
{
|
|
union {
|
|
uint8_t b[2];
|
|
uint16_t u;
|
|
};
|
|
Read(b, 2);
|
|
ConvertU16(u);
|
|
return u;
|
|
}
|
|
|
|
uint32_t DataInput::ReadU32()
|
|
{
|
|
union {
|
|
uint8_t b[4];
|
|
uint32_t u;
|
|
};
|
|
Read(b, 4);
|
|
ConvertU32(u);
|
|
return u;
|
|
}
|
|
|
|
float DataInput::ReadFloat()
|
|
{
|
|
union {
|
|
uint8_t b[4];
|
|
uint32_t u;
|
|
float f;
|
|
};
|
|
Read(b, 4);
|
|
ConvertU32(u);
|
|
return f;
|
|
}
|
|
|
|
float4_t DataInput::ReadFloat4()
|
|
{
|
|
float4_t f4;
|
|
float* b = reinterpret_cast<float*>(&f4);
|
|
|
|
for(int i=0; i < 4; i++)
|
|
b[i] = ReadFloat();
|
|
|
|
return f4;
|
|
}
|
|
|
|
double DataInput::ReadDouble()
|
|
{
|
|
union {
|
|
uint8_t b[8];
|
|
uint64_t u;
|
|
double d;
|
|
};
|
|
Read(b, 8);
|
|
ConvertD64(u);
|
|
return d;
|
|
}
|
|
|
|
String* DataInput::ReadMultiByte(uint32_t length, String* charset)
|
|
{
|
|
CheckEOF(length);
|
|
|
|
Toplevel* toplevel = this->toplevel();
|
|
uint32_t codepage = toplevel->charsetToCodepage(charset);
|
|
String* result = toplevel->readMultiByte(codepage, length, this);
|
|
return result;
|
|
}
|
|
|
|
String* DataInput::ReadUTFBytes(uint32_t length)
|
|
{
|
|
CheckEOF(length);
|
|
|
|
char *buffer = mmfx_new_array_opt( char, length+1, MMgc::kCanFail );
|
|
if (!buffer) {
|
|
ThrowMemoryError();
|
|
}
|
|
|
|
Read(buffer, length);
|
|
buffer[length] = 0;
|
|
|
|
// Since this is supposed to read UTF8 into a string, it really should ignore the UTF8 BOM that
|
|
// might reasonably occur at the head of the data.
|
|
char* utf8chars = buffer;
|
|
if (length >= 3 && (unsigned char)buffer[0] == 0xEF && (unsigned char)buffer[1] == 0xBB && (unsigned char)buffer[2] == 0xBF)
|
|
{
|
|
utf8chars += 3;
|
|
}
|
|
|
|
String* out = toplevel()->core()->newStringUTF8(utf8chars);
|
|
mmfx_delete_array( buffer );
|
|
|
|
return out;
|
|
}
|
|
|
|
String* DataInput::ReadUTF()
|
|
{
|
|
return ReadUTFBytes(ReadU16());
|
|
}
|
|
|
|
void DataInput::ReadByteArray(ByteArray& buffer,
|
|
uint32_t offset,
|
|
uint32_t count)
|
|
{
|
|
uint32_t available = Available();
|
|
|
|
if (count == 0) {
|
|
count = available;
|
|
}
|
|
|
|
if (count > available) {
|
|
ThrowEOFError();
|
|
}
|
|
|
|
// check for 32 bit overflow
|
|
uint64_t total = (uint64_t)offset + (uint64_t)count;
|
|
if (total != (uint64_t)(offset + count))
|
|
ThrowRangeError();
|
|
|
|
// Grow the buffer if necessary
|
|
if (offset + count >= buffer.GetLength()) {
|
|
buffer.SetLength(offset + count);
|
|
}
|
|
|
|
Read(buffer.GetWritableBuffer() + offset, count);
|
|
}
|
|
|
|
void DataInput::CheckEOF(uint32_t count)
|
|
{
|
|
if (Available() < count) {
|
|
ThrowEOFError();
|
|
}
|
|
}
|
|
|
|
Atom DataInput::ReadObject()
|
|
{
|
|
Toplevel* toplevel = this->toplevel();
|
|
return toplevel->readObject(GetObjectEncoding(), this);
|
|
}
|
|
|
|
//
|
|
// DataOutput
|
|
//
|
|
|
|
void DataOutput::WriteBoolean(bool value)
|
|
{
|
|
WriteU8(value ? 1 : 0);
|
|
}
|
|
|
|
void DataOutput::WriteU8(uint8_t value)
|
|
{
|
|
Write(&value, 1);
|
|
}
|
|
|
|
void DataOutput::WriteU16(uint16_t value)
|
|
{
|
|
union {
|
|
uint8_t b[2];
|
|
uint16_t u;
|
|
};
|
|
u = value;
|
|
ConvertU16(u);
|
|
Write(b, 2);
|
|
}
|
|
|
|
void DataOutput::WriteU32(uint32_t value)
|
|
{
|
|
union {
|
|
uint8_t b[4];
|
|
uint32_t u;
|
|
};
|
|
u = value;
|
|
ConvertU32(u);
|
|
Write(b, 4);
|
|
}
|
|
|
|
void DataOutput::WriteFloat(float value)
|
|
{
|
|
union {
|
|
uint8_t b[4];
|
|
uint32_t u;
|
|
float f;
|
|
};
|
|
f = value;
|
|
ConvertU32(u);
|
|
Write(b, 4);
|
|
}
|
|
|
|
void DataOutput::WriteFloat4(float4_t value)
|
|
{
|
|
float* pval = reinterpret_cast<float*>(&value);
|
|
for(int i=0;i<4;i++)
|
|
{
|
|
WriteFloat(pval[i]);
|
|
}
|
|
}
|
|
|
|
void DataOutput::WriteDouble(double value)
|
|
{
|
|
union {
|
|
uint8_t b[8];
|
|
uint64_t u;
|
|
double d;
|
|
};
|
|
d = value;
|
|
ConvertD64(u);
|
|
Write(b, 8);
|
|
}
|
|
|
|
void DataOutput::WriteMultiByte(String* str, String* charset)
|
|
{
|
|
Toplevel* toplevel = this->toplevel();
|
|
uint32_t codepage = toplevel->charsetToCodepage(charset);
|
|
toplevel->writeMultiByte(codepage, str, this);
|
|
}
|
|
|
|
void DataOutput::WriteUTF(String *str)
|
|
{
|
|
StUTF8String utf8(str);
|
|
uint32_t length = utf8.length();
|
|
if (length > 65535) {
|
|
ThrowRangeError();
|
|
}
|
|
WriteU16((uint16_t)length);
|
|
Write(utf8.c_str(), length*sizeof(char));
|
|
}
|
|
|
|
void DataOutput::WriteUTFBytes(String *str)
|
|
{
|
|
StUTF8String utf8(str);
|
|
int len = utf8.length();
|
|
Write(utf8.c_str(), len*sizeof(char));
|
|
}
|
|
|
|
void DataOutput::WriteByteArray(ByteArray& buffer,
|
|
uint32_t offset,
|
|
uint32_t count)
|
|
{
|
|
if (offset > buffer.GetLength())
|
|
offset = buffer.GetLength();
|
|
|
|
if (count == 0) {
|
|
count = buffer.GetLength()-offset;
|
|
}
|
|
|
|
if (count > buffer.GetLength()-offset) {
|
|
ThrowRangeError();
|
|
}
|
|
|
|
if (count > 0) {
|
|
Write(buffer.GetReadableBuffer()+offset, count);
|
|
}
|
|
}
|
|
|
|
void DataOutput::WriteObject(Atom atom)
|
|
{
|
|
Toplevel* toplevel = this->toplevel();
|
|
toplevel->writeObject(GetObjectEncoding(), this, atom);
|
|
}
|
|
}
|
|
|
|
|