/src/serenity/Userland/Libraries/LibJS/Runtime/DataViewConstructor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Checked.h> |
8 | | #include <AK/TypeCasts.h> |
9 | | #include <LibJS/Runtime/AbstractOperations.h> |
10 | | #include <LibJS/Runtime/DataView.h> |
11 | | #include <LibJS/Runtime/DataViewConstructor.h> |
12 | | #include <LibJS/Runtime/Error.h> |
13 | | #include <LibJS/Runtime/GlobalObject.h> |
14 | | |
15 | | namespace JS { |
16 | | |
17 | | JS_DEFINE_ALLOCATOR(DataViewConstructor); |
18 | | |
19 | | DataViewConstructor::DataViewConstructor(Realm& realm) |
20 | 0 | : NativeFunction(realm.vm().names.DataView.as_string(), realm.intrinsics().function_prototype()) |
21 | 0 | { |
22 | 0 | } |
23 | | |
24 | | void DataViewConstructor::initialize(Realm& realm) |
25 | 0 | { |
26 | 0 | auto& vm = this->vm(); |
27 | 0 | Base::initialize(realm); |
28 | | |
29 | | // 25.3.3.1 DataView.prototype, https://tc39.es/ecma262/#sec-dataview.prototype |
30 | 0 | define_direct_property(vm.names.prototype, realm.intrinsics().data_view_prototype(), 0); |
31 | |
|
32 | 0 | define_direct_property(vm.names.length, Value(1), Attribute::Configurable); |
33 | 0 | } |
34 | | |
35 | | // 25.3.2.1 DataView ( buffer [ , byteOffset [ , byteLength ] ] ), https://tc39.es/ecma262/#sec-dataview-buffer-byteoffset-bytelength |
36 | | ThrowCompletionOr<Value> DataViewConstructor::call() |
37 | 0 | { |
38 | 0 | auto& vm = this->vm(); |
39 | | |
40 | | // 1. If NewTarget is undefined, throw a TypeError exception. |
41 | 0 | return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, vm.names.DataView); |
42 | 0 | } |
43 | | |
44 | | // 25.3.2.1 DataView ( buffer [ , byteOffset [ , byteLength ] ] ), https://tc39.es/ecma262/#sec-dataview-buffer-byteoffset-bytelength |
45 | | ThrowCompletionOr<NonnullGCPtr<Object>> DataViewConstructor::construct(FunctionObject& new_target) |
46 | 0 | { |
47 | 0 | auto& vm = this->vm(); |
48 | |
|
49 | 0 | auto buffer = vm.argument(0); |
50 | 0 | auto byte_offset = vm.argument(1); |
51 | 0 | auto byte_length = vm.argument(2); |
52 | | |
53 | | // 2. Perform ? RequireInternalSlot(buffer, [[ArrayBufferData]]). |
54 | 0 | if (!buffer.is_object() || !is<ArrayBuffer>(buffer.as_object())) |
55 | 0 | return vm.throw_completion<TypeError>(ErrorType::IsNotAn, buffer.to_string_without_side_effects(), vm.names.ArrayBuffer); |
56 | | |
57 | 0 | auto& array_buffer = static_cast<ArrayBuffer&>(buffer.as_object()); |
58 | | |
59 | | // 3. Let offset be ? ToIndex(byteOffset). |
60 | 0 | auto offset = TRY(byte_offset.to_index(vm)); |
61 | | |
62 | | // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. |
63 | 0 | if (array_buffer.is_detached()) |
64 | 0 | return vm.throw_completion<TypeError>(ErrorType::DetachedArrayBuffer); |
65 | | |
66 | | // 5. Let bufferByteLength be ArrayBufferByteLength(buffer, seq-cst). |
67 | 0 | auto buffer_byte_length = array_buffer_byte_length(array_buffer, ArrayBuffer::Order::SeqCst); |
68 | | |
69 | | // 6. If offset > bufferByteLength, throw a RangeError exception. |
70 | 0 | if (offset > buffer_byte_length) |
71 | 0 | return vm.throw_completion<RangeError>(ErrorType::DataViewOutOfRangeByteOffset, offset, buffer_byte_length); |
72 | | |
73 | | // 7. Let bufferIsFixedLength be IsFixedLengthArrayBuffer(buffer). |
74 | 0 | auto buffer_is_fixed_length = array_buffer.is_fixed_length(); |
75 | |
|
76 | 0 | ByteLength view_byte_length { 0 }; |
77 | | |
78 | | // 8. If byteLength is undefined, then |
79 | 0 | if (byte_length.is_undefined()) { |
80 | | // a. If bufferIsFixedLength is true, then |
81 | 0 | if (buffer_is_fixed_length) { |
82 | | // i. Let viewByteLength be bufferByteLength - offset. |
83 | 0 | view_byte_length = buffer_byte_length - offset; |
84 | 0 | } |
85 | | // b. Else, |
86 | 0 | else { |
87 | | // i. Let viewByteLength be auto. |
88 | 0 | view_byte_length = ByteLength::auto_(); |
89 | 0 | } |
90 | 0 | } |
91 | | // 9. Else, |
92 | 0 | else { |
93 | | // a. Let viewByteLength be ? ToIndex(byteLength). |
94 | 0 | view_byte_length = TRY(byte_length.to_index(vm)); |
95 | | |
96 | | // b. If offset + viewByteLength > bufferByteLength, throw a RangeError exception. |
97 | 0 | auto checked_add = AK::make_checked(offset) + AK::make_checked(static_cast<size_t>(view_byte_length.length())); |
98 | |
|
99 | 0 | if (checked_add.has_overflow() || checked_add.value() > buffer_byte_length) |
100 | 0 | return vm.throw_completion<RangeError>(ErrorType::InvalidLength, vm.names.DataView); |
101 | 0 | } |
102 | | |
103 | | // 10. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataView.prototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »). |
104 | 0 | auto data_view = TRY(ordinary_create_from_constructor<DataView>(vm, new_target, &Intrinsics::data_view_prototype, &array_buffer, move(view_byte_length), offset)); |
105 | | |
106 | | // 11. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. |
107 | 0 | if (array_buffer.is_detached()) |
108 | 0 | return vm.throw_completion<TypeError>(ErrorType::DetachedArrayBuffer); |
109 | | |
110 | | // 12. Set bufferByteLength to ArrayBufferByteLength(buffer, seq-cst). |
111 | 0 | buffer_byte_length = array_buffer_byte_length(array_buffer, ArrayBuffer::Order::SeqCst); |
112 | | |
113 | | // 13. If offset > bufferByteLength, throw a RangeError exception. |
114 | 0 | if (offset > buffer_byte_length) |
115 | 0 | return vm.throw_completion<RangeError>(ErrorType::DataViewOutOfRangeByteOffset, offset, buffer_byte_length); |
116 | | |
117 | | // 14. If byteLength is not undefined, then |
118 | 0 | if (!byte_length.is_undefined()) { |
119 | | // a. If offset + viewByteLength > bufferByteLength, throw a RangeError exception. |
120 | 0 | auto checked_add = AK::make_checked(offset) + AK::make_checked(static_cast<size_t>(view_byte_length.length())); |
121 | |
|
122 | 0 | if (checked_add.has_overflow() || checked_add.value() > buffer_byte_length) |
123 | 0 | return vm.throw_completion<RangeError>(ErrorType::InvalidLength, vm.names.DataView); |
124 | 0 | } |
125 | | |
126 | | // 15. Set O.[[ViewedArrayBuffer]] to buffer. |
127 | | // 16. Set O.[[ByteLength]] to viewByteLength. |
128 | | // 17. Set O.[[ByteOffset]] to offset. |
129 | | |
130 | | // 18. Return O. |
131 | 0 | return data_view; |
132 | 0 | } |
133 | | |
134 | | } |