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