runtime/globals/encoding/
decoder.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use encoding_rs::{Decoder, DecoderResult, Encoding, UTF_8};
8use ion::class::Reflector;
9use ion::function::Opt;
10use ion::{Error, ErrorKind, FromValue, Result, js_class};
11
12use crate::globals::file::BufferSource;
13
14#[derive(Default, FromValue)]
15pub struct TextDecoderOptions {
16	#[ion(default)]
17	fatal: bool,
18	#[ion(default, name = "ignoreBOM")]
19	ignore_byte_order_mark: bool,
20}
21
22#[derive(Default, FromValue)]
23pub struct TextDecodeOptions {
24	#[ion(default)]
25	stream: bool,
26}
27
28#[js_class]
29pub struct TextDecoder {
30	reflector: Reflector,
31	#[trace(no_trace)]
32	decoder: Decoder,
33	pub fatal: bool,
34	pub ignore_byte_order_mark: bool,
35}
36
37#[js_class]
38impl TextDecoder {
39	#[ion(constructor)]
40	pub fn constructor(Opt(label): Opt<String>, Opt(options): Opt<TextDecoderOptions>) -> Result<TextDecoder> {
41		let encoding;
42		if let Some(label) = label {
43			let enc = Encoding::for_label_no_replacement(label.as_bytes());
44			match enc {
45				None => {
46					return Err(Error::new(
47						format!("The given encoding '{label}' is not supported."),
48						ErrorKind::Range,
49					));
50				}
51				Some(enc) => encoding = enc,
52			}
53		} else {
54			encoding = UTF_8;
55		}
56
57		let options = options.unwrap_or_default();
58		let decoder = if options.ignore_byte_order_mark {
59			encoding.new_decoder_without_bom_handling()
60		} else {
61			encoding.new_decoder()
62		};
63
64		Ok(TextDecoder {
65			reflector: Reflector::default(),
66			decoder,
67			fatal: options.fatal,
68			ignore_byte_order_mark: options.ignore_byte_order_mark,
69		})
70	}
71
72	pub fn decode(
73		&mut self, #[ion(convert = true)] buffer: BufferSource, Opt(options): Opt<TextDecodeOptions>,
74	) -> Result<String> {
75		let mut string = String::with_capacity(self.decoder.max_utf8_buffer_length(buffer.len()).unwrap());
76		let stream = options.unwrap_or_default().stream;
77		if self.fatal {
78			let vec_buffer;
79			let buffer = if buffer.is_shared() {
80				vec_buffer = buffer.to_vec();
81				&vec_buffer
82			} else {
83				unsafe { buffer.as_slice() }
84			};
85
86			let (result, _) = self.decoder.decode_to_string_without_replacement(buffer, &mut string, !stream);
87			if let DecoderResult::Malformed(_, _) = result {
88				return Err(Error::new("TextDecoder.decode: Decoding Failed", ErrorKind::Type));
89			}
90		} else {
91			let (_, _, _) = self.decoder.decode_to_string(unsafe { buffer.as_slice() }, &mut string, !stream);
92		}
93		Ok(string)
94	}
95
96	#[ion(get)]
97	pub fn get_encoding(&self) -> String {
98		String::from(self.decoder.encoding().name())
99	}
100
101	#[ion(get)]
102	pub fn get_fatal(&self) -> bool {
103		self.fatal
104	}
105
106	#[ion(get, name = "ignoreBOM")]
107	pub fn get_ignore_bom(&self) -> bool {
108		self.ignore_byte_order_mark
109	}
110}