/src/serenity/Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibJS/Runtime/TypedArray.h> |
8 | | #include <LibWeb/Bindings/Intrinsics.h> |
9 | | #include <LibWeb/Bindings/TextEncoderPrototype.h> |
10 | | #include <LibWeb/Encoding/TextEncoder.h> |
11 | | #include <LibWeb/WebIDL/ExceptionOr.h> |
12 | | |
13 | | namespace Web::Encoding { |
14 | | |
15 | | JS_DEFINE_ALLOCATOR(TextEncoder); |
16 | | |
17 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<TextEncoder>> TextEncoder::construct_impl(JS::Realm& realm) |
18 | 0 | { |
19 | 0 | return realm.heap().allocate<TextEncoder>(realm, realm); |
20 | 0 | } |
21 | | |
22 | | TextEncoder::TextEncoder(JS::Realm& realm) |
23 | 0 | : PlatformObject(realm) |
24 | 0 | { |
25 | 0 | } |
26 | | |
27 | 0 | TextEncoder::~TextEncoder() = default; |
28 | | |
29 | | void TextEncoder::initialize(JS::Realm& realm) |
30 | 0 | { |
31 | 0 | Base::initialize(realm); |
32 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(TextEncoder); |
33 | 0 | } |
34 | | |
35 | | // https://encoding.spec.whatwg.org/#dom-textencoder-encode |
36 | | JS::NonnullGCPtr<JS::Uint8Array> TextEncoder::encode(String const& input) const |
37 | 0 | { |
38 | | // NOTE: The AK::String is always UTF-8, so most of these steps are no-ops. |
39 | | // 1. Convert input to an I/O queue of scalar values. |
40 | | // 2. Let output be the I/O queue of bytes « end-of-queue ». |
41 | | // 3. While true: |
42 | | // 1. Let item be the result of reading from input. |
43 | | // 2. Let result be the result of processing an item with item, an instance of the UTF-8 encoder, input, output, and "fatal". |
44 | | // 3. Assert: result is not an error. |
45 | | // 4. If result is finished, then convert output into a byte sequence and return a Uint8Array object wrapping an ArrayBuffer containing output. |
46 | |
|
47 | 0 | auto byte_buffer = MUST(ByteBuffer::copy(input.bytes())); |
48 | 0 | auto array_length = byte_buffer.size(); |
49 | 0 | auto array_buffer = JS::ArrayBuffer::create(realm(), move(byte_buffer)); |
50 | 0 | return JS::Uint8Array::create(realm(), array_length, *array_buffer); |
51 | 0 | } |
52 | | |
53 | | // https://encoding.spec.whatwg.org/#dom-textencoder-encodeinto |
54 | | TextEncoderEncodeIntoResult TextEncoder::encode_into(String const& source, JS::Handle<WebIDL::BufferSource> const& destination) const |
55 | 0 | { |
56 | 0 | auto& data = destination->viewed_array_buffer()->buffer(); |
57 | | |
58 | | // 1. Let read be 0. |
59 | 0 | WebIDL::UnsignedLongLong read = 0; |
60 | | // 2. Let written be 0. |
61 | 0 | WebIDL::UnsignedLongLong written = 0; |
62 | | |
63 | | // NOTE: The AK::String is always UTF-8, so most of these steps are no-ops. |
64 | | // 3. Let encoder be an instance of the UTF-8 encoder. |
65 | | // 4. Let unused be the I/O queue of scalar values « end-of-queue ». |
66 | | // 5. Convert source to an I/O queue of scalar values. |
67 | 0 | auto code_points = source.code_points(); |
68 | 0 | auto it = code_points.begin(); |
69 | | |
70 | | // 6. While true: |
71 | 0 | while (true) { |
72 | | // 6.1. Let item be the result of reading from source. |
73 | | // 6.2. Let result be the result of running encoder’s handler on unused and item. |
74 | | // 6.3. If result is finished, then break. |
75 | 0 | if (it.done()) |
76 | 0 | break; |
77 | 0 | auto item = *it; |
78 | 0 | auto result = it.underlying_code_point_bytes(); |
79 | | |
80 | | // 6.4. Otherwise: |
81 | | // 6.4.1. If destination’s byte length − written is greater than or equal to the number of bytes in result, then: |
82 | 0 | if (data.size() - written >= result.size()) { |
83 | | // 6.4.1.1. If item is greater than U+FFFF, then increment read by 2. |
84 | 0 | if (item > 0xffff) { |
85 | 0 | read += 2; |
86 | 0 | } |
87 | | // 6.4.1.2. Otherwise, increment read by 1. |
88 | 0 | else { |
89 | 0 | read++; |
90 | 0 | } |
91 | | |
92 | | // 6.4.1.3. Write the bytes in result into destination, with startingOffset set to written. |
93 | | // 6.4.1.4. Increment written by the number of bytes in result. |
94 | 0 | for (auto byte : result) |
95 | 0 | data[written++] = byte; |
96 | 0 | } |
97 | | // 6.4.2. Otherwise, break. |
98 | 0 | else { |
99 | 0 | break; |
100 | 0 | } |
101 | | |
102 | 0 | ++it; |
103 | 0 | } |
104 | | |
105 | | // 7. Return «[ "read" → read, "written" → written ]». |
106 | 0 | return { read, written }; |
107 | 0 | } |
108 | | |
109 | | // https://encoding.spec.whatwg.org/#dom-textencoder-encoding |
110 | | FlyString const& TextEncoder::encoding() |
111 | 0 | { |
112 | 0 | static FlyString const encoding = "utf-8"_fly_string; |
113 | 0 | return encoding; |
114 | 0 | } |
115 | | |
116 | | } |