/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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/. */
package org.mozilla.javascript.typedarrays;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.IdFunctionObject;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
/**
* This class represents the JavaScript "DataView" interface, which allows direct manipulations of the
* bytes in a NativeArrayBuffer. Java programmers would be best off getting the underling "byte[]" array
* from the NativeArrayBuffer and manipulating it directly, perhaps using the "ByteIo" class as a helper.
*/
public class NativeDataView
extends NativeArrayBufferView
{
private static final long serialVersionUID = 1427967607557438968L;
public static final String CLASS_NAME = "DataView";
public NativeDataView()
{
super();
}
public NativeDataView(NativeArrayBuffer ab, int offset, int length)
{
super(ab, offset, length);
}
@Override
public String getClassName()
{
return CLASS_NAME;
}
public static void init(Context cx, Scriptable scope, boolean sealed)
{
NativeDataView dv = new NativeDataView();
dv.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
}
private void rangeCheck(int offset, int len)
{
if ((offset < 0) || ((offset + len) > byteLength)) {
throw ScriptRuntime.constructError("RangeError", "offset out of range");
}
}
private void checkOffset(Object[] args, int pos)
{
if (args.length <= pos) {
throw ScriptRuntime.constructError("TypeError", "missing required offset parameter");
}
if (Undefined.instance.equals(args[pos])) {
throw ScriptRuntime.constructError("RangeError", "invalid offset");
}
}
private void checkValue(Object[] args, int pos)
{
if (args.length <= pos) {
throw ScriptRuntime.constructError("TypeError", "missing required value parameter");
}
if (Undefined.instance.equals(args[pos])) {
throw ScriptRuntime.constructError("RangeError", "invalid value parameter");
}
}
private static NativeDataView realThis(Scriptable thisObj, IdFunctionObject f)
{
if (!(thisObj instanceof NativeDataView))
throw incompatibleCallError(f);
return (NativeDataView)thisObj;
}
private NativeDataView js_constructor(NativeArrayBuffer ab, int offset, int length)
{
if (length < 0) {
throw ScriptRuntime.constructError("RangeError", "length out of range");
}
if ((offset < 0) || ((offset + length) > ab.getLength())) {
throw ScriptRuntime.constructError("RangeError", "offset out of range");
}
return new NativeDataView(ab, offset, length);
}
private Object js_getInt(int bytes, boolean signed, Object[] args)
{
checkOffset(args, 0);
int offset = ScriptRuntime.toInt32(args[0]);
rangeCheck(offset, bytes);
boolean littleEndian =
(isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]));
switch (bytes) {
case 1:
return (signed ? ByteIo.readInt8(arrayBuffer.buffer, offset) :
ByteIo.readUint8(arrayBuffer.buffer, offset));
case 2:
return (signed ? ByteIo.readInt16(arrayBuffer.buffer, offset, littleEndian) :
ByteIo.readUint16(arrayBuffer.buffer, offset, littleEndian));
case 4:
return (signed ? ByteIo.readInt32(arrayBuffer.buffer, offset, littleEndian) :
ByteIo.readUint32(arrayBuffer.buffer, offset, littleEndian));
default:
throw new AssertionError();
}
}
private Object js_getFloat(int bytes, Object[] args)
{
checkOffset(args, 0);
int offset = ScriptRuntime.toInt32(args[0]);
rangeCheck(offset, bytes);
boolean littleEndian =
(isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]));
switch (bytes) {
case 4:
return ByteIo.readFloat32(arrayBuffer.buffer, offset, littleEndian);
case 8:
return ByteIo.readFloat64(arrayBuffer.buffer, offset, littleEndian);
default:
throw new AssertionError();
}
}
private void js_setInt(int bytes, boolean signed, Object[] args)
{
checkOffset(args, 0);
checkValue(args, 1);
int offset = ScriptRuntime.toInt32(args[0]);
rangeCheck(offset, bytes);
boolean littleEndian =
(isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]));
switch (bytes) {
case 1:
if (signed) {
ByteIo.writeInt8(arrayBuffer.buffer, offset, Conversions.toInt8(args[1]));
} else {
ByteIo.writeUint8(arrayBuffer.buffer, offset, Conversions.toUint8(args[1]));
}
break;
case 2:
if (signed) {
ByteIo.writeInt16(arrayBuffer.buffer, offset, Conversions.toInt16(args[1]), littleEndian);
} else {
ByteIo.writeUint16(arrayBuffer.buffer, offset, Conversions.toUint16(args[1]), littleEndian);
}
break;
case 4:
if (signed) {
ByteIo.writeInt32(arrayBuffer.buffer, offset, Conversions.toInt32(args[1]), littleEndian);
} else {
ByteIo.writeUint32(arrayBuffer.buffer, offset, Conversions.toUint32(args[1]), littleEndian);
}
break;
default:
throw new AssertionError();
}
}
private void js_setFloat(int bytes, Object[] args)
{
checkOffset(args, 0);
checkValue(args, 1);
int offset = ScriptRuntime.toInt32(args[0]);
rangeCheck(offset, bytes);
boolean littleEndian =
(isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]));
double val = ScriptRuntime.toNumber(args[1]);
switch (bytes) {
case 4:
ByteIo.writeFloat32(arrayBuffer.buffer, offset, val, littleEndian);
break;
case 8:
ByteIo.writeFloat64(arrayBuffer.buffer, offset, val, littleEndian);
break;
default:
throw new AssertionError();
}
}
// Function dispatcher
@Override
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
{
if (!f.hasTag(getClassName())) {
return super.execIdCall(f, cx, scope, thisObj, args);
}
int id = f.methodId();
switch (id) {
case Id_constructor:
if (isArg(args, 0) && (args[0] instanceof NativeArrayBuffer)) {
NativeArrayBuffer ab = (NativeArrayBuffer)args[0];
int off = isArg(args, 1) ? ScriptRuntime.toInt32(args[1]) : 0;
int len = isArg(args, 2) ? ScriptRuntime.toInt32(args[2]) : ab.getLength() - off;
return js_constructor(ab, off, len);
} else {
throw ScriptRuntime.constructError("TypeError", "Missing parameters");
}
case Id_getInt8:
return realThis(thisObj, f).js_getInt(1, true, args);
case Id_getUint8:
return realThis(thisObj, f).js_getInt(1, false, args);
case Id_getInt16:
return realThis(thisObj, f).js_getInt(2, true, args);
case Id_getUint16:
return realThis(thisObj, f).js_getInt(2, false, args);
case Id_getInt32:
return realThis(thisObj, f).js_getInt(4, true, args);
case Id_getUint32:
return realThis(thisObj, f).js_getInt(4, false, args);
case Id_getFloat32:
return realThis(thisObj, f).js_getFloat(4, args);
case Id_getFloat64:
return realThis(thisObj, f).js_getFloat(8, args);
case Id_setInt8:
realThis(thisObj, f).js_setInt(1, true, args);
return Undefined.instance;
case Id_setUint8:
realThis(thisObj, f).js_setInt(1, false, args);
return Undefined.instance;
case Id_setInt16:
realThis(thisObj, f).js_setInt(2, true, args);
return Undefined.instance;
case Id_setUint16:
realThis(thisObj, f).js_setInt(2, false, args);
return Undefined.instance;
case Id_setInt32:
realThis(thisObj, f).js_setInt(4, true, args);
return Undefined.instance;
case Id_setUint32:
realThis(thisObj, f).js_setInt(4, false, args);
return Undefined.instance;
case Id_setFloat32:
realThis(thisObj, f).js_setFloat(4, args);
return Undefined.instance;
case Id_setFloat64:
realThis(thisObj, f).js_setFloat(8, args);
return Undefined.instance;
}
throw new IllegalArgumentException(String.valueOf(id));
}
@Override
protected void initPrototypeId(int id)
{
String s;
int arity;
switch (id) {
case Id_constructor: arity = 1; s = "constructor"; break;
case Id_getInt8: arity = 1; s = "getInt8"; break;
case Id_getUint8: arity = 1; s = "getUint8"; break;
case Id_getInt16: arity = 1; s = "getInt16"; break;
case Id_getUint16: arity = 1; s = "getUint16"; break;
case Id_getInt32: arity = 1; s = "getInt32"; break;
case Id_getUint32: arity = 1; s = "getUint32"; break;
case Id_getFloat32: arity = 1; s = "getFloat32"; break;
case Id_getFloat64: arity = 1; s = "getFloat64"; break;
case Id_setInt8: arity = 2; s = "setInt8"; break;
case Id_setUint8: arity = 2; s = "setUint8"; break;
case Id_setInt16: arity = 2; s = "setInt16"; break;
case Id_setUint16: arity = 2; s = "setUint16"; break;
case Id_setInt32: arity = 2; s = "setInt32"; break;
case Id_setUint32: arity = 2; s = "setUint32"; break;
case Id_setFloat32: arity = 2; s = "setFloat32"; break;
case Id_setFloat64: arity = 2; s = "setFloat64"; break;
default: throw new IllegalArgumentException(String.valueOf(id));
}
initPrototypeMethod(getClassName(), id, s, arity);
}
// #string_id_map#
@Override
protected int findPrototypeId(String s)
{
int id;
// #generated# Last update: 2014-12-08 17:26:24 PST
L0: { id = 0; String X = null; int c;
L: switch (s.length()) {
case 7: c=s.charAt(0);
if (c=='g') { X="getInt8";id=Id_getInt8; }
else if (c=='s') { X="setInt8";id=Id_setInt8; }
break L;
case 8: c=s.charAt(6);
if (c=='1') {
c=s.charAt(0);
if (c=='g') { X="getInt16";id=Id_getInt16; }
else if (c=='s') { X="setInt16";id=Id_setInt16; }
}
else if (c=='3') {
c=s.charAt(0);
if (c=='g') { X="getInt32";id=Id_getInt32; }
else if (c=='s') { X="setInt32";id=Id_setInt32; }
}
else if (c=='t') {
c=s.charAt(0);
if (c=='g') { X="getUint8";id=Id_getUint8; }
else if (c=='s') { X="setUint8";id=Id_setUint8; }
}
break L;
case 9: c=s.charAt(0);
if (c=='g') {
c=s.charAt(8);
if (c=='2') { X="getUint32";id=Id_getUint32; }
else if (c=='6') { X="getUint16";id=Id_getUint16; }
}
else if (c=='s') {
c=s.charAt(8);
if (c=='2') { X="setUint32";id=Id_setUint32; }
else if (c=='6') { X="setUint16";id=Id_setUint16; }
}
break L;
case 10: c=s.charAt(0);
if (c=='g') {
c=s.charAt(9);
if (c=='2') { X="getFloat32";id=Id_getFloat32; }
else if (c=='4') { X="getFloat64";id=Id_getFloat64; }
}
else if (c=='s') {
c=s.charAt(9);
if (c=='2') { X="setFloat32";id=Id_setFloat32; }
else if (c=='4') { X="setFloat64";id=Id_setFloat64; }
}
break L;
case 11: X="constructor";id=Id_constructor; break L;
}
if (X!=null && X!=s && !X.equals(s)) id = 0;
break L0;
}
// #/generated#
return id;
}
private static final int
Id_constructor = 1,
Id_getInt8 = 2,
Id_getUint8 = 3,
Id_getInt16 = 4,
Id_getUint16 = 5,
Id_getInt32 = 6,
Id_getUint32 = 7,
Id_getFloat32 = 8,
Id_getFloat64 = 9,
Id_setInt8 = 10,
Id_setUint8 = 11,
Id_setInt16 = 12,
Id_setUint16 = 13,
Id_setInt32 = 14,
Id_setUint32 = 15,
Id_setFloat32 = 16,
Id_setFloat64 = 17,
MAX_PROTOTYPE_ID = Id_setFloat64;
// #/string_id_map#
}