IDLAbstractOperations.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  3. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/ByteBuffer.h>
  8. #include <AK/NumericLimits.h>
  9. #include <LibJS/Runtime/AbstractOperations.h>
  10. #include <LibJS/Runtime/ArrayBuffer.h>
  11. #include <LibJS/Runtime/DataView.h>
  12. #include <LibJS/Runtime/PropertyKey.h>
  13. #include <LibJS/Runtime/TypedArray.h>
  14. #include <LibWeb/Bindings/IDLAbstractOperations.h>
  15. namespace Web::Bindings::IDL {
  16. // https://webidl.spec.whatwg.org/#is-an-array-index
  17. bool is_an_array_index(JS::GlobalObject& global_object, JS::PropertyKey const& property_name)
  18. {
  19. // 1. If Type(P) is not String, then return false.
  20. if (!property_name.is_number())
  21. return false;
  22. // 2. Let index be ! CanonicalNumericIndexString(P).
  23. auto index = JS::canonical_numeric_index_string(global_object, property_name);
  24. // 3. If index is undefined, then return false.
  25. if (index.is_undefined())
  26. return false;
  27. // 4. If IsInteger(index) is false, then return false.
  28. // NOTE: IsInteger is the old name of IsIntegralNumber.
  29. if (!index.is_integral_number())
  30. return false;
  31. // 5. If index is −0, then return false.
  32. if (index.is_negative_zero())
  33. return false;
  34. // FIXME: I'm not sure if this is correct.
  35. auto index_as_double = index.as_double();
  36. // 6. If index < 0, then return false.
  37. if (index_as_double < 0)
  38. return false;
  39. // 7. If index ≥ 2 ** 32 − 1, then return false.
  40. // Note: 2 ** 32 − 1 is the maximum array length allowed by ECMAScript.
  41. if (index_as_double >= NumericLimits<u32>::max())
  42. return false;
  43. // 8. Return true.
  44. return true;
  45. }
  46. // https://webidl.spec.whatwg.org/#dfn-get-buffer-source-copy
  47. Optional<ByteBuffer> get_buffer_source_copy(JS::Object const& buffer_source)
  48. {
  49. // 1. Let esBufferSource be the result of converting bufferSource to an ECMAScript value.
  50. // 2. Let esArrayBuffer be esBufferSource.
  51. JS::ArrayBuffer* es_array_buffer;
  52. // 3. Let offset be 0.
  53. u32 offset = 0;
  54. // 4. Let length be 0.
  55. u32 length = 0;
  56. // 5. If esBufferSource has a [[ViewedArrayBuffer]] internal slot, then:
  57. if (is<JS::TypedArrayBase>(buffer_source)) {
  58. auto const& es_buffer_source = static_cast<JS::TypedArrayBase const&>(buffer_source);
  59. // 1. Set esArrayBuffer to esBufferSource.[[ViewedArrayBuffer]].
  60. es_array_buffer = es_buffer_source.viewed_array_buffer();
  61. // 2. Set offset to esBufferSource.[[ByteOffset]].
  62. offset = es_buffer_source.byte_offset();
  63. // 3. Set length to esBufferSource.[[ByteLength]].
  64. length = es_buffer_source.byte_length();
  65. } else if (is<JS::DataView>(buffer_source)) {
  66. auto const& es_buffer_source = static_cast<JS::DataView const&>(buffer_source);
  67. // 1. Set esArrayBuffer to esBufferSource.[[ViewedArrayBuffer]].
  68. es_array_buffer = es_buffer_source.viewed_array_buffer();
  69. // 2. Set offset to esBufferSource.[[ByteOffset]].
  70. offset = es_buffer_source.byte_offset();
  71. // 3. Set length to esBufferSource.[[ByteLength]].
  72. length = es_buffer_source.byte_length();
  73. }
  74. // 6. Otherwise:
  75. else {
  76. // 1. Assert: esBufferSource is an ArrayBuffer or SharedArrayBuffer object.
  77. auto const& es_buffer_source = static_cast<JS::ArrayBuffer const&>(buffer_source);
  78. es_array_buffer = &const_cast<JS ::ArrayBuffer&>(es_buffer_source);
  79. // 2. Set length to esBufferSource.[[ArrayBufferByteLength]].
  80. length = es_buffer_source.byte_length();
  81. }
  82. // 7. If ! IsDetachedBuffer(esArrayBuffer) is true, then return the empty byte sequence.
  83. if (es_array_buffer->is_detached())
  84. return ByteBuffer {};
  85. // 8. Let bytes be a new byte sequence of length equal to length.
  86. auto bytes = ByteBuffer::create_zeroed(length);
  87. if (!bytes.has_value())
  88. return {};
  89. // 9. For i in the range offset to offset + length − 1, inclusive, set bytes[i − offset] to ! GetValueFromBuffer(esArrayBuffer, i, Uint8, true, Unordered).
  90. for (u64 i = offset; i <= offset + length - 1; ++i) {
  91. auto value = es_array_buffer->get_value<u8>(i, true, JS::ArrayBuffer::Unordered);
  92. (*bytes)[i - offset] = (u8)value.as_u32();
  93. }
  94. // 10. Return bytes.
  95. return bytes;
  96. }
  97. }