1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use dom::bindings::codegen::Bindings::TextDecoderBinding;
6 use dom::bindings::codegen::Bindings::TextDecoderBinding::TextDecoderMethods;
7 use dom::bindings::error::{Error, Fallible};
8 use dom::bindings::reflector::{Reflector, reflect_dom_object};
9 use dom::bindings::root::DomRoot;
10 use dom::bindings::str::{DOMString, USVString};
11 use dom::globalscope::GlobalScope;
12 use dom_struct::dom_struct;
13 use encoding_rs::Encoding;
14 use js::jsapi::{JSContext, JSObject};
15 use std::borrow::ToOwned;
16 
17 #[dom_struct]
18 pub struct TextDecoder {
19     reflector_: Reflector,
20     encoding: &'static Encoding,
21     fatal: bool,
22 }
23 
24 impl TextDecoder {
new_inherited(encoding: &'static Encoding, fatal: bool) -> TextDecoder25     fn new_inherited(encoding: &'static Encoding, fatal: bool) -> TextDecoder {
26         TextDecoder {
27             reflector_: Reflector::new(),
28             encoding: encoding,
29             fatal: fatal,
30         }
31     }
32 
make_range_error() -> Fallible<DomRoot<TextDecoder>>33     fn make_range_error() -> Fallible<DomRoot<TextDecoder>> {
34         Err(Error::Range("The given encoding is not supported.".to_owned()))
35     }
36 
new(global: &GlobalScope, encoding: &'static Encoding, fatal: bool) -> DomRoot<TextDecoder>37     pub fn new(global: &GlobalScope, encoding: &'static Encoding, fatal: bool) -> DomRoot<TextDecoder> {
38         reflect_dom_object(Box::new(TextDecoder::new_inherited(encoding, fatal)),
39                            global,
40                            TextDecoderBinding::Wrap)
41     }
42 
43     /// <https://encoding.spec.whatwg.org/#dom-textdecoder>
Constructor(global: &GlobalScope, label: DOMString, options: &TextDecoderBinding::TextDecoderOptions) -> Fallible<DomRoot<TextDecoder>>44     pub fn Constructor(global: &GlobalScope,
45                        label: DOMString,
46                        options: &TextDecoderBinding::TextDecoderOptions)
47                             -> Fallible<DomRoot<TextDecoder>> {
48         let encoding = match Encoding::for_label_no_replacement(label.as_bytes()) {
49             None => return TextDecoder::make_range_error(),
50             Some(enc) => enc
51         };
52         Ok(TextDecoder::new(global, encoding, options.fatal))
53     }
54 }
55 
56 
57 impl TextDecoderMethods for TextDecoder {
58     // https://encoding.spec.whatwg.org/#dom-textdecoder-encoding
Encoding(&self) -> DOMString59     fn Encoding(&self) -> DOMString {
60         DOMString::from(self.encoding.name().to_ascii_lowercase())
61     }
62 
63     // https://encoding.spec.whatwg.org/#dom-textdecoder-fatal
Fatal(&self) -> bool64     fn Fatal(&self) -> bool {
65         self.fatal
66     }
67 
68     #[allow(unsafe_code)]
69     // https://encoding.spec.whatwg.org/#dom-textdecoder-decode
Decode(&self, _cx: *mut JSContext, input: Option<*mut JSObject>) -> Fallible<USVString>70     unsafe fn Decode(&self, _cx: *mut JSContext, input: Option<*mut JSObject>)
71               -> Fallible<USVString> {
72         let input = match input {
73             Some(input) => input,
74             None => return Ok(USVString("".to_owned())),
75         };
76 
77         typedarray!(in(_cx) let data_res: ArrayBufferView = input);
78         let mut data = match data_res {
79             Ok(data) => data,
80             Err(_)   => {
81                 return Err(Error::Type("Argument to TextDecoder.decode is not an ArrayBufferView".to_owned()));
82             }
83         };
84 
85         let s = if self.fatal {
86             match self.encoding.decode_without_bom_handling_and_without_replacement(data.as_slice()) {
87                 Some(s) => s,
88                 None => return Err(Error::Type("Decoding failed".to_owned())),
89             }
90         } else {
91             let (s, _has_errors) = self.encoding.decode_without_bom_handling(data.as_slice());
92             s
93         };
94         Ok(USVString(s.into_owned()))
95     }
96 }
97