start decoder

cli-redesign
Avril 4 years ago
parent d9fc959738
commit 745a3a61d5
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -15,4 +15,5 @@ lazy_static = "1.4"
tokio = {version = "0.2", features= ["full"], optional=true}
reqwest = {version = "0.10", features= ["stream"]}
memmap = "0.7"
getrandom = "0.1"
getrandom = "0.1"
base64 = "0.12"

@ -0,0 +1,27 @@
pub trait JoinStrsExt: Sized
{
/// Join an iterator of `str` with a seperator
fn join(self, with: &str) -> String;
}
impl<T,I> JoinStrsExt for I
where I: Iterator<Item=T>,
T: AsRef<str>
{
fn join(self, with: &str) -> String
{
let mut output = String::new();
let mut first=true;
for string in self
{
if !first {
output.push_str(with);
}
let string = string.as_ref();
output.push_str(string);
first=false;
}
output
}
}

@ -1,7 +0,0 @@
use super::*;
#[derive(Debug)]
pub struct Loli
{
}

@ -0,0 +1,55 @@
use super::*;
use std::{
str,
io::{
self,
Write,
},
};
const HEADER_BASE64_JPEG: &'static str = "/9j/";
const HEADER_BASE64_PNG: &'static str = "iVBO";
const HEADER_BASE64_GIF: &'static str = "R0lG";
/// An image type header
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ImageType
{
Png,
Jpeg,
Gif,
}
impl Default for ImageType
{
fn default() -> Self
{
Self::Jpeg
}
}
impl str::FromStr for ImageType
{
type Err = error::Error;
/// Determine image type from base64
fn from_str(from: &str) -> Result<Self, Self::Err>
{
if from.len() > 4 {
Ok(match &from[..4] {
HEADER_BASE64_GIF => Self::Gif,
HEADER_BASE64_PNG => Self::Png,
HEADER_BASE64_JPEG => Self::Jpeg,
_ => return Err(error::Error::UnknownFormat),
})
} else {
Err(error::Error::InvalidFormat)
}
}
}
/// Calculate the required data size from base64 input size
pub const fn data_size(base64: usize) -> usize
{
((4 * base64 / 3) + 3) & !3
}

@ -0,0 +1,77 @@
use super::*;
use std::{
error,
fmt,
io,
};
#[derive(Debug)]
pub enum Error
{
/// Image format could not be determined.
UnknownFormat,
/// Image is not valid
InvalidFormat,
/// Image decode failedb
DecodeError,
// Internals
/// IO error
IO(io::Error),
/// Failed to format text
Formatter(fmt::Error),
/// Something bad
Unknown,
}
impl error::Error for Error
{
fn source(&self) -> Option<&(dyn error::Error + 'static)>
{
Some(match &self {
Self::IO(io) => io,
Self::Formatter(fmt) => fmt,
_ => return None,
})
}
}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "loli module: ")?;
match self {
Self::UnknownFormat => write!(f, "could not determine image format"),
Self::InvalidFormat => write!(f, "image is not valid"),
Self::DecodeError => write!(f, "image decode failed"),
Self::IO(io) => write!(f, "io: {}", io),
Self::Formatter(fmt) => write!(f, "formatting: {}", fmt),
_ => write!(f, "unknown error"),
}
}
}
impl From<io::Error> for Error
{
fn from(er: io::Error) -> Self
{
Self::IO(er)
}
}
impl From<fmt::Error> for Error
{
fn from(er: fmt::Error) -> Self
{
Self::Formatter(er)
}
}
impl From<base64::DecodeError> for Error
{
fn from(_er: base64::DecodeError) -> Self
{
Self::DecodeError
}
}

@ -0,0 +1,28 @@
pub mod error;
pub mod encoding;
/// Attempt to decode an image
pub fn decode<S, W>(input: S, mut output: W) -> Result<usize, error::Error>
where S: AsRef<[u8]>,
W: AsMut<[u8]>
{
let input_bytes = input.as_ref();
let output_bytes = output.as_mut();
Ok(base64::decode_config_slice(input_bytes, base64::STANDARD, output_bytes)?)
}
/// Calculate the size for a base64 inpue
pub fn calc_size<T>(input: T) -> usize
where T: AsRef<[u8]>
{
encoding::data_size(input.as_ref().len())
}
/// Try to get the image format from a `str` slice.
pub fn attempt_get_format<T>(input: T) -> Result<encoding::ImageType, error::Error>
where T: AsRef<str>
{
input.as_ref().parse()
}

@ -6,6 +6,9 @@ use termprogress::{
ProgressBar,
};
mod ext;
use ext::*;
mod config;
mod args;
mod url;

@ -30,7 +30,7 @@ fn generate_filename(mut to: impl fmt::Write) -> Result<(), error::Error>
write!(to, "{}", PREFIX)?;
for byte in buffer.iter() {
write!(to, "{:2x}", *byte)?;
write!(to, "{:02x}", *byte)?;
}
Ok(())

@ -15,7 +15,7 @@ mod tasklist;
mod progress;
/// Download a loli async
pub async fn perform(url: impl AsRef<str>, path: impl AsRef<Path>, mut progress: progress::CommandSender) -> Result<(), error::Error>
pub async fn perform(url: impl AsRef<str>, path: impl AsRef<Path>, progress: &mut progress::CommandSender) -> Result<String, error::Error>
{
let url = url.as_ref();
let path = path.as_ref();
@ -54,9 +54,9 @@ pub async fn perform(url: impl AsRef<str>, path: impl AsRef<Path>, mut progress:
prog_send!(progress.bump(1));
}
prog_send!(progress.println(format!("done for {}", url)));
prog_send!(link progress.pop_task(task));
//prog_send!(link progress.pop_task(task));
Ok(())
Ok(task)
}
pub async fn work(conf: config::Config) -> Result<(), Box<dyn std::error::Error>>
@ -85,10 +85,11 @@ pub async fn work(conf: config::Config) -> Result<(), Box<dyn std::error::Error>
},
};*/
let temp = tempfile::TempFile::new();
match perform(&url, &temp, prog).await {
match perform(&url, &temp, &mut prog).await {
Err(e) => panic!("Failed downloading {} -> {:?}: {}", url, temp, e), //TODO: Make real error handler
Ok(_) => {
Ok(task) => {
//TODO: memmap `temp` and decode base64 into new file `path`. also determine the encoding.
prog_send!(link prog.pop_task(task));
},
}

@ -71,7 +71,7 @@ impl TaskList
pub fn recalc_buffer(&mut self)
{
self.1 = self.0.iter().map(|(_, s)| s.as_str()).collect(); //TODO: Iterator extension join method for strings
self.1 = self.0.iter().map(|(_, s)| s.as_str()).join(", ");
}
pub fn as_str(&self) -> &str

Loading…
Cancel
Save