support decoding without mime type
This commit is contained in:
parent
601d04020c
commit
16066479b4
4 changed files with 41 additions and 39 deletions
|
@ -8,12 +8,12 @@ use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
io::{self},
|
io,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
enum IconType {
|
enum IconKind {
|
||||||
PNG,
|
PNG,
|
||||||
JPEG,
|
JPEG,
|
||||||
ICO,
|
ICO,
|
||||||
|
@ -30,6 +30,30 @@ pub enum IconInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconInfo {
|
impl IconInfo {
|
||||||
|
async fn decode<R: AsyncRead + Unpin>(
|
||||||
|
reader: &mut R,
|
||||||
|
kind: Option<IconKind>,
|
||||||
|
) -> Result<IconInfo, Box<dyn Error>> {
|
||||||
|
let mut header = [0; 2];
|
||||||
|
reader.read_exact(&mut header).await?;
|
||||||
|
|
||||||
|
match (kind, header) {
|
||||||
|
(Some(IconKind::PNG), _) | (_, [0xC2, 0x89]) => {
|
||||||
|
let size = get_png_size(reader).await?;
|
||||||
|
Ok(IconInfo::PNG { size })
|
||||||
|
}
|
||||||
|
(Some(IconKind::ICO), _) | (_, [0x00, 0x00]) => {
|
||||||
|
let sizes = get_ico_sizes(reader).await?;
|
||||||
|
Ok(IconInfo::ICO { sizes })
|
||||||
|
}
|
||||||
|
(Some(IconKind::JPEG), _) | (_, [0xFF, 0xD8]) => {
|
||||||
|
let size = get_jpeg_size(reader).await?;
|
||||||
|
Ok(IconInfo::JPEG { size })
|
||||||
|
}
|
||||||
|
_ => Err("unknown icon type".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn load(
|
pub async fn load(
|
||||||
url: Url,
|
url: Url,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
@ -85,7 +109,7 @@ impl IconInfo {
|
||||||
size: *sizes.largest(),
|
size: *sizes.largest(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IconType::PNG
|
Some(IconKind::PNG)
|
||||||
}
|
}
|
||||||
|
|
||||||
(mime::IMAGE, mime::JPEG) => {
|
(mime::IMAGE, mime::JPEG) => {
|
||||||
|
@ -94,7 +118,7 @@ impl IconInfo {
|
||||||
size: *sizes.largest(),
|
size: *sizes.largest(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IconType::JPEG
|
Some(IconKind::JPEG)
|
||||||
}
|
}
|
||||||
|
|
||||||
(mime::IMAGE, "x-icon") | (mime::IMAGE, "vnd.microsoft.icon") => {
|
(mime::IMAGE, "x-icon") | (mime::IMAGE, "vnd.microsoft.icon") => {
|
||||||
|
@ -102,28 +126,15 @@ impl IconInfo {
|
||||||
return Ok(IconInfo::ICO { sizes });
|
return Ok(IconInfo::ICO { sizes });
|
||||||
}
|
}
|
||||||
|
|
||||||
IconType::ICO
|
Some(IconKind::ICO)
|
||||||
}
|
}
|
||||||
|
|
||||||
(mime::IMAGE, mime::SVG) => return Ok(IconInfo::SVG),
|
(mime::IMAGE, mime::SVG) | (mime::TEXT, mime::PLAIN) => return Ok(IconInfo::SVG),
|
||||||
|
|
||||||
_ => return Err(format!("unsupported mime type {}", mime).into()),
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(match kind {
|
IconInfo::decode(&mut body, kind).await
|
||||||
IconType::PNG => {
|
|
||||||
let size = get_png_sizes(&mut body).await?;
|
|
||||||
IconInfo::PNG { size }
|
|
||||||
}
|
|
||||||
IconType::ICO => {
|
|
||||||
let sizes = get_ico_sizes(&mut body).await?;
|
|
||||||
IconInfo::ICO { sizes }
|
|
||||||
}
|
|
||||||
IconType::JPEG => {
|
|
||||||
let size = get_jpeg_size(&mut body).await?;
|
|
||||||
IconInfo::JPEG { size }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Option<&IconSize> {
|
pub fn size(&self) -> Option<&IconSize> {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{png::get_png_sizes, IconSize, IconSizes};
|
use super::{png::get_png_size, IconSize, IconSizes};
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -13,16 +13,14 @@ const INDEX_SIZE: u16 = 16;
|
||||||
pub async fn get_ico_sizes<R: AsyncRead + Unpin>(
|
pub async fn get_ico_sizes<R: AsyncRead + Unpin>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
) -> Result<IconSizes, Box<dyn Error>> {
|
) -> Result<IconSizes, Box<dyn Error>> {
|
||||||
let mut offset = 0;
|
let mut offset = 4;
|
||||||
let mut header = [0; 6];
|
let mut header = [0; 4];
|
||||||
reader.read_exact(&mut header).await?;
|
reader.read_exact(&mut header).await?;
|
||||||
offset += header.len();
|
|
||||||
let mut header = Cursor::new(header);
|
let mut header = Cursor::new(header);
|
||||||
|
|
||||||
let header_type = header.read_u16::<LittleEndian>()?;
|
|
||||||
let icon_type = header.read_u16::<LittleEndian>()?;
|
let icon_type = header.read_u16::<LittleEndian>()?;
|
||||||
|
|
||||||
if header_type != 0 || icon_type != ICO_TYPE {
|
if icon_type != ICO_TYPE {
|
||||||
return Err("bad header".into());
|
return Err("bad header".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +46,7 @@ pub async fn get_ico_sizes<R: AsyncRead + Unpin>(
|
||||||
reader.read_exact(&mut data).await?;
|
reader.read_exact(&mut data).await?;
|
||||||
offset += data.len();
|
offset += data.len();
|
||||||
|
|
||||||
let size = get_png_sizes(reader).await;
|
let size = get_png_size(reader).await;
|
||||||
if let Ok(size) = size {
|
if let Ok(size) = size {
|
||||||
sizes.push(size);
|
sizes.push(size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,6 @@ use tokio_futures_byteorder::AsyncReadBytesExt;
|
||||||
pub async fn get_jpeg_size<R: AsyncRead + Unpin>(
|
pub async fn get_jpeg_size<R: AsyncRead + Unpin>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
) -> Result<IconSize, Box<dyn Error>> {
|
) -> Result<IconSize, Box<dyn Error>> {
|
||||||
let mut data = [0; 2];
|
|
||||||
reader.read_exact(&mut data).await?;
|
|
||||||
let data = &mut Cursor::new(data);
|
|
||||||
|
|
||||||
// first marker of the file MUST be 0xFFD8
|
|
||||||
assert_slice_eq!(data, 0, &[0xFF, 0xD8], "bad header");
|
|
||||||
|
|
||||||
let mut marker = [0; 2];
|
let mut marker = [0; 2];
|
||||||
let mut depth = 0i32;
|
let mut depth = 0i32;
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use std::{error::Error, io::Cursor};
|
use std::{error::Error, io::Cursor};
|
||||||
|
|
||||||
pub async fn get_png_sizes<R: AsyncRead + Unpin>(
|
pub async fn get_png_size<R: AsyncRead + Unpin>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
) -> Result<IconSize, Box<dyn Error>> {
|
) -> Result<IconSize, Box<dyn Error>> {
|
||||||
let mut header = [0; 24];
|
let mut header = [0; 22];
|
||||||
reader.read_exact(&mut header).await?;
|
reader.read_exact(&mut header).await?;
|
||||||
let header = &mut Cursor::new(header);
|
let header = &mut Cursor::new(header);
|
||||||
|
|
||||||
assert_slice_eq!(header, 0, b"\x89PNG\r\n\x1a\n", "bad header");
|
assert_slice_eq!(header, 0, b"PNG\r\n\x1a\n", "bad header");
|
||||||
assert_slice_eq!(header, 12, b"IHDR", "bad header");
|
assert_slice_eq!(header, 10, b"IHDR", "bad header");
|
||||||
|
|
||||||
let width = header.read_u32::<BigEndian>()?;
|
let width = header.read_u32::<BigEndian>()?;
|
||||||
let height = header.read_u32::<BigEndian>()?;
|
let height = header.read_u32::<BigEndian>()?;
|
||||||
|
|
Reference in a new issue