File indexing completed on 2024-04-28 15:23:06

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2013 Bernd Buschinski <b.buschinski@googlemail.com>
0004  *
0005  *  This library is free software; you can redistribute it and/or
0006  *  modify it under the terms of the GNU Lesser General Public
0007  *  License as published by the Free Software Foundation; either
0008  *  version 2 of the License, or (at your option) any later version.
0009  *
0010  *  This library is distributed in the hope that it will be useful,
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  *  Lesser General Public License for more details.
0014  *
0015  *  You should have received a copy of the GNU Lesser General Public
0016  *  License along with this library; if not, write to the Free Software
0017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018  */
0019 
0020 #include "ecma/kjs_arraybuffer.h"
0021 
0022 #include <kjs/operations.h>
0023 
0024 #include "kjs_arraybuffer.lut.h"
0025 
0026 namespace KJS
0027 {
0028 
0029 ArrayBufferConstructorImp::ArrayBufferConstructorImp(ExecState *exec, DOM::DocumentImpl *d)
0030     : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), doc(d)
0031 {
0032 }
0033 
0034 bool ArrayBufferConstructorImp::implementsConstruct() const
0035 {
0036     return true;
0037 }
0038 
0039 JSObject *ArrayBufferConstructorImp::construct(ExecState * /*exec*/, const List &args)
0040 {
0041     double sizeF = 0.0;
0042     size_t size = 0;
0043     if (args[0]->getNumber(sizeF)) {
0044         if (!KJS::isNaN(sizeF) && !KJS::isInf(sizeF) && sizeF > 0) {
0045             size = static_cast<size_t>(sizeF);
0046         }
0047     }
0048 
0049     return new ArrayBuffer(size);
0050 }
0051 
0052 /* Source for ArrayBufferProtoTable.
0053 
0054 @begin ArrayBufferProtoTable 1
0055     splice  ArrayBuffer::Splice     Function|DontDelete     1
0056 @end
0057 
0058 */
0059 
0060 KJS_DEFINE_PROTOTYPE(ArrayBufferProto)
0061 KJS_IMPLEMENT_PROTOFUNC(ArrayBufferProtoFunc)
0062 KJS_IMPLEMENT_PROTOTYPE("ArrayBuffer", ArrayBufferProto, ArrayBufferProtoFunc, ObjectPrototype)
0063 
0064 const ClassInfo ArrayBuffer::info = { "ArrayBuffer", nullptr, &ArrayBufferTable, nullptr };
0065 
0066 /* Source for ArrayBufferTable.
0067 
0068 @begin ArrayBufferTable 1
0069     byteLength  ArrayBuffer::ByteLength     ReadOnly|DontDelete
0070 @end
0071 
0072 */
0073 
0074 ArrayBuffer::ArrayBuffer(size_t size)
0075     : JSObject(),
0076       m_size(size),
0077       m_buffer(nullptr)
0078 {
0079     if (m_size > 0) {
0080         m_buffer = new uint8_t[m_size];
0081         memset(m_buffer, 0, m_size);
0082     }
0083 }
0084 
0085 ArrayBuffer::ArrayBuffer(uint8_t *buffer, size_t size)
0086     : JSObject(),
0087       m_size(size),
0088       m_buffer(nullptr)
0089 {
0090     if (m_size > 0) {
0091         m_buffer = new uint8_t[m_size];
0092         memcpy(m_buffer, buffer, m_size);
0093     }
0094 }
0095 
0096 ArrayBuffer::~ArrayBuffer()
0097 {
0098     delete[] m_buffer;
0099 }
0100 
0101 bool ArrayBuffer::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0102 {
0103     return getStaticValueSlot<ArrayBuffer, JSObject>(exec, &ArrayBufferTable, this, propertyName, slot);
0104 }
0105 
0106 JSValue *ArrayBuffer::getValueProperty(ExecState * /*exec*/, int token) const
0107 {
0108     switch (token) {
0109     case ByteLength:
0110         return jsNumber(m_size);
0111     default:
0112         return jsUndefined();
0113     }
0114 }
0115 
0116 // -------------------------- ArrayBufferProtoFunc ----------------------------
0117 
0118 JSValue *ArrayBufferProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0119 {
0120     if (thisObj->inherits(&ArrayBuffer::info)) {
0121         return throwError(exec, TypeError);
0122     }
0123 
0124     ArrayBuffer *arraybuf = static_cast<ArrayBuffer *>(thisObj);
0125     switch (id) {
0126     case ArrayBuffer::Splice: {
0127         // Slice takes max long/signed size_t
0128         // If start or end are negative, it refers to an index from the end of the array
0129         ssize_t start = 0;
0130         ssize_t end = 0;
0131         double tmp;
0132         if (args[0]->getNumber(tmp)) {
0133             start = static_cast<ssize_t>(tmp);
0134         }
0135         if (args.size() >= 2 && args[1]->getNumber(tmp)) {
0136             end = static_cast<ssize_t>(tmp);
0137         }
0138 
0139         // turn negative start/end into a valid positive index
0140         if (start < 0 && arraybuf->byteLength() > static_cast<size_t>(-start)) {
0141             start = arraybuf->byteLength() + start;
0142         }
0143         if (end < 0 && arraybuf->byteLength() > static_cast<size_t>(-end)) {
0144             end = arraybuf->byteLength() + end;
0145         }
0146 
0147         if (static_cast<size_t>(start) > arraybuf->byteLength()) {
0148             start = arraybuf->byteLength();
0149         }
0150         if (static_cast<size_t>(end) > arraybuf->byteLength()) {
0151             end = 0;
0152         }
0153 
0154         size_t length = 0;
0155         if (start < end) {
0156             length = end - start;
0157         } else if (args.size() < 2 && start > 0 && arraybuf->byteLength() > static_cast<size_t>(start)) {
0158             length = arraybuf->byteLength() - start;
0159         }
0160 
0161         ArrayBuffer *ret = new ArrayBuffer(length);
0162         memcpy(ret->buffer(), arraybuf->buffer() + start, length);
0163         return ret;
0164     }
0165     default:
0166         return jsUndefined();
0167     }
0168 }
0169 
0170 } // namespace KJS