/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.objects.binary; import static com.github.anba.es6draft.runtime.AbstractOperations.ToBoolean; import static com.github.anba.es6draft.runtime.AbstractOperations.ToInteger; import static com.github.anba.es6draft.runtime.AbstractOperations.ToLength; import static com.github.anba.es6draft.runtime.AbstractOperations.ToNumber; import static com.github.anba.es6draft.runtime.internal.Errors.newRangeError; import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError; import static com.github.anba.es6draft.runtime.internal.Properties.createProperties; import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.GetValueFromBuffer; import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.IsDetachedBuffer; import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.SetValueInBuffer; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.Initializable; import com.github.anba.es6draft.runtime.internal.Messages; import com.github.anba.es6draft.runtime.internal.Properties.Attributes; import com.github.anba.es6draft.runtime.internal.Properties.Prototype; import com.github.anba.es6draft.runtime.internal.Properties.Value; import com.github.anba.es6draft.runtime.types.Constructor; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.Type; import com.github.anba.es6draft.runtime.types.builtins.BuiltinConstructor; /** * <h1>24 Structured Data</h1><br> * <h2>24.2 DataView Objects</h2> * <ul> * <li>24.2.1 Abstract Operations For DataView Objects * <li>24.2.2 The DataView Constructor * <li>24.2.3 Properties of the DataView Constructor * </ul> */ public final class DataViewConstructor extends BuiltinConstructor implements Initializable { /** * Constructs a new DataView constructor function. * * @param realm * the realm object */ public DataViewConstructor(Realm realm) { super(realm, "DataView", 3); } @Override public void initialize(Realm realm) { createProperties(realm, this, Properties.class); } @Override public DataViewConstructor clone() { return new DataViewConstructor(getRealm()); } /** * 24.2.1 Abstract Operations For DataView Objects <br> * 24.2.1.1 GetViewValue(view, requestIndex, isLittleEndian, type) * * @param cx * the execution context * @param view * the data view object * @param requestIndex * the element index * @param isLittleEndian * the little endian flag * @param type * the element type * @return the view element value */ public static double GetViewValue(ExecutionContext cx, Object view, Object requestIndex, Object isLittleEndian, ElementType type) { /* steps 1-2 */ if (!(view instanceof DataViewObject)) { throw newTypeError(cx, Messages.Key.IncompatibleObject); } DataViewObject dataView = (DataViewObject) view; /* step 3 */ double numberIndex = ToNumber(cx, requestIndex); /* steps 4-5 */ double getIndex = ToInteger(numberIndex); /* step 6 */ if (numberIndex != getIndex || getIndex < 0) { throw newRangeError(cx, Messages.Key.InvalidByteOffset); } /* step 7 */ boolean littleEndian = ToBoolean(isLittleEndian); /* step 8 */ ArrayBuffer buffer = dataView.getBuffer(); /* step 9 */ if (IsDetachedBuffer(buffer)) { throw newTypeError(cx, Messages.Key.BufferDetached); } /* step 10 */ long viewOffset = dataView.getByteOffset(); /* step 11 */ long viewSize = dataView.getByteLength(); /* step 12 */ int elementSize = type.size(); /* step 13 */ if (getIndex + elementSize > viewSize) { throw newRangeError(cx, Messages.Key.ArrayOffsetOutOfRange); } /* step 14 */ long bufferIndex = (long) getIndex + viewOffset; /* step 15 */ return GetValueFromBuffer(buffer, bufferIndex, type, littleEndian); } /** * 24.2.1 Abstract Operations For DataView Objects <br> * 24.2.1.2 SetViewValue(view, requestIndex, isLittleEndian, type, value) * * @param cx * the execution context * @param view * the data view object * @param requestIndex * the element index * @param isLittleEndian * the little endian flag * @param type * the element type * @param value * the new view element value */ public static void SetViewValue(ExecutionContext cx, Object view, Object requestIndex, Object isLittleEndian, ElementType type, Object value) { /* steps 1-2 */ if (!(view instanceof DataViewObject)) { throw newTypeError(cx, Messages.Key.IncompatibleObject); } DataViewObject dataView = (DataViewObject) view; /* step 3 */ double numberIndex = ToNumber(cx, requestIndex); /* steps 4-5 */ double getIndex = ToInteger(numberIndex); /* step 6 */ if (numberIndex != getIndex || getIndex < 0) { throw newRangeError(cx, Messages.Key.InvalidByteOffset); } double numberValue = ToNumber(cx, value); /* step 7 */ boolean littleEndian = ToBoolean(isLittleEndian); /* step 8 */ ArrayBuffer buffer = dataView.getBuffer(); /* step 9 */ if (IsDetachedBuffer(buffer)) { throw newTypeError(cx, Messages.Key.BufferDetached); } /* step 10 */ long viewOffset = dataView.getByteOffset(); /* step 11 */ long viewSize = dataView.getByteLength(); /* step 12 */ int elementSize = type.size(); /* step 13 */ if (getIndex + elementSize > viewSize) { throw newRangeError(cx, Messages.Key.ArrayOffsetOutOfRange); } /* step 14 */ long bufferIndex = (long) getIndex + viewOffset; /* step 15 */ SetValueInBuffer(buffer, bufferIndex, type, numberValue, littleEndian); } /** * 24.2.2.1 DataView (buffer [, byteOffset [, byteLength ] ]) */ @Override public Object call(ExecutionContext callerContext, Object thisValue, Object... args) { /* step 1 */ throw newTypeError(calleeContext(), Messages.Key.InvalidCall, "DataView"); } /** * 24.2.2.1 DataView (buffer [, byteOffset [, byteLength ] ]) */ @Override public DataViewObject construct(ExecutionContext callerContext, Constructor newTarget, Object... args) { ExecutionContext calleeContext = calleeContext(); Object buffer = argument(args, 0); // FIXME: spec bug - missing/undefined byteOffset parameter not handled. // https://bugs.ecmascript.org/show_bug.cgi?id=4516 Object byteOffset = argument(args, 1, 0); Object byteLength = argument(args, 2); /* step 1 (not applicable)*/ /* steps 2-3 */ if (!(buffer instanceof ArrayBuffer)) { throw newTypeError(calleeContext, Messages.Key.IncompatibleObject); } ArrayBuffer bufferObj = (ArrayBuffer) buffer; /* step 4 */ double numberOffset = ToNumber(calleeContext, byteOffset); /* steps 5-6 */ double offset = ToInteger(numberOffset); /* step 7 */ if (numberOffset != offset || offset < 0) { throw newRangeError(calleeContext, Messages.Key.InvalidByteOffset); } /* step 8 */ if (IsDetachedBuffer(bufferObj)) { throw newTypeError(calleeContext, Messages.Key.BufferDetached); } /* step 9 */ long bufferByteLength = bufferObj.getByteLength(); /* step 10 */ if (offset > bufferByteLength) { throw newRangeError(calleeContext, Messages.Key.ArrayOffsetOutOfRange); } /* steps 11-12 */ long viewByteLength, viewByteOffset = (long) offset; if (Type.isUndefined(byteLength)) { viewByteLength = bufferByteLength - viewByteOffset; } else { viewByteLength = ToLength(calleeContext, byteLength); if (offset + viewByteLength > bufferByteLength) { throw newRangeError(calleeContext, Messages.Key.ArrayOffsetOutOfRange); } } /* steps 13-19 */ return new DataViewObject(calleeContext.getRealm(), bufferObj, viewByteLength, viewByteOffset, GetPrototypeFromConstructor(calleeContext, newTarget, Intrinsics.DataViewPrototype)); } /** * 24.2.3 Properties of the DataView Constructor */ public enum Properties { ; @Prototype public static final Intrinsics __proto__ = Intrinsics.FunctionPrototype; @Value(name = "length", attributes = @Attributes(writable = false, enumerable = false, configurable = true)) public static final int length = 3; @Value(name = "name", attributes = @Attributes(writable = false, enumerable = false, configurable = true)) public static final String name = "DataView"; /** * 24.2.3.1 DataView.prototype */ @Value(name = "prototype", attributes = @Attributes(writable = false, enumerable = false, configurable = false)) public static final Intrinsics prototype = Intrinsics.DataViewPrototype; } }