root/axscript/ByteArrayGlue.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. BEGIN_NATIVE_MAP
  2. ThrowMemoryError
  3. Grow
  4. Push
  5. Push
  6. SetLength
  7. DataOutput
  8. Available
  9. SetLength
  10. Read
  11. Write
  12. m_byteArray
  13. getUintProperty
  14. setUintProperty
  15. getAtomProperty
  16. setAtomProperty
  17. hasAtomProperty
  18. setLength
  19. get_length
  20. set_length
  21. getFilePointer
  22. available
  23. seek
  24. _toString
  25. readByte
  26. readUnsignedByte
  27. readShort
  28. readUnsignedShort
  29. readInt
  30. readUnsignedInt
  31. readFloat
  32. readDouble
  33. readBoolean
  34. writeBoolean
  35. writeByte
  36. writeShort
  37. writeInt
  38. writeUnsignedInt
  39. writeFloat
  40. writeDouble
  41. zlib_compress
  42. zlib_uncompress
  43. checkNull
  44. writeBytes
  45. readBytes
  46. readUTF
  47. readUTFBytes
  48. writeUTF
  49. writeUTFBytes
  50. fill
  51. createInstance
  52. readFile
  53. get_endian
  54. set_endian
  55. 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);
        }

}       



/* [<][>][^][v][top][bottom][index][help] */