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.charset.Charset;
18 import java.util.Arrays;
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 @JsxClass
39 public class TextDecoder extends HtmlUnitScriptable {
40 private String whatwgEncoding_ = "utf-8";
41
42
43
44
45
46 @JsxConstructor
47 public void jsConstructor(final Object encodingLabel) {
48 if (JavaScriptEngine.isUndefined(encodingLabel)) {
49 return;
50 }
51
52 String enc = JavaScriptEngine.toString(encodingLabel);
53 enc = enc.trim().toLowerCase(Locale.ROOT);
54 final String whatwgEncoding = StandardEncodingTranslator.ENCODING_FROM_LABEL.get(enc);
55
56 if (whatwgEncoding == null
57 || StandardEncodingTranslator.REPLACEMENT.equalsIgnoreCase(whatwgEncoding)) {
58 throw JavaScriptEngine.rangeError("Failed to construct 'TextDecoder': The encoding label provided ('"
59 + encodingLabel + "') is invalid.");
60 }
61
62 whatwgEncoding_ = whatwgEncoding;
63 }
64
65
66
67
68 @JsxGetter
69 public String getEncoding() {
70 return whatwgEncoding_;
71 }
72
73
74
75
76
77 @JsxFunction
78 public String decode(final Object buffer) {
79 if (JavaScriptEngine.isUndefined(buffer)) {
80 return "";
81 }
82
83 if (buffer instanceof NativeArrayBuffer) {
84 return new String(((NativeArrayBuffer) buffer).getBuffer(), getEncoding(whatwgEncoding_));
85 }
86
87 if (buffer instanceof NativeArrayBufferView) {
88 final NativeArrayBufferView arrayBufferView = (NativeArrayBufferView) buffer;
89 final NativeArrayBuffer arrayBuffer = arrayBufferView.getBuffer();
90 if (arrayBuffer != null) {
91 final int byteLength = arrayBufferView.getByteLength();
92 final int byteOffset = arrayBufferView.getByteOffset();
93 final byte[] backedBytes = arrayBuffer.getBuffer();
94 final byte[] bytes = Arrays.copyOfRange(backedBytes, byteOffset, byteOffset + byteLength);
95 return new String(bytes, getEncoding(whatwgEncoding_));
96 }
97 }
98
99 throw JavaScriptEngine.typeError("Argument 1 of TextDecoder.decode could not be"
100 + " converted to any of: ArrayBufferView, ArrayBuffer.");
101 }
102
103 private Charset getEncoding(final String encodingLabel) {
104 if (XUserDefinedCharset.NAME.equalsIgnoreCase(encodingLabel)) {
105 return XUserDefinedCharset.INSTANCE;
106 }
107
108 final String ianaEncoding = StandardEncodingTranslator
109 .ENCODING_TO_IANA_ENCODING.getOrDefault(encodingLabel, encodingLabel);
110
111 final String javaEncoding = StandardEncodingTranslator
112 .IANA_TO_JAVA_ENCODINGS.getOrDefault(ianaEncoding, ianaEncoding);
113
114 return Charset.forName(javaEncoding);
115 }
116 }