1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host;
16
17 import java.nio.ByteBuffer;
18 import java.nio.charset.Charset;
19 import java.util.Locale;
20
21 import org.htmlunit.corejs.javascript.typedarrays.NativeArrayBuffer;
22 import org.htmlunit.corejs.javascript.typedarrays.NativeArrayBufferView;
23 import org.htmlunit.cyberneko.xerces.util.StandardEncodingTranslator;
24 import org.htmlunit.javascript.HtmlUnitScriptable;
25 import org.htmlunit.javascript.JavaScriptEngine;
26 import org.htmlunit.javascript.configuration.JsxClass;
27 import org.htmlunit.javascript.configuration.JsxConstructor;
28 import org.htmlunit.javascript.configuration.JsxFunction;
29 import org.htmlunit.javascript.configuration.JsxGetter;
30 import org.htmlunit.util.XUserDefinedCharset;
31
32
33
34
35
36
37
38
39
40 @JsxClass
41 public class TextDecoder extends HtmlUnitScriptable {
42 private String whatwgEncoding_ = "utf-8";
43
44
45
46
47
48
49 @JsxConstructor
50 public void jsConstructor(final Object encodingLabel) {
51 if (JavaScriptEngine.isUndefined(encodingLabel)) {
52 return;
53 }
54
55 String enc = JavaScriptEngine.toString(encodingLabel);
56 enc = enc.trim().toLowerCase(Locale.ROOT);
57 final String whatwgEncoding = StandardEncodingTranslator.ENCODING_FROM_LABEL.get(enc);
58
59 if (whatwgEncoding == null
60 || StandardEncodingTranslator.REPLACEMENT.equalsIgnoreCase(whatwgEncoding)) {
61 throw JavaScriptEngine.rangeError("Failed to construct 'TextDecoder': The encoding label provided ('"
62 + encodingLabel + "') is invalid.");
63 }
64
65 whatwgEncoding_ = whatwgEncoding;
66 }
67
68
69
70
71
72
73 @JsxGetter
74 public String getEncoding() {
75 return whatwgEncoding_;
76 }
77
78
79
80
81
82
83
84 @JsxFunction
85 public String decode(final Object buffer) {
86 if (JavaScriptEngine.isUndefined(buffer)) {
87 return "";
88 }
89
90 final Charset charset = getEncoding(whatwgEncoding_);
91
92 if (buffer instanceof NativeArrayBuffer arrayBuffer) {
93 return charset.decode(arrayBuffer.getByteBuffer()).toString();
94 }
95
96 if (buffer instanceof NativeArrayBufferView arrayBufferView) {
97 final NativeArrayBuffer arrayBuffer = arrayBufferView.getBuffer();
98 if (arrayBuffer != null) {
99 final ByteBuffer bb = arrayBuffer.getByteBuffer();
100 bb.position(arrayBufferView.getByteOffset());
101 bb.limit(arrayBufferView.getByteOffset() + arrayBufferView.getByteLength());
102 return charset.decode(bb).toString();
103 }
104 }
105
106 throw JavaScriptEngine.typeError("Argument 1 of TextDecoder.decode could not be"
107 + " converted to any of: ArrayBufferView, ArrayBuffer.");
108 }
109
110 private Charset getEncoding(final String encodingLabel) {
111 if (XUserDefinedCharset.NAME.equalsIgnoreCase(encodingLabel)) {
112 return XUserDefinedCharset.INSTANCE;
113 }
114
115 final String ianaEncoding = StandardEncodingTranslator
116 .ENCODING_TO_IANA_ENCODING.getOrDefault(encodingLabel, encodingLabel);
117
118 final String javaEncoding = StandardEncodingTranslator
119 .IANA_TO_JAVA_ENCODINGS.getOrDefault(ianaEncoding, ianaEncoding);
120
121 return Charset.forName(javaEncoding);
122 }
123 }