/* This Source Code Form is subject to the terms of the Mozilla Public * 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 std::os::raw::c_char; use nserror::nsresult; use xpcom::create_instance; use xpcom::interfaces::{nsIFile, nsIFileInputStream, nsIInputStream}; /// Open the file provided and read its content into a vector of bytes. pub fn read_file(file: &nsIFile) -> Result, nsresult> { // Open a stream from the file. let file_stream = create_instance::(c"@mozilla.org/network/file-input-stream;1") .ok_or(nserror::NS_ERROR_FAILURE)?; unsafe { file_stream.Init(file, -1, -1, nsIFileInputStream::CLOSE_ON_EOF) }.to_result()?; // Read as many bytes as available from the stream. read_stream(file_stream.coerce()) } pub fn read_stream(stream: &nsIInputStream) -> Result, nsresult> { let mut bytes_available = 0; unsafe { stream.Available(&mut bytes_available) }.to_result()?; // `nsIInputStream::Available` reads into a u64, but `nsIInputStream::Read` // takes a u32. let bytes_available = ::try_from(bytes_available).or(Err(nserror::NS_ERROR_FAILURE))?; let mut read_sink: Vec = vec![0; ::try_from(bytes_available).or(Err(nserror::NS_ERROR_FAILURE))?]; // The amount of bytes actually read from the stream. let mut bytes_read: u32 = 0; // SAFETY: The call contract from `nsIInputStream::Read` guarantees that the // bytes written into the provided buffer is of type c_char (char* in // C-land) and is contiguous for the length it writes in `bytes_read`; and // that `bytes_read` is not greater than `bytes_available`. unsafe { let read_ptr = read_sink.as_mut_ptr(); stream .Read(read_ptr as *mut c_char, bytes_available, &mut bytes_read) .to_result()?; }; // TODO: We currently assume all of the data we care about is in the stream // when we read, which might not be the case if we're copying multiple // messages. let bytes_read = ::try_from(bytes_read).or(Err(nserror::NS_ERROR_FAILURE))?; Ok(Vec::from(&read_sink[..bytes_read])) }