/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- BEGIN_NATIVE_MAP
- ThrowMemoryError
- Grow
- Push
- Push
- SetLength
- DataOutput
- Available
- SetLength
- Read
- Write
- m_byteArray
- getUintProperty
- setUintProperty
- getAtomProperty
- setAtomProperty
- hasAtomProperty
- setLength
- get_length
- set_length
- getFilePointer
- available
- seek
- _toString
- readByte
- readUnsignedByte
- readShort
- readUnsignedShort
- readInt
- readUnsignedInt
- readFloat
- readDouble
- readBoolean
- writeBoolean
- writeByte
- writeShort
- writeInt
- writeUnsignedInt
- writeFloat
- writeDouble
- zlib_compress
- zlib_uncompress
- checkNull
- writeBytes
- readBytes
- readUTF
- readUTFBytes
- writeUTF
- writeUTFBytes
- fill
- createInstance
- readFile
- get_endian
- set_endian
- writeFile
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "axtam.h"
namespace axtam {
class ByteArrayObject;
class ByteArray;
}
#include "DataIO.h"
#include "ByteArrayGlue.h"
#include "DomainClass.h"
//#include "genericzlib.h"
namespace axtam
{
BEGIN_NATIVE_MAP(ByteArrayClass)
NATIVE_METHOD(flash_utils_ByteArray_toString, ByteArrayObject::_toString)
NATIVE_METHOD(flash_utils_ByteArray_length_get, ByteArrayObject::get_length)
NATIVE_METHOD(flash_utils_ByteArray_length_set, ByteArrayObject::set_length)
NATIVE_METHOD(flash_utils_ByteArray_readBytes, ByteArrayObject::readBytes)
NATIVE_METHOD(flash_utils_ByteArray_writeBytes, ByteArrayObject::writeBytes)
NATIVE_METHOD(flash_utils_ByteArray_writeBoolean, ByteArrayObject::writeBoolean)
NATIVE_METHOD(flash_utils_ByteArray_writeByte, ByteArrayObject::writeByte)
NATIVE_METHOD(flash_utils_ByteArray_writeShort, ByteArrayObject::writeShort)
NATIVE_METHOD(flash_utils_ByteArray_writeInt, ByteArrayObject::writeInt)
NATIVE_METHOD(flash_utils_ByteArray_writeUnsignedInt, ByteArrayObject::writeUnsignedInt)
NATIVE_METHOD(flash_utils_ByteArray_writeFloat, ByteArrayObject::writeFloat)
NATIVE_METHOD(flash_utils_ByteArray_writeDouble, ByteArrayObject::writeDouble)
NATIVE_METHOD(flash_utils_ByteArray_writeUTF, ByteArrayObject::writeUTF)
NATIVE_METHOD(flash_utils_ByteArray_writeUTFBytes, ByteArrayObject::writeUTFBytes)
NATIVE_METHOD(flash_utils_ByteArray_readBoolean, ByteArrayObject::readBoolean)
NATIVE_METHOD(flash_utils_ByteArray_readByte, ByteArrayObject::readByte)
NATIVE_METHOD(flash_utils_ByteArray_readUnsignedByte, ByteArrayObject::readUnsignedByte)
NATIVE_METHOD(flash_utils_ByteArray_readShort, ByteArrayObject::readShort)
NATIVE_METHOD(flash_utils_ByteArray_readUnsignedShort, ByteArrayObject::readUnsignedShort)
NATIVE_METHOD(flash_utils_ByteArray_readInt, ByteArrayObject::readInt)
NATIVE_METHOD(flash_utils_ByteArray_readUnsignedInt, ByteArrayObject::readUnsignedInt)
NATIVE_METHOD(flash_utils_ByteArray_readFloat, ByteArrayObject::readFloat)
NATIVE_METHOD(flash_utils_ByteArray_readDouble, ByteArrayObject::readDouble)
NATIVE_METHOD(flash_utils_ByteArray_readUTF, ByteArrayObject::readUTF)
NATIVE_METHOD(flash_utils_ByteArray_readUTFBytes, ByteArrayObject::readUTFBytes)
NATIVE_METHOD(flash_utils_ByteArray_bytesAvailable_get, ByteArrayObject::available)
NATIVE_METHOD(flash_utils_ByteArray_position_get, ByteArrayObject::getFilePointer)
NATIVE_METHOD(flash_utils_ByteArray_position_set, ByteArrayObject::seek)
NATIVE_METHOD(flash_utils_ByteArray_compress, ByteArrayObject::zlib_compress)
NATIVE_METHOD(flash_utils_ByteArray_uncompress, ByteArrayObject::zlib_uncompress)
NATIVE_METHOD(flash_utils_ByteArray_endian_get, ByteArrayObject::get_endian)
NATIVE_METHOD(flash_utils_ByteArray_endian_set, ByteArrayObject::set_endian)
NATIVE_METHOD(flash_utils_ByteArray_writeFile, ByteArrayObject::writeFile)
NATIVE_METHOD(flash_utils_ByteArray_readFile, ByteArrayClass::readFile)
END_NATIVE_MAP()
//
// ByteArray
//
ByteArray::ByteArray()
{
m_capacity = 0;
m_length = 0;
m_array = NULL;
}
ByteArray::ByteArray(const ByteArray &lhs)
{
m_array = new U8[lhs.m_length];
if (!m_array)
{
ThrowMemoryError();
return;
}
m_capacity = lhs.m_length;
m_length = lhs.m_length;
memcpy(m_array, lhs.m_array, m_length);
}
ByteArray::~ByteArray()
{
if (m_array)
{
delete [] m_array;
m_array = NULL;
}
m_capacity = 0;
m_length = 0;
}
void ByteArray::ThrowMemoryError()
{
// todo throw out of memory exception
// m_toplevel->memoryError->throwError(kOutOfMemoryError);
}
bool ByteArray::Grow(uint32 minimumCapacity)
{
if (minimumCapacity > m_capacity)
{
uint32 newCapacity = m_capacity << 1;
if (newCapacity < minimumCapacity)
{
newCapacity = minimumCapacity;
}
if (newCapacity < kGrowthIncr)
{
newCapacity = kGrowthIncr;
}
U8 *newArray = new U8[newCapacity];
if (!newArray)
{
return false;
}
if (m_array)
{
memcpy(newArray, m_array, m_length);
delete [] m_array;
}
memset(newArray+m_length, 0, newCapacity-m_capacity);
m_array = newArray;
m_capacity = newCapacity;
}
return true;
}
U8 ByteArray::operator[] (uint32 index) const
{
if (m_length <= index)
{
return 0;
}
return m_array[index];
}
U8& ByteArray::operator[] (uint32 index)
{
if (m_length <= index)
{
Grow(index+1);
m_length = index+1;
}
return m_array[index];
}
void ByteArray::Push(U8 value)
{
if (m_length >= m_capacity)
{
Grow(m_length + 1);
}
m_array[m_length++] = value;
}
void ByteArray::Push(const U8 *data, uint32 count)
{
Grow(m_length + count);
memcpy(m_array + m_length, data, count);
m_length += count;
}
void ByteArray::SetLength(uint32 newLength)
{
if (newLength > m_capacity)
{
if (!Grow(newLength))
{
ThrowMemoryError();
return;
}
}
m_length = newLength;
}
//
// ByteArrayFile
//
ByteArrayFile::ByteArrayFile(Toplevel *toplevel)
: DataInput(toplevel),
DataOutput(toplevel)
{
m_filePointer = 0;
}
uint32 ByteArrayFile::Available()
{
if (m_filePointer <= m_length) {
return m_length - m_filePointer;
} else {
return 0;
}
}
void ByteArrayFile::SetLength(uint32 newLength)
{
ByteArray::SetLength(newLength);
if (m_filePointer > newLength) {
m_filePointer = newLength;
}
}
void ByteArrayFile::Read(void *buffer, uint32 count)
{
CheckEOF(count);
if (count > 0)
{
memcpy(buffer, m_array+m_filePointer, count);
m_filePointer += count;
}
}
void ByteArrayFile::Write(const void *buffer, uint32 count)
{
if (m_filePointer+count >= m_length) {
Grow(m_filePointer+count);
m_length = m_filePointer+count;
}
memcpy(m_array+m_filePointer, buffer, count);
m_filePointer += count;
}
//
// ByteArrayObject
//
ByteArrayObject::ByteArrayObject(VTable *ivtable,
ScriptObject *delegate)
: ScriptObject(ivtable, delegate),
m_byteArray(toplevel())
{
c.set(&m_byteArray, sizeof(ByteArrayFile));
}
Atom ByteArrayObject::getUintProperty(uint32 i) const
{
if (i < (uint32)m_byteArray.GetLength()) {
return core()->intToAtom(m_byteArray[i]);
} else {
return undefinedAtom;
}
}
void ByteArrayObject::setUintProperty(uint32 i, Atom value)
{
m_byteArray[i] = (U8)(core()->integer(value));
}
Atom ByteArrayObject::getAtomProperty(Atom name) const
{
AvmCore *core = this->core();
uint32 index;
if (core->getIndexFromAtom(name, &index)) {
if (index < (uint32) m_byteArray.GetLength()) {
return core->intToAtom(m_byteArray[index]);
} else {
return undefinedAtom;
}
}
return ScriptObject::getAtomProperty(name);
}
void ByteArrayObject::setAtomProperty(Atom name, Atom value)
{
AvmCore *core = this->core();
uint32 index;
if (core->getIndexFromAtom(name, &index)) {
int intValue = core->integer(value);
m_byteArray[index] = (U8)(intValue);
} else {
ScriptObject::setAtomProperty(name, value);
}
}
bool ByteArrayObject::hasAtomProperty(Atom name) const
{
return ScriptObject::hasAtomProperty(name) || getAtomProperty(name) != undefinedAtom;
}
void ByteArrayObject::setLength(uint32 newLength)
{
m_byteArray.SetLength(newLength);
}
uint32 ByteArrayObject::get_length()
{
return m_byteArray.GetLength();
}
void ByteArrayObject::set_length(uint32 value)
{
setLength(value);
}
int ByteArrayObject::getFilePointer()
{
return m_byteArray.GetFilePointer();
}
int ByteArrayObject::available()
{
return m_byteArray.Available();
}
void ByteArrayObject::seek(int offset)
{
if (offset >= 0) {
m_byteArray.Seek(offset);
}
}
String* ByteArrayObject::_toString()
{
unsigned char *c = (unsigned char*)m_byteArray.GetBuffer();
uint32 len = m_byteArray.GetLength();
if (len >= 3)
{
// UTF8 BOM
if ((c[0] == 0xef) && (c[1] == 0xbb) && (c[2] == 0xbf))
{
return core()->newString(((char *)c) + 3, len - 3);
}
else if ((c[0] == 0xfe) && (c[1] == 0xff))
{
//UTF-16 big endian
c += 2;
len = (len - 2) >> 1;
Stringp out = new (core()->GetGC()) String(len);
wchar *buffer = out->lockBuffer();
for (uint32 i = 0; i < len; i++)
{
buffer[i] = (c[0] << 8) + c[1];
c += 2;
}
out->unlockBuffer();
return out;
}
else if ((c[0] == 0xff) && (c[1] == 0xfe))
{
//UTF-16 little endian
c += 2;
len = (len - 2) >> 1;
Stringp out = new (core()->GetGC()) String(len);
wchar *buffer = out->lockBuffer();
for (uint32 i = 0; i < len; i++)
{
buffer[i] = (c[1] << 8) + c[0];
c += 2;
}
out->unlockBuffer();
return out;
}
}
return core()->newString(((char *)c), len);
}
int ByteArrayObject::readByte()
{
return (signed char)m_byteArray.ReadU8();
}
int ByteArrayObject::readUnsignedByte()
{
return m_byteArray.ReadU8();
}
int ByteArrayObject::readShort()
{
return (short)m_byteArray.ReadU16();
}
int ByteArrayObject::readUnsignedShort()
{
return m_byteArray.ReadU16();
}
int ByteArrayObject::readInt()
{
return (int)m_byteArray.ReadU32();
}
uint32 ByteArrayObject::readUnsignedInt()
{
return m_byteArray.ReadU32();
}
double ByteArrayObject::readFloat()
{
return m_byteArray.ReadFloat();
}
double ByteArrayObject::readDouble()
{
return m_byteArray.ReadDouble();
}
bool ByteArrayObject::readBoolean()
{
return m_byteArray.ReadBoolean();
}
void ByteArrayObject::writeBoolean(bool value)
{
m_byteArray.WriteBoolean(value);
}
void ByteArrayObject::writeByte(int value)
{
m_byteArray.WriteU8((U8)value);
}
void ByteArrayObject::writeShort(int value)
{
m_byteArray.WriteU16((unsigned short)value);
}
void ByteArrayObject::writeInt(int value)
{
m_byteArray.WriteU32((uint32)value);
}
void ByteArrayObject::writeUnsignedInt(uint32 value)
{
m_byteArray.WriteU32(value);
}
void ByteArrayObject::writeFloat(double value)
{
m_byteArray.WriteFloat((float)value);
}
void ByteArrayObject::writeDouble(double value)
{
m_byteArray.WriteDouble(value);
}
void ByteArrayObject::zlib_compress()
{
#ifdef HAVE_ZLIB
int len = m_byteArray.GetLength();
if (!len) // empty buffer should give us a empty result
return;
unsigned long gzlen = len * 3/2 + 32; // enough for growth plus zlib headers
U8 *gzdata = new U8[gzlen];
// Use zlib to compress the data
compress2((U8*)gzdata, (unsigned long*)&gzlen,
m_byteArray.GetBuffer(), len, 9);
// Replace the byte array with the compressed data
m_byteArray.SetLength(0);
//m_byteArray.WriteU32((U32)len);
m_byteArray.Write(gzdata, gzlen);
delete [] gzdata;
#else
AvmAssert(0);
#endif
}
void ByteArrayObject::zlib_uncompress()
{
#ifdef HAVE_ZLIB
// Snapshot the compressed data.
unsigned long gzlen = m_byteArray.GetLength();
if (!gzlen) // empty buffer should give us a empty result
return;
U8 *gzdata = new U8[gzlen];
memcpy(gzdata, m_byteArray.GetBuffer(), gzlen);
// Clear the buffer
m_byteArray.Seek(0);
m_byteArray.SetLength(0);
// The following block is to force destruction
// of zstream before potential exception throw.
int error = Z_OK;
{
// Decompress the data
PlatformZlibStream zstream;
zstream.SetNextIn(gzdata);
zstream.SetAvailIn(gzlen);
const int kBufferSize = 8192;
U8 *buffer = new U8 [kBufferSize];
do {
zstream.SetNextOut(buffer);
zstream.SetAvailOut(kBufferSize);
error = zstream.InflateWithStatus();
m_byteArray.Write(buffer, kBufferSize-zstream.AvailOut());
} while (error == Z_OK);
delete [] buffer;
delete [] gzdata;
}
// position byte array at the beginning
m_byteArray.Seek(0);
if (error != Z_OK && error != Z_STREAM_END) {
toplevel()->throwError(kShellCompressedDataError);
}
#else
AvmAssert(0);
#endif
}
void ByteArrayObject::checkNull(void *instance, const char *name)
{
if (instance == NULL) {
toplevel()->throwTypeError(kNullArgumentError, core()->toErrorString(name));
}
}
void ByteArrayObject::writeBytes(ByteArrayObject *bytes,
uint32 offset,
uint32 length)
{
checkNull(bytes, "bytes");
if (length == 0) {
length = bytes->getLength() - offset;
}
m_byteArray.WriteByteArray(bytes->GetByteArray(),
offset,
length);
}
void ByteArrayObject::readBytes(ByteArrayObject *bytes,
uint32 offset,
uint32 length)
{
checkNull(bytes, "bytes");
if (length == 0) {
length = m_byteArray.Available();
}
m_byteArray.ReadByteArray(bytes->GetByteArray(),
offset,
length);
}
String* ByteArrayObject::readUTF()
{
return m_byteArray.ReadUTF();
}
String* ByteArrayObject::readUTFBytes(uint32 length)
{
return m_byteArray.ReadUTFBytes(length);
}
void ByteArrayObject::writeUTF(String *value)
{
checkNull(value, "value");
m_byteArray.WriteUTF(value);
}
void ByteArrayObject::writeUTFBytes(String *value)
{
checkNull(value, "value");
m_byteArray.WriteUTFBytes(value);
}
void ByteArrayObject::fill(const void *b, int len)
{
m_byteArray.Write(b, len);
}
//
// ByteArrayClass
//
ByteArrayClass::ByteArrayClass(VTable *vtable)
: ClassClosure(vtable)
{
prototype = toplevel()->objectClass->construct();
}
ScriptObject* ByteArrayClass::createInstance(VTable *ivtable,
ScriptObject *prototype)
{
return new (core()->GetGC(), ivtable->getExtraSize()) ByteArrayObject(ivtable, prototype);
}
ByteArrayObject * ByteArrayClass::readFile(Stringp filename)
{
Toplevel* toplevel = this->toplevel();
if (!filename) {
toplevel->throwArgumentError(kNullArgumentError, "filename");
}
UTF8String* filenameUTF8 = filename->toUTF8String();
FILE *fp = fopen(filenameUTF8->c_str(), "rb");
if (fp == NULL) {
toplevel->throwError(kFileOpenError, filename);
}
fseek(fp, 0L, SEEK_END);
long len = ftell(fp);
rewind(fp);
unsigned char *c = new unsigned char[len+1];
Atom args[1] = {nullObjectAtom};
ByteArrayObject *b = (ByteArrayObject*)AvmCore::atomToScriptObject(construct(0,args));
b->setLength(0);
while (len > 0)
{
int actual = fread(c, 1, len, fp);
if (actual > 0)
{
b->fill(c, actual);
len -= actual;
}
else
{
break;
}
}
b->seek(0);
delete [] c;
return b;
}
Stringp ByteArrayObject::get_endian()
{
return (m_byteArray.GetEndian() == kBigEndian) ? core()->constantString("bigEndian") : core()->constantString("littleEndian");
}
void ByteArrayObject::set_endian(Stringp type)
{
AvmCore* core = this->core();
type = core->internString(type);
if (type == core->constantString("bigEndian"))
{
m_byteArray.SetEndian(kBigEndian);
}
else if (type == core->constantString("littleEndian"))
{
m_byteArray.SetEndian(kLittleEndian);
}
else
{
toplevel()->throwArgumentError(kInvalidArgumentError, "type");
}
}
void ByteArrayObject::writeFile(Stringp filename)
{
Toplevel* toplevel = this->toplevel();
if (!filename) {
toplevel->throwArgumentError(kNullArgumentError, "filename");
}
UTF8String* filenameUTF8 = filename->toUTF8String();
FILE *fp = fopen(filenameUTF8->c_str(), "wb");
if (fp == NULL) {
toplevel->throwError(kFileWriteError, filename);
}
fwrite(&(this->GetByteArray())[0], this->get_length(), 1, fp);
fclose(fp);
}
}