1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.nashorn.internal.objects; 26 27 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 28 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; 29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 30 31 import java.nio.ByteBuffer; 32 import java.nio.ByteOrder; 33 import jdk.nashorn.internal.objects.annotations.Attribute; 34 import jdk.nashorn.internal.objects.annotations.Constructor; 35 import jdk.nashorn.internal.objects.annotations.Function; 36 import jdk.nashorn.internal.objects.annotations.Property; 37 import jdk.nashorn.internal.objects.annotations.ScriptClass; 38 import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; 39 import jdk.nashorn.internal.objects.annotations.SpecializedFunction; 40 import jdk.nashorn.internal.runtime.JSType; 41 import jdk.nashorn.internal.runtime.PropertyMap; 42 import jdk.nashorn.internal.runtime.ScriptObject; 43 import jdk.nashorn.internal.runtime.ScriptRuntime; 44 45 /** 46 * <p> 47 * DataView builtin constructor. Based on the specification here: 48 * http://www.khronos.org/registry/typedarray/specs/latest/#8 49 * </p> 50 * <p> 51 * An ArrayBuffer is a useful object for representing an arbitrary chunk of data. 52 * In many cases, such data will be read from disk or from the network, and will 53 * not follow the alignment restrictions that are imposed on the typed array views 54 * described earlier. In addition, the data will often be heterogeneous in nature 55 * and have a defined byte order. The DataView view provides a low-level interface 56 * for reading such data from and writing it to an ArrayBuffer. 57 * </p> 58 * <p> 59 * Regardless of the host computer's endianness, DataView reads or writes values 60 * to or from main memory with a specified endianness: big or little. 61 * </p> 62 */ 63 @ScriptClass("DataView") 64 public class NativeDataView extends ScriptObject { 65 // initialized by nasgen 66 private static PropertyMap $nasgenmap$; 67 68 // inherited ArrayBufferView properties 69 70 /** 71 * Underlying ArrayBuffer storage object 72 */ 73 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 74 public final Object buffer; 75 76 /** 77 * The offset in bytes from the start of the ArrayBuffer 78 */ 79 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 80 public final int byteOffset; 81 82 /** 83 * The number of bytes from the offset that this DataView will reference 84 */ 85 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 86 public final int byteLength; 87 88 // underlying ByteBuffer 89 private final ByteBuffer buf; 90 91 private NativeDataView(NativeArrayBuffer arrBuf) { 92 this(arrBuf, arrBuf.getBuffer(), 0); 93 } 94 95 private NativeDataView(NativeArrayBuffer arrBuf, int offset) { 96 this(arrBuf, bufferFrom(arrBuf, offset), offset); 97 } 98 99 private NativeDataView(NativeArrayBuffer arrBuf, int offset, int length) { 100 this(arrBuf, bufferFrom(arrBuf, offset, length), offset, length); 101 } 102 103 private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset) { 104 this(arrBuf, buf, offset, buf.capacity() - offset); 105 } 106 107 private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) { 108 super(Global.instance().getDataViewPrototype(), $nasgenmap$); 109 this.buffer = arrBuf; 110 this.byteOffset = offset; 111 this.byteLength = length; 112 this.buf = buf; 113 } 114 115 /** 116 * Create a new DataView object using the passed ArrayBuffer for its 117 * storage. Optional byteOffset and byteLength can be used to limit the 118 * section of the buffer referenced. The byteOffset indicates the offset in 119 * bytes from the start of the ArrayBuffer, and the byteLength is the number 120 * of bytes from the offset that this DataView will reference. If both 121 * byteOffset and byteLength are omitted, the DataView spans the entire 122 * ArrayBuffer range. If the byteLength is omitted, the DataView extends from 123 * the given byteOffset until the end of the ArrayBuffer. 124 * 125 * If the given byteOffset and byteLength references an area beyond the end 126 * of the ArrayBuffer an exception is raised. 127 128 * @param newObj if this constructor was invoked with 'new' or not 129 * @param self constructor function object 130 * @param args arguments to the constructor 131 * @return newly constructed DataView object 132 */ 133 @Constructor(arity = 1) 134 public static Object constructor(final boolean newObj, final Object self, final Object... args) { 135 if (args.length == 0 || !(args[0] instanceof NativeArrayBuffer)) { 136 throw typeError("not.an.arraybuffer.in.dataview"); 137 } 138 139 final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0]; 140 switch (args.length) { 141 case 1: 142 return new NativeDataView(arrBuf); 143 case 2: 144 return new NativeDataView(arrBuf, JSType.toInt32(args[1])); 145 default: 146 return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); 147 } 148 } 149 150 /** 151 * Specialized version of DataView constructor 152 * 153 * @param newObj if this constructor was invoked with 'new' or not 154 * @param self constructor function object 155 * @param arrBuf underlying ArrayBuffer storage object 156 * @param offset offset in bytes from the start of the ArrayBuffer 157 * @return newly constructed DataView object 158 */ 159 @SpecializedConstructor 160 public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { 161 if (!(arrBuf instanceof NativeArrayBuffer)) { 162 throw typeError("not.an.arraybuffer.in.dataview"); 163 } 164 return new NativeDataView((NativeArrayBuffer) arrBuf, offset); 165 } 166 167 /** 168 * Specialized version of DataView constructor 169 * 170 * @param newObj if this constructor was invoked with 'new' or not 171 * @param self constructor function object 172 * @param arrBuf underlying ArrayBuffer storage object 173 * @param offset in bytes from the start of the ArrayBuffer 174 * @param length is the number of bytes from the offset that this DataView will reference 175 * @return newly constructed DataView object 176 */ 177 @SpecializedConstructor 178 public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) { 179 if (!(arrBuf instanceof NativeArrayBuffer)) { 180 throw typeError("not.an.arraybuffer.in.dataview"); 181 } 182 return new NativeDataView((NativeArrayBuffer) arrBuf, offset, length); 183 } 184 185 // Gets the value of the given type at the specified byte offset 186 // from the start of the view. There is no alignment constraint; 187 // multi-byte values may be fetched from any offset. 188 // 189 // For multi-byte values, the optional littleEndian argument 190 // indicates whether a big-endian or little-endian value should be 191 // read. If false or undefined, a big-endian value is read. 192 // 193 // These methods raise an exception if they would read 194 // beyond the end of the view. 195 196 /** 197 * Get 8-bit signed int from given byteOffset 198 * 199 * @param self DataView object 200 * @param byteOffset byte offset to read from 201 * @return 8-bit signed int value at the byteOffset 202 */ 203 @Function(attributes = Attribute.NOT_ENUMERABLE) 204 public static int getInt8(final Object self, final Object byteOffset) { 205 try { 206 return getBuffer(self).get(JSType.toInt32(byteOffset)); 207 } catch (final IndexOutOfBoundsException ioe) { 208 throw rangeError(ioe, "dataview.offset"); 209 } 210 } 211 212 /** 213 * Get 8-bit signed int from given byteOffset 214 * 215 * @param self DataView object 216 * @param byteOffset byte offset to read from 217 * @return 8-bit signed int value at the byteOffset 218 */ 219 @SpecializedFunction 220 public static int getInt8(final Object self, final int byteOffset) { 221 try { 222 return getBuffer(self).get(byteOffset); 223 } catch (final IndexOutOfBoundsException ioe) { 224 throw rangeError(ioe, "dataview.offset"); 225 } 226 } 227 228 /** 229 * Get 8-bit unsigned int from given byteOffset 230 * 231 * @param self DataView object 232 * @param byteOffset byte offset to read from 233 * @return 8-bit unsigned int value at the byteOffset 234 */ 235 @Function(attributes = Attribute.NOT_ENUMERABLE) 236 public static int getUint8(final Object self, final Object byteOffset) { 237 try { 238 return (0xFF & getBuffer(self).get(JSType.toInt32(byteOffset))); 239 } catch (final IndexOutOfBoundsException ioe) { 240 throw rangeError(ioe, "dataview.offset"); 241 } 242 } 243 244 /** 245 * Get 8-bit unsigned int from given byteOffset 246 * 247 * @param self DataView object 248 * @param byteOffset byte offset to read from 249 * @return 8-bit unsigned int value at the byteOffset 250 */ 251 @SpecializedFunction 252 public static int getUint8(final Object self, final int byteOffset) { 253 try { 254 return (0xFF & getBuffer(self).get(byteOffset)); 255 } catch (final IndexOutOfBoundsException ioe) { 256 throw rangeError(ioe, "dataview.offset"); 257 } 258 } 259 260 /** 261 * Get 16-bit signed int from given byteOffset 262 * 263 * @param self DataView object 264 * @param byteOffset byte offset to read from 265 * @param littleEndian (optional) flag indicating whether to read in little endian order 266 * @return 16-bit signed int value at the byteOffset 267 */ 268 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 269 public static int getInt16(final Object self, final Object byteOffset, final Object littleEndian) { 270 try { 271 return getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset)); 272 } catch (final IndexOutOfBoundsException ioe) { 273 throw rangeError(ioe, "dataview.offset"); 274 } 275 } 276 277 /** 278 * Get 16-bit signed int from given byteOffset 279 * 280 * @param self DataView object 281 * @param byteOffset byte offset to read from 282 * @return 16-bit signed int value at the byteOffset 283 */ 284 @SpecializedFunction 285 public static int getInt16(final Object self, final int byteOffset) { 286 try { 287 return getBuffer(self, false).getShort(byteOffset); 288 } catch (final IndexOutOfBoundsException ioe) { 289 throw rangeError(ioe, "dataview.offset"); 290 } 291 } 292 293 /** 294 * Get 16-bit signed int from given byteOffset 295 * 296 * @param self DataView object 297 * @param byteOffset byte offset to read from 298 * @param littleEndian (optional) flag indicating whether to read in little endian order 299 * @return 16-bit signed int value at the byteOffset 300 */ 301 @SpecializedFunction 302 public static int getInt16(final Object self, final int byteOffset, final boolean littleEndian) { 303 try { 304 return getBuffer(self, littleEndian).getShort(byteOffset); 305 } catch (final IndexOutOfBoundsException ioe) { 306 throw rangeError(ioe, "dataview.offset"); 307 } 308 } 309 310 /** 311 * Get 16-bit unsigned int from given byteOffset 312 * 313 * @param self DataView object 314 * @param byteOffset byte offset to read from 315 * @param littleEndian (optional) flag indicating whether to read in little endian order 316 * @return 16-bit unsigned int value at the byteOffset 317 */ 318 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 319 public static int getUint16(final Object self, final Object byteOffset, final Object littleEndian) { 320 try { 321 return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset))); 322 } catch (final IndexOutOfBoundsException ioe) { 323 throw rangeError(ioe, "dataview.offset"); 324 } 325 } 326 327 /** 328 * Get 16-bit unsigned int from given byteOffset 329 * 330 * @param self DataView object 331 * @param byteOffset byte offset to read from 332 * @return 16-bit unsigned int value at the byteOffset 333 */ 334 @SpecializedFunction 335 public static int getUint16(final Object self, final int byteOffset) { 336 try { 337 return (int) (0xFFFF & getBuffer(self, false).getShort(byteOffset)); 338 } catch (final IndexOutOfBoundsException ioe) { 339 throw rangeError(ioe, "dataview.offset"); 340 } 341 } 342 343 /** 344 * Get 16-bit unsigned int from given byteOffset 345 * 346 * @param self DataView object 347 * @param byteOffset byte offset to read from 348 * @param littleEndian (optional) flag indicating whether to read in little endian order 349 * @return 16-bit unsigned int value at the byteOffset 350 */ 351 @SpecializedFunction 352 public static int getUint16(final Object self, final int byteOffset, final boolean littleEndian) { 353 try { 354 return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(byteOffset)); 355 } catch (final IndexOutOfBoundsException ioe) { 356 throw rangeError(ioe, "dataview.offset"); 357 } 358 } 359 360 /** 361 * Get 32-bit signed int from given byteOffset 362 * 363 * @param self DataView object 364 * @param byteOffset byte offset to read from 365 * @param littleEndian (optional) flag indicating whether to read in little endian order 366 * @return 32-bit signed int value at the byteOffset 367 */ 368 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 369 public static int getInt32(final Object self, final Object byteOffset, final Object littleEndian) { 370 try { 371 return getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)); 372 } catch (final IndexOutOfBoundsException ioe) { 373 throw rangeError(ioe, "dataview.offset"); 374 } 375 } 376 377 /** 378 * Get 32-bit signed int from given byteOffset 379 * 380 * @param self DataView object 381 * @param byteOffset byte offset to read from 382 * @return 32-bit signed int value at the byteOffset 383 */ 384 @SpecializedFunction 385 public static int getInt32(final Object self, final int byteOffset) { 386 try { 387 return getBuffer(self, false).getInt(byteOffset); 388 } catch (final IndexOutOfBoundsException ioe) { 389 throw rangeError(ioe, "dataview.offset"); 390 } 391 } 392 393 /** 394 * Get 32-bit signed int from given byteOffset 395 * 396 * @param self DataView object 397 * @param byteOffset byte offset to read from 398 * @param littleEndian (optional) flag indicating whether to read in little endian order 399 * @return 32-bit signed int value at the byteOffset 400 */ 401 @SpecializedFunction 402 public static int getInt32(final Object self, final int byteOffset, final boolean littleEndian) { 403 try { 404 return getBuffer(self, littleEndian).getInt(byteOffset); 405 } catch (final IndexOutOfBoundsException ioe) { 406 throw rangeError(ioe, "dataview.offset"); 407 } 408 } 409 410 /** 411 * Get 32-bit unsigned int from given byteOffset 412 * 413 * @param self DataView object 414 * @param byteOffset byte offset to read from 415 * @param littleEndian (optional) flag indicating whether to read in little endian order 416 * @return 32-bit unsigned int value at the byteOffset 417 */ 418 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 419 public static long getUint32(final Object self, final Object byteOffset, final Object littleEndian) { 420 try { 421 return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset))); 422 } catch (final IndexOutOfBoundsException ioe) { 423 throw rangeError(ioe, "dataview.offset"); 424 } 425 } 426 427 /** 428 * Get 32-bit unsigned int from given byteOffset 429 * 430 * @param self DataView object 431 * @param byteOffset byte offset to read from 432 * @return 32-bit unsigned int value at the byteOffset 433 */ 434 @SpecializedFunction 435 public static long getUint32(final Object self, final int byteOffset) { 436 try { 437 return (long) (0xFFFFFFFFL & getBuffer(self, false).getInt(JSType.toInt32(byteOffset))); 438 } catch (final IndexOutOfBoundsException ioe) { 439 throw rangeError(ioe, "dataview.offset"); 440 } 441 } 442 443 /** 444 * Get 32-bit unsigned int from given byteOffset 445 * 446 * @param self DataView object 447 * @param byteOffset byte offset to read from 448 * @param littleEndian (optional) flag indicating whether to read in little endian order 449 * @return 32-bit unsigned int value at the byteOffset 450 */ 451 @SpecializedFunction 452 public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) { 453 try { 454 return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset))); 455 } catch (final IndexOutOfBoundsException ioe) { 456 throw rangeError(ioe, "dataview.offset"); 457 } 458 } 459 460 /** 461 * Get 32-bit float value from given byteOffset 462 * 463 * @param self DataView object 464 * @param byteOffset byte offset to read from 465 * @param littleEndian (optional) flag indicating whether to read in little endian order 466 * @return 32-bit float value at the byteOffset 467 */ 468 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 469 public static double getFloat32(final Object self, final Object byteOffset, final Object littleEndian) { 470 try { 471 return getBuffer(self, littleEndian).getFloat(JSType.toInt32(byteOffset)); 472 } catch (final IndexOutOfBoundsException ioe) { 473 throw rangeError(ioe, "dataview.offset"); 474 } 475 } 476 477 /** 478 * Get 32-bit float value from given byteOffset 479 * 480 * @param self DataView object 481 * @param byteOffset byte offset to read from 482 * @return 32-bit float value at the byteOffset 483 */ 484 @SpecializedFunction 485 public static double getFloat32(final Object self, final int byteOffset) { 486 try { 487 return getBuffer(self, false).getFloat(byteOffset); 488 } catch (final IndexOutOfBoundsException ioe) { 489 throw rangeError(ioe, "dataview.offset"); 490 } 491 } 492 493 /** 494 * Get 32-bit float value from given byteOffset 495 * 496 * @param self DataView object 497 * @param byteOffset byte offset to read from 498 * @param littleEndian (optional) flag indicating whether to read in little endian order 499 * @return 32-bit float value at the byteOffset 500 */ 501 @SpecializedFunction 502 public static double getFloat32(final Object self, final int byteOffset, final boolean littleEndian) { 503 try { 504 return getBuffer(self, littleEndian).getFloat(byteOffset); 505 } catch (final IndexOutOfBoundsException ioe) { 506 throw rangeError(ioe, "dataview.offset"); 507 } 508 } 509 510 /** 511 * Get 64-bit float value from given byteOffset 512 * 513 * @param self DataView object 514 * @param byteOffset byte offset to read from 515 * @param littleEndian (optional) flag indicating whether to read in little endian order 516 * @return 64-bit float value at the byteOffset 517 */ 518 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 519 public static double getFloat64(final Object self, final Object byteOffset, final Object littleEndian) { 520 try { 521 return getBuffer(self, littleEndian).getDouble(JSType.toInt32(byteOffset)); 522 } catch (final IndexOutOfBoundsException ioe) { 523 throw rangeError(ioe, "dataview.offset"); 524 } 525 } 526 527 /** 528 * Get 64-bit float value from given byteOffset 529 * 530 * @param self DataView object 531 * @param byteOffset byte offset to read from 532 * @return 64-bit float value at the byteOffset 533 */ 534 @SpecializedFunction 535 public static double getFloat64(final Object self, final int byteOffset) { 536 try { 537 return getBuffer(self, false).getDouble(byteOffset); 538 } catch (final IndexOutOfBoundsException ioe) { 539 throw rangeError(ioe, "dataview.offset"); 540 } 541 } 542 543 /** 544 * Get 64-bit float value from given byteOffset 545 * 546 * @param self DataView object 547 * @param byteOffset byte offset to read from 548 * @param littleEndian (optional) flag indicating whether to read in little endian order 549 * @return 64-bit float value at the byteOffset 550 */ 551 @SpecializedFunction 552 public static double getFloat64(final Object self, final int byteOffset, final boolean littleEndian) { 553 try { 554 return getBuffer(self, littleEndian).getDouble(byteOffset); 555 } catch (final IndexOutOfBoundsException ioe) { 556 throw rangeError(ioe, "dataview.offset"); 557 } 558 } 559 560 // Stores a value of the given type at the specified byte offset 561 // from the start of the view. There is no alignment constraint; 562 // multi-byte values may be stored at any offset. 563 // 564 // For multi-byte values, the optional littleEndian argument 565 // indicates whether the value should be stored in big-endian or 566 // little-endian byte order. If false or undefined, the value is 567 // stored in big-endian byte order. 568 // 569 // These methods raise an exception if they would write 570 // beyond the end of the view. 571 572 /** 573 * Set 8-bit signed int at the given byteOffset 574 * 575 * @param self DataView object 576 * @param byteOffset byte offset to read from 577 * @param value byte value to set 578 * @return undefined 579 */ 580 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 581 public static Object setInt8(final Object self, final Object byteOffset, final Object value) { 582 try { 583 getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value)); 584 return UNDEFINED; 585 } catch (final IndexOutOfBoundsException ioe) { 586 throw rangeError(ioe, "dataview.offset"); 587 } 588 } 589 590 /** 591 * Set 8-bit signed int at the given byteOffset 592 * 593 * @param self DataView object 594 * @param byteOffset byte offset to read from 595 * @param value byte value to set 596 * @return undefined 597 */ 598 @SpecializedFunction 599 public static Object setInt8(final Object self, final int byteOffset, final int value) { 600 try { 601 getBuffer(self).put(byteOffset, (byte)value); 602 return UNDEFINED; 603 } catch (final IndexOutOfBoundsException ioe) { 604 throw rangeError(ioe, "dataview.offset"); 605 } 606 } 607 608 /** 609 * Set 8-bit unsigned int at the given byteOffset 610 * 611 * @param self DataView object 612 * @param byteOffset byte offset to write at 613 * @param value byte value to set 614 * @return undefined 615 */ 616 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 617 public static Object setUint8(final Object self, final Object byteOffset, final Object value) { 618 try { 619 getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value)); 620 return UNDEFINED; 621 } catch (final IndexOutOfBoundsException ioe) { 622 throw rangeError(ioe, "dataview.offset"); 623 } 624 } 625 626 /** 627 * Set 8-bit unsigned int at the given byteOffset 628 * 629 * @param self DataView object 630 * @param byteOffset byte offset to write at 631 * @param value byte value to set 632 * @return undefined 633 */ 634 @SpecializedFunction 635 public static Object setUint8(final Object self, final int byteOffset, final int value) { 636 try { 637 getBuffer(self).put(byteOffset, (byte)value); 638 return UNDEFINED; 639 } catch (final IndexOutOfBoundsException ioe) { 640 throw rangeError(ioe, "dataview.offset"); 641 } 642 } 643 644 /** 645 * Set 16-bit signed int at the given byteOffset 646 * 647 * @param self DataView object 648 * @param byteOffset byte offset to write at 649 * @param value short value to set 650 * @param littleEndian (optional) flag indicating whether to write in little endian order 651 * @return undefined 652 */ 653 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 654 public static Object setInt16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 655 try { 656 getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value)); 657 return UNDEFINED; 658 } catch (final IndexOutOfBoundsException ioe) { 659 throw rangeError(ioe, "dataview.offset"); 660 } 661 } 662 663 /** 664 * Set 16-bit signed int at the given byteOffset 665 * 666 * @param self DataView object 667 * @param byteOffset byte offset to write at 668 * @param value short value to set 669 * @return undefined 670 */ 671 @SpecializedFunction 672 public static Object setInt16(final Object self, final int byteOffset, final int value) { 673 try { 674 getBuffer(self, false).putShort(byteOffset, (short)value); 675 return UNDEFINED; 676 } catch (final IndexOutOfBoundsException ioe) { 677 throw rangeError(ioe, "dataview.offset"); 678 } 679 } 680 681 /** 682 * Set 16-bit signed int at the given byteOffset 683 * 684 * @param self DataView object 685 * @param byteOffset byte offset to write at 686 * @param value short value to set 687 * @param littleEndian (optional) flag indicating whether to write in little endian order 688 * @return undefined 689 */ 690 @SpecializedFunction 691 public static Object setInt16(final Object self, final int byteOffset, final int value, final boolean littleEndian) { 692 try { 693 getBuffer(self, littleEndian).putShort(byteOffset, (short)value); 694 return UNDEFINED; 695 } catch (final IndexOutOfBoundsException ioe) { 696 throw rangeError(ioe, "dataview.offset"); 697 } 698 } 699 700 /** 701 * Set 16-bit unsigned int at the given byteOffset 702 * 703 * @param self DataView object 704 * @param byteOffset byte offset to write at 705 * @param value short value to set 706 * @param littleEndian (optional) flag indicating whether to write in little endian order 707 * @return undefined 708 */ 709 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 710 public static Object setUint16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 711 try { 712 getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value)); 713 return UNDEFINED; 714 } catch (final IndexOutOfBoundsException ioe) { 715 throw rangeError(ioe, "dataview.offset"); 716 } 717 } 718 719 /** 720 * Set 16-bit unsigned int at the given byteOffset 721 * 722 * @param self DataView object 723 * @param byteOffset byte offset to write at 724 * @param value short value to set 725 * @return undefined 726 */ 727 @SpecializedFunction 728 public static Object setUint16(final Object self, final int byteOffset, final int value) { 729 try { 730 getBuffer(self, false).putShort(byteOffset, (short)value); 731 return UNDEFINED; 732 } catch (final IndexOutOfBoundsException ioe) { 733 throw rangeError(ioe, "dataview.offset"); 734 } 735 } 736 737 /** 738 * Set 16-bit unsigned int at the given byteOffset 739 * 740 * @param self DataView object 741 * @param byteOffset byte offset to write at 742 * @param value short value to set 743 * @param littleEndian (optional) flag indicating whether to write in little endian order 744 * @return undefined 745 */ 746 @SpecializedFunction 747 public static Object setUint16(final Object self, final int byteOffset, final int value, final boolean littleEndian) { 748 try { 749 getBuffer(self, littleEndian).putShort(byteOffset, (short)value); 750 return UNDEFINED; 751 } catch (final IndexOutOfBoundsException ioe) { 752 throw rangeError(ioe, "dataview.offset"); 753 } 754 } 755 756 /** 757 * Set 32-bit signed int at the given byteOffset 758 * 759 * @param self DataView object 760 * @param byteOffset byte offset to write at 761 * @param value int value to set 762 * @param littleEndian (optional) flag indicating whether to write in little endian order 763 * @return undefined 764 */ 765 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 766 public static Object setInt32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 767 try { 768 getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toInt32(value)); 769 return UNDEFINED; 770 } catch (final IndexOutOfBoundsException ioe) { 771 throw rangeError(ioe, "dataview.offset"); 772 } 773 } 774 775 /** 776 * Set 32-bit signed int at the given byteOffset 777 * 778 * @param self DataView object 779 * @param byteOffset byte offset to write at 780 * @param value int value to set 781 * @return undefined 782 */ 783 @SpecializedFunction 784 public static Object setInt32(final Object self, final int byteOffset, final int value) { 785 try { 786 getBuffer(self, false).putInt(byteOffset, value); 787 return UNDEFINED; 788 } catch (final IndexOutOfBoundsException ioe) { 789 throw rangeError(ioe, "dataview.offset"); 790 } 791 } 792 793 /** 794 * Set 32-bit signed int at the given byteOffset 795 * 796 * @param self DataView object 797 * @param byteOffset byte offset to write at 798 * @param value int value to set 799 * @param littleEndian (optional) flag indicating whether to write in little endian order 800 * @return undefined 801 */ 802 @SpecializedFunction 803 public static Object setInt32(final Object self, final int byteOffset, final int value, final boolean littleEndian) { 804 try { 805 getBuffer(self, littleEndian).putInt(byteOffset, value); 806 return UNDEFINED; 807 } catch (final IndexOutOfBoundsException ioe) { 808 throw rangeError(ioe, "dataview.offset"); 809 } 810 } 811 812 /** 813 * Set 32-bit unsigned int at the given byteOffset 814 * 815 * @param self DataView object 816 * @param byteOffset byte offset to write at 817 * @param value int value to set 818 * @param littleEndian (optional) flag indicating whether to write in little endian order 819 * @return undefined 820 */ 821 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 822 public static Object setUint32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 823 try { 824 getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toUint32(value)); 825 return UNDEFINED; 826 } catch (final IndexOutOfBoundsException ioe) { 827 throw rangeError(ioe, "dataview.offset"); 828 } 829 } 830 831 /** 832 * Set 32-bit unsigned int at the given byteOffset 833 * 834 * @param self DataView object 835 * @param byteOffset byte offset to write at 836 * @param value int value to set 837 * @return undefined 838 */ 839 @SpecializedFunction 840 public static Object setUint32(final Object self, final int byteOffset, final long value) { 841 try { 842 getBuffer(self, false).putInt(byteOffset, (int)value); 843 return UNDEFINED; 844 } catch (final IndexOutOfBoundsException ioe) { 845 throw rangeError(ioe, "dataview.offset"); 846 } 847 } 848 849 /** 850 * Set 32-bit unsigned int at the given byteOffset 851 * 852 * @param self DataView object 853 * @param byteOffset byte offset to write at 854 * @param value int value to set 855 * @param littleEndian (optional) flag indicating whether to write in little endian order 856 * @return undefined 857 */ 858 @SpecializedFunction 859 public static Object setUint32(final Object self, final int byteOffset, final long value, final boolean littleEndian) { 860 try { 861 getBuffer(self, littleEndian).putInt(byteOffset, (int)value); 862 return UNDEFINED; 863 } catch (final IndexOutOfBoundsException ioe) { 864 throw rangeError(ioe, "dataview.offset"); 865 } 866 } 867 868 /** 869 * Set 32-bit float at the given byteOffset 870 * 871 * @param self DataView object 872 * @param byteOffset byte offset to write at 873 * @param value float value to set 874 * @param littleEndian (optional) flag indicating whether to write in little endian order 875 * @return undefined 876 */ 877 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 878 public static Object setFloat32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 879 try { 880 getBuffer(self, littleEndian).putFloat((int)JSType.toUint32(byteOffset), (float)JSType.toNumber(value)); 881 return UNDEFINED; 882 } catch (final IndexOutOfBoundsException ioe) { 883 throw rangeError(ioe, "dataview.offset"); 884 } 885 } 886 887 /** 888 * Set 32-bit float at the given byteOffset 889 * 890 * @param self DataView object 891 * @param byteOffset byte offset to write at 892 * @param value float value to set 893 * @return undefined 894 */ 895 @SpecializedFunction 896 public static Object setFloat32(final Object self, final int byteOffset, final double value) { 897 try { 898 getBuffer(self, false).putFloat(byteOffset, (float)value); 899 return UNDEFINED; 900 } catch (final IndexOutOfBoundsException ioe) { 901 throw rangeError(ioe, "dataview.offset"); 902 } 903 } 904 905 /** 906 * Set 32-bit float at the given byteOffset 907 * 908 * @param self DataView object 909 * @param byteOffset byte offset to write at 910 * @param value float value to set 911 * @param littleEndian (optional) flag indicating whether to write in little endian order 912 * @return undefined 913 */ 914 @SpecializedFunction 915 public static Object setFloat32(final Object self, final int byteOffset, final double value, final boolean littleEndian) { 916 try { 917 getBuffer(self, littleEndian).putFloat(byteOffset, (float)value); 918 return UNDEFINED; 919 } catch (final IndexOutOfBoundsException ioe) { 920 throw rangeError(ioe, "dataview.offset"); 921 } 922 } 923 924 /** 925 * Set 64-bit float at the given byteOffset 926 * 927 * @param self DataView object 928 * @param byteOffset byte offset to write at 929 * @param value double value to set 930 * @param littleEndian (optional) flag indicating whether to write in little endian order 931 * @return undefined 932 */ 933 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 934 public static Object setFloat64(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { 935 try { 936 getBuffer(self, littleEndian).putDouble((int)JSType.toUint32(byteOffset), JSType.toNumber(value)); 937 return UNDEFINED; 938 } catch (final IndexOutOfBoundsException ioe) { 939 throw rangeError(ioe, "dataview.offset"); 940 } 941 } 942 943 /** 944 * Set 64-bit float at the given byteOffset 945 * 946 * @param self DataView object 947 * @param byteOffset byte offset to write at 948 * @param value double value to set 949 * @return undefined 950 */ 951 @SpecializedFunction 952 public static Object setFloat64(final Object self, final int byteOffset, final double value) { 953 try { 954 getBuffer(self, false).putDouble(byteOffset, value); 955 return UNDEFINED; 956 } catch (final IndexOutOfBoundsException ioe) { 957 throw rangeError(ioe, "dataview.offset"); 958 } 959 } 960 961 /** 962 * Set 64-bit float at the given byteOffset 963 * 964 * @param self DataView object 965 * @param byteOffset byte offset to write at 966 * @param value double value to set 967 * @param littleEndian (optional) flag indicating whether to write in little endian order 968 * @return undefined 969 */ 970 @SpecializedFunction 971 public static Object setFloat64(final Object self, final int byteOffset, final double value, final boolean littleEndian) { 972 try { 973 getBuffer(self, littleEndian).putDouble(byteOffset, value); 974 return UNDEFINED; 975 } catch (final IndexOutOfBoundsException ioe) { 976 throw rangeError(ioe, "dataview.offset"); 977 } 978 } 979 980 // internals only below this point 981 private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset) { 982 try { 983 return nab.getBuffer(offset); 984 } catch (final IndexOutOfBoundsException ioe) { 985 throw rangeError(ioe, "dataview.constructor.offset"); 986 } 987 } 988 989 private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset, final int length) { 990 try { 991 return nab.getBuffer(offset, length); 992 } catch (final IndexOutOfBoundsException ioe) { 993 throw rangeError(ioe, "dataview.constructor.offset"); 994 } 995 } 996 997 private static NativeDataView checkSelf(final Object self) { 998 if (!(self instanceof NativeDataView)) { 999 throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self)); 1000 } 1001 return (NativeDataView)self; 1002 } 1003 1004 private static ByteBuffer getBuffer(final Object self) { 1005 return checkSelf(self).buf; 1006 } 1007 1008 private static ByteBuffer getBuffer(final Object self, final Object littleEndian) { 1009 return getBuffer(self, JSType.toBoolean(littleEndian)); 1010 } 1011 1012 private static ByteBuffer getBuffer(final Object self, final boolean littleEndian) { 1013 return getBuffer(self).order(littleEndian? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); 1014 } 1015 }