diff options
author | Jonas Reinwald <jonas.reinwald@htwg-konstanz.de> | 2017-12-07 16:57:06 +0100 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2018-06-04 15:53:08 -0400 |
commit | 0fdafb08c8813229fb756bd0900ac54278cf1c85 (patch) | |
tree | 4571f448807c214fe50903279cf536c4e4b87f71 /components | |
parent | 3e8caa46792b552c6a7559714077d1b3d9f33194 (diff) | |
download | servo-0fdafb08c8813229fb756bd0900ac54278cf1c85.tar.gz servo-0fdafb08c8813229fb756bd0900ac54278cf1c85.zip |
Implement read methods on FileReaderSync
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/bindings/error.rs | 3 | ||||
-rw-r--r-- | components/script/dom/domexception.rs | 2 | ||||
-rw-r--r-- | components/script/dom/filereader.rs | 208 | ||||
-rw-r--r-- | components/script/dom/filereadersync.rs | 86 | ||||
-rw-r--r-- | components/script/dom/webidls/DOMException.webidl | 1 | ||||
-rw-r--r-- | components/script/dom/webidls/FileReaderSync.webidl | 12 |
6 files changed, 234 insertions, 78 deletions
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index ed46fa3a924..dee6e9766f0 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -69,6 +69,8 @@ pub enum Error { TypeMismatch, /// InvalidModificationError DOMException InvalidModification, + /// NotReadableError DOMException + NotReadable, /// TypeError JavaScript Error Type(String), @@ -110,6 +112,7 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, resu Error::QuotaExceeded => DOMErrorName::QuotaExceededError, Error::TypeMismatch => DOMErrorName::TypeMismatchError, Error::InvalidModification => DOMErrorName::InvalidModificationError, + Error::NotReadable => DOMErrorName::NotReadableError, Error::Type(message) => { assert!(!JS_IsExceptionPending(cx)); throw_type_error(cx, &message); diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs index e94689b242b..4f2c076ec66 100644 --- a/components/script/dom/domexception.rs +++ b/components/script/dom/domexception.rs @@ -35,6 +35,7 @@ pub enum DOMErrorName { TimeoutError = DOMExceptionConstants::TIMEOUT_ERR, InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR, DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR, + NotReadableError = DOMExceptionConstants::NOT_READABLE_ERR, } #[dom_struct] @@ -94,6 +95,7 @@ impl DOMExceptionMethods for DOMException { DOMErrorName::InvalidNodeTypeError => "The supplied node is incorrect or has an incorrect ancestor for this operation.", DOMErrorName::DataCloneError => "The object can not be cloned.", + DOMErrorName::NotReadableError => "The I/O read operation failed." }; DOMString::from(message) diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index 7475e4adbd6..037e54907c0 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -51,12 +51,15 @@ pub type TrustedFileReader = Trusted<FileReader>; pub struct ReadMetaData { pub blobtype: String, pub label: Option<String>, - pub function: FileReaderFunction + pub function: FileReaderFunction, } impl ReadMetaData { - pub fn new(blobtype: String, - label: Option<String>, function: FileReaderFunction) -> ReadMetaData { + pub fn new( + blobtype: String, + label: Option<String>, + function: FileReaderFunction, + ) -> ReadMetaData { ReadMetaData { blobtype: blobtype, label: label, @@ -82,6 +85,54 @@ pub enum FileReaderResult { String(DOMString), } +pub struct FileReaderSharedFunctionality; + +impl FileReaderSharedFunctionality { + pub fn dataurl_format(blob_contents: &[u8], blob_type: String) -> DOMString { + let base64 = base64::encode(&blob_contents); + + let dataurl = if blob_type.is_empty() { + format!("data:base64,{}", base64) + } else { + format!("data:{};base64,{}", blob_type, base64) + }; + + DOMString::from(dataurl) + } + + pub fn text_decode( + blob_contents: &[u8], + blob_type: &str, + blob_label: &Option<String>, + ) -> DOMString { + //https://w3c.github.io/FileAPI/#encoding-determination + // Steps 1 & 2 & 3 + let mut encoding = blob_label + .as_ref() + .map(|string| string.as_bytes()) + .and_then(Encoding::for_label); + + // Step 4 & 5 + encoding = encoding.or_else(|| { + let resultmime = blob_type.parse::<Mime>().ok(); + resultmime.and_then(|Mime(_, _, ref parameters)| { + parameters + .iter() + .find(|&&(ref k, _)| &Attr::Charset == k) + .and_then(|&(_, ref v)| Encoding::for_label(v.as_str().as_bytes())) + }) + }); + + // Step 6 + let enc = encoding.unwrap_or(UTF_8); + + let convert = blob_contents; + // Step 7 + let (output, _, _) = enc.decode(convert); + DOMString::from(output) + } +} + #[dom_struct] pub struct FileReader { eventtarget: EventTarget, @@ -103,8 +154,11 @@ impl FileReader { } pub fn new(global: &GlobalScope) -> DomRoot<FileReader> { - reflect_dom_object(Box::new(FileReader::new_inherited()), - global, FileReaderBinding::Wrap) + reflect_dom_object( + Box::new(FileReader::new_inherited()), + global, + FileReaderBinding::Wrap, + ) } pub fn Constructor(global: &GlobalScope) -> Fallible<DomRoot<FileReader>> { @@ -112,7 +166,11 @@ impl FileReader { } //https://w3c.github.io/FileAPI/#dfn-error-steps - pub fn process_read_error(filereader: TrustedFileReader, gen_id: GenerationId, error: DOMErrorName) { + pub fn process_read_error( + filereader: TrustedFileReader, + gen_id: GenerationId, + error: DOMErrorName, + ) { let fr = filereader.root(); macro_rules! return_on_abort( @@ -174,8 +232,12 @@ impl FileReader { // https://w3c.github.io/FileAPI/#dfn-readAsText #[allow(unsafe_code)] - pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId, - data: ReadMetaData, blob_contents: Arc<Vec<u8>>) { + pub fn process_read_eof( + filereader: TrustedFileReader, + gen_id: GenerationId, + data: ReadMetaData, + blob_contents: Arc<Vec<u8>>, + ) { let fr = filereader.root(); macro_rules! return_on_abort( @@ -192,13 +254,21 @@ impl FileReader { // Step 8.2 match data.function { - FileReaderFunction::ReadAsDataUrl => - FileReader::perform_readasdataurl(&fr.result, data, &blob_contents), - FileReaderFunction::ReadAsText => - FileReader::perform_readastext(&fr.result, data, &blob_contents), + FileReaderFunction::ReadAsDataUrl => { + FileReader::perform_readasdataurl(&fr.result, data, &blob_contents) + }, + FileReaderFunction::ReadAsText => { + FileReader::perform_readastext(&fr.result, data, &blob_contents) + }, FileReaderFunction::ReadAsArrayBuffer => { - let _ac = JSAutoCompartment::new(fr.global().get_cx(), *fr.reflector().get_jsobject()); - FileReader::perform_readasarraybuffer(&fr.result, fr.global().get_cx(), data, &blob_contents) + let _ac = + JSAutoCompartment::new(fr.global().get_cx(), *fr.reflector().get_jsobject()); + FileReader::perform_readasarraybuffer( + &fr.result, + fr.global().get_cx(), + data, + &blob_contents, + ) }, }; @@ -215,55 +285,43 @@ impl FileReader { } // https://w3c.github.io/FileAPI/#dfn-readAsText - fn perform_readastext(result: &DomRefCell<Option<FileReaderResult>>, data: ReadMetaData, blob_bytes: &[u8]) { + fn perform_readastext( + result: &DomRefCell<Option<FileReaderResult>>, + data: ReadMetaData, + blob_bytes: &[u8], + ) { let blob_label = &data.label; let blob_type = &data.blobtype; - //https://w3c.github.io/FileAPI/#encoding-determination - // Steps 1 & 2 & 3 - let mut encoding = blob_label.as_ref() - .map(|string| string.as_bytes()) - .and_then(Encoding::for_label); - - // Step 4 & 5 - encoding = encoding.or_else(|| { - let resultmime = blob_type.parse::<Mime>().ok(); - resultmime.and_then(|Mime(_, _, ref parameters)| { - parameters.iter() - .find(|&&(ref k, _)| &Attr::Charset == k) - .and_then(|&(_, ref v)| Encoding::for_label(v.as_str().as_bytes())) - }) - }); - - // Step 6 - let enc = encoding.unwrap_or(UTF_8); - - let convert = blob_bytes; - // Step 7 - let (output, _, _) = enc.decode(convert); - *result.borrow_mut() = Some(FileReaderResult::String(DOMString::from(output))); + let output = FileReaderSharedFunctionality::text_decode(blob_bytes, blob_type, blob_label); + *result.borrow_mut() = Some(FileReaderResult::String(output)); } //https://w3c.github.io/FileAPI/#dfn-readAsDataURL - fn perform_readasdataurl(result: &DomRefCell<Option<FileReaderResult>>, data: ReadMetaData, bytes: &[u8]) { - let base64 = base64::encode(bytes); - - let output = if data.blobtype.is_empty() { - format!("data:base64,{}", base64) - } else { - format!("data:{};base64,{}", data.blobtype, base64) - }; - - *result.borrow_mut() = Some(FileReaderResult::String(DOMString::from(output))); + fn perform_readasdataurl( + result: &DomRefCell<Option<FileReaderResult>>, + data: ReadMetaData, + bytes: &[u8], + ) { + let output = FileReaderSharedFunctionality::dataurl_format(bytes, data.blobtype); + + *result.borrow_mut() = Some(FileReaderResult::String(output)); } // https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer #[allow(unsafe_code)] - fn perform_readasarraybuffer(result: &DomRefCell<Option<FileReaderResult>>, - cx: *mut JSContext, _: ReadMetaData, bytes: &[u8]) { + fn perform_readasarraybuffer( + result: &DomRefCell<Option<FileReaderResult>>, + cx: *mut JSContext, + _: ReadMetaData, + bytes: &[u8], + ) { unsafe { rooted!(in(cx) let mut array_buffer = ptr::null_mut::<JSObject>()); - assert!(ArrayBuffer::create(cx, CreateWith::Slice(bytes), array_buffer.handle_mut()).is_ok()); + assert!( + ArrayBuffer::create(cx, CreateWith::Slice(bytes), array_buffer.handle_mut()) + .is_ok() + ); *result.borrow_mut() = Some(FileReaderResult::ArrayBuffer(Heap::default())); @@ -335,13 +393,12 @@ impl FileReaderMethods for FileReader { // https://w3c.github.io/FileAPI/#dfn-result unsafe fn GetResult(&self, _: *mut JSContext) -> Option<StringOrObject> { self.result.borrow().as_ref().map(|r| match *r { - FileReaderResult::String(ref string) => - StringOrObject::String(string.clone()), + FileReaderResult::String(ref string) => StringOrObject::String(string.clone()), FileReaderResult::ArrayBuffer(ref arr_buffer) => { let result = RootedTraceableBox::new(Heap::default()); result.set((*arr_buffer.ptr.get()).to_object()); StringOrObject::Object(result) - } + }, }) } @@ -351,12 +408,17 @@ impl FileReaderMethods for FileReader { } } - impl FileReader { fn dispatch_progress_event(&self, type_: Atom, loaded: u64, total: Option<u64>) { - let progressevent = ProgressEvent::new(&self.global(), - type_, EventBubbles::DoesNotBubble, EventCancelable::NotCancelable, - total.is_some(), loaded, total.unwrap_or(0)); + let progressevent = ProgressEvent::new( + &self.global(), + type_, + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable, + total.is_some(), + loaded, + total.unwrap_or(0), + ); progressevent.upcast::<Event>().fire(self.upcast()); } @@ -365,7 +427,12 @@ impl FileReader { self.generation_id.set(GenerationId(prev_id + 1)); } - fn read(&self, function: FileReaderFunction, blob: &Blob, label: Option<DOMString>) -> ErrorResult { + fn read( + &self, + function: FileReaderFunction, + blob: &Blob, + label: Option<DOMString>, + ) -> ErrorResult { // Step 1 if self.ready_state.get() == FileReaderReadyState::Loading { return Err(Error::InvalidState); @@ -388,16 +455,19 @@ impl FileReader { let canceller = global.task_canceller(); let task_source = global.file_reading_task_source(); - thread::Builder::new().name("file reader async operation".to_owned()).spawn(move || { - perform_annotated_read_operation( - gen_id, - load_data, - blob_contents, - fr, - task_source, - canceller, - ) - }).expect("Thread spawning failed"); + thread::Builder::new() + .name("file reader async operation".to_owned()) + .spawn(move || { + perform_annotated_read_operation( + gen_id, + load_data, + blob_contents, + fr, + task_source, + canceller, + ) + }) + .expect("Thread spawning failed"); Ok(()) } diff --git a/components/script/dom/filereadersync.rs b/components/script/dom/filereadersync.rs index bbdb83a23a9..cc9a821a073 100644 --- a/components/script/dom/filereadersync.rs +++ b/components/script/dom/filereadersync.rs @@ -2,17 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::codegen::Bindings::FileReaderSyncBinding; -use dom::bindings::error::Fallible; +use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; +use dom::bindings::codegen::Bindings::FileReaderSyncBinding::{FileReaderSyncBinding, FileReaderSyncMethods}; +use dom::bindings::error::{Error, Fallible}; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::root::DomRoot; +use dom::bindings::str::DOMString; +use dom::blob::Blob; use dom::eventtarget::EventTarget; +use dom::filereader::FileReaderSharedFunctionality; use dom::globalscope::GlobalScope; use dom_struct::dom_struct; +use js::jsapi::{JSContext, JSObject}; +use js::typedarray::{ArrayBuffer, CreateWith}; +use std::ptr; +use std::ptr::NonNull; #[dom_struct] pub struct FileReaderSync { - eventtarget: EventTarget + eventtarget: EventTarget, } impl FileReaderSync { @@ -23,11 +31,79 @@ impl FileReaderSync { } pub fn new(global: &GlobalScope) -> DomRoot<FileReaderSync> { - reflect_dom_object(Box::new(FileReaderSync::new_inherited()), - global, FileReaderSyncBinding::Wrap) + reflect_dom_object( + Box::new(FileReaderSync::new_inherited()), + global, + FileReaderSyncBinding::Wrap, + ) } pub fn Constructor(global: &GlobalScope) -> Fallible<DomRoot<FileReaderSync>> { Ok(FileReaderSync::new(global)) } + + fn get_blob_bytes(blob: &Blob) -> Result<Vec<u8>, Error> { + blob.get_bytes().map_err(|_| Error::NotReadable) + } +} + +impl FileReaderSyncMethods for FileReaderSync { + // https://w3c.github.io/FileAPI/#readAsBinaryStringSyncSection + fn ReadAsBinaryString(&self, blob: &Blob) -> Fallible<DOMString> { + // step 1 + let blob_contents = FileReaderSync::get_blob_bytes(blob)?; + + // step 2 + Ok(DOMString::from(String::from_utf8_lossy(&blob_contents))) + } + + // https://w3c.github.io/FileAPI/#readAsTextSync + fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> Fallible<DOMString> { + // step 1 + let blob_contents = FileReaderSync::get_blob_bytes(blob)?; + + // step 2 + let blob_label = label.map(String::from); + let blob_type = String::from(blob.Type()); + + let output = + FileReaderSharedFunctionality::text_decode(&blob_contents, &blob_type, &blob_label); + + Ok(output) + } + + // https://w3c.github.io/FileAPI/#readAsDataURLSync-section + fn ReadAsDataURL(&self, blob: &Blob) -> Fallible<DOMString> { + // step 1 + let blob_contents = FileReaderSync::get_blob_bytes(blob)?; + + // step 2 + let output = + FileReaderSharedFunctionality::dataurl_format(&blob_contents, blob.Type().to_string()); + + Ok(output) + } + + #[allow(unsafe_code)] + // https://w3c.github.io/FileAPI/#readAsArrayBufferSyncSection + unsafe fn ReadAsArrayBuffer( + &self, + cx: *mut JSContext, + blob: &Blob, + ) -> Fallible<NonNull<JSObject>> { + // step 1 + let blob_contents = FileReaderSync::get_blob_bytes(blob)?; + + // step 2 + rooted!(in(cx) let mut array_buffer = ptr::null_mut::<JSObject>()); + assert!( + ArrayBuffer::create( + cx, + CreateWith::Slice(&blob_contents), + array_buffer.handle_mut() + ).is_ok() + ); + + Ok(NonNull::new_unchecked(array_buffer.get())) + } } diff --git a/components/script/dom/webidls/DOMException.webidl b/components/script/dom/webidls/DOMException.webidl index 69866372cb6..fb39af05488 100644 --- a/components/script/dom/webidls/DOMException.webidl +++ b/components/script/dom/webidls/DOMException.webidl @@ -34,6 +34,7 @@ interface DOMException { const unsigned short TIMEOUT_ERR = 23; const unsigned short INVALID_NODE_TYPE_ERR = 24; const unsigned short DATA_CLONE_ERR = 25; + const unsigned short NOT_READABLE_ERR = 26; // Error code as u16 readonly attribute unsigned short code; diff --git a/components/script/dom/webidls/FileReaderSync.webidl b/components/script/dom/webidls/FileReaderSync.webidl index cbc18a47921..40a0d75df2b 100644 --- a/components/script/dom/webidls/FileReaderSync.webidl +++ b/components/script/dom/webidls/FileReaderSync.webidl @@ -8,8 +8,12 @@ interface FileReaderSync { // Synchronously return strings - // ArrayBuffer readAsArrayBuffer(Blob blob); - // DOMString readAsBinaryString(Blob blob); - // DOMString readAsText(Blob blob, optional DOMString label); - // DOMString readAsDataURL(Blob blob); + [Throws] + ArrayBuffer readAsArrayBuffer(Blob blob); + [Throws] + DOMString readAsBinaryString(Blob blob); + [Throws] + DOMString readAsText(Blob blob, optional DOMString label); + [Throws] + DOMString readAsDataURL(Blob blob); }; |