use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use either::Either;
use super::embedded::EmbeddedFiles;
use super::Env;
use crate::error::AssemblerError;
use crate::preamble::ParserOptions;
use crate::progress::Progress;
type Fname<'a, 'b> = either::Either<&'a Path, (&'a str, &'b Env)>;
pub fn get_filename(
fname: &str,
options: &ParserOptions,
env: Option<&Env>
) -> Result<PathBuf, AssemblerError> {
options.get_path_for(fname, env).map_err(|e| {
match e {
either::Either::Left(asm) => asm,
either::Either::Right(tested) => {
AssemblerError::AssemblingError {
msg: format!("{} not found. TEsted {:?}", fname, tested)
}
}
}
})
}
pub fn load_binary(fname: Fname, options: &ParserOptions) -> Result<Vec<u8>, AssemblerError> {
let fname = match &fname {
either::Either::Right((p, env)) => get_filename(p, options, Some(env))?,
either::Either::Left(p) => p.into()
};
let fname_repr = fname.to_str().unwrap();
let progress = if options.show_progress {
Progress::progress().add_load(fname_repr);
Some(fname_repr)
}
else {
None
};
let content = if fname_repr.starts_with("inner://") {
EmbeddedFiles::get(fname_repr)
.ok_or(AssemblerError::IOError {
msg: format!("Unable to open {:?}; it is not embedded.", fname_repr)
})?
.data
.to_vec()
}
else {
let mut f = File::open(&fname).map_err(|e| {
AssemblerError::IOError {
msg: format!("Unable to open {:?}. {}", fname, e)
}
})?;
let mut content = Vec::new();
f.read_to_end(&mut content).map_err(|e| {
AssemblerError::IOError {
msg: format!("Unable to read {:?}. {}", fname, e.to_string())
}
})?;
content
};
if let Some(progress) = progress {
Progress::progress().remove_load(progress);
}
Ok(content)
}
pub fn read_source<P: AsRef<Path>>(
fname: P,
options: &ParserOptions
) -> Result<String, AssemblerError> {
let fname = fname.as_ref();
let content = load_binary(Either::Left(fname), options)?;
handle_source_encoding(fname.to_str().unwrap(), &content)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn handle_source_encoding(_fname: &str, content: &[u8]) -> Result<String, AssemblerError> {
let mut decoder = chardetng::EncodingDetector::new();
decoder.feed(content, true);
let encoding = decoder.guess(None, true);
let content = encoding.decode(content).0;
let content = content.into_owned();
Ok(content)
}
#[cfg(target_arch = "wasm32")]
pub fn handle_source_encoding(_fname: &str, content: &[u8]) -> Result<String, AssemblerError> {
todo!()
}