runtime/globals/encoding/
decoder.rs1use 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}