support decoding without mime type

This commit is contained in:
Sam Denty 2022-10-08 13:27:29 +01:00
parent 601d04020c
commit 16066479b4
No known key found for this signature in database
GPG key ID: 7B4EAF7B9E291B79
4 changed files with 41 additions and 39 deletions

View file

@ -8,12 +8,12 @@ use std::{
cmp::Ordering,
error::Error,
fmt::{self, Display},
io::{self},
io,
};
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
enum IconType {
enum IconKind {
PNG,
JPEG,
ICO,
@ -30,6 +30,30 @@ pub enum 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(
url: Url,
headers: HeaderMap,
@ -85,7 +109,7 @@ impl IconInfo {
size: *sizes.largest(),
});
}
IconType::PNG
Some(IconKind::PNG)
}
(mime::IMAGE, mime::JPEG) => {
@ -94,7 +118,7 @@ impl IconInfo {
size: *sizes.largest(),
});
}
IconType::JPEG
Some(IconKind::JPEG)
}
(mime::IMAGE, "x-icon") | (mime::IMAGE, "vnd.microsoft.icon") => {
@ -102,28 +126,15 @@ impl IconInfo {
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 {
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 }
}
})
IconInfo::decode(&mut body, kind).await
}
pub fn size(&self) -> Option<&IconSize> {

View file

@ -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 futures::prelude::*;
use std::{
@ -13,16 +13,14 @@ const INDEX_SIZE: u16 = 16;
pub async fn get_ico_sizes<R: AsyncRead + Unpin>(
reader: &mut R,
) -> Result<IconSizes, Box<dyn Error>> {
let mut offset = 0;
let mut header = [0; 6];
let mut offset = 4;
let mut header = [0; 4];
reader.read_exact(&mut header).await?;
offset += header.len();
let mut header = Cursor::new(header);
let header_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());
}
@ -48,7 +46,7 @@ pub async fn get_ico_sizes<R: AsyncRead + Unpin>(
reader.read_exact(&mut data).await?;
offset += data.len();
let size = get_png_sizes(reader).await;
let size = get_png_size(reader).await;
if let Ok(size) = size {
sizes.push(size);
}

View file

@ -7,13 +7,6 @@ use tokio_futures_byteorder::AsyncReadBytesExt;
pub async fn get_jpeg_size<R: AsyncRead + Unpin>(
reader: &mut R,
) -> 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 depth = 0i32;

View file

@ -3,15 +3,15 @@ use byteorder::{BigEndian, ReadBytesExt};
use futures::prelude::*;
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,
) -> Result<IconSize, Box<dyn Error>> {
let mut header = [0; 24];
let mut header = [0; 22];
reader.read_exact(&mut header).await?;
let header = &mut Cursor::new(header);
assert_slice_eq!(header, 0, b"\x89PNG\r\n\x1a\n", "bad header");
assert_slice_eq!(header, 12, b"IHDR", "bad header");
assert_slice_eq!(header, 0, b"PNG\r\n\x1a\n", "bad header");
assert_slice_eq!(header, 10, b"IHDR", "bad header");
let width = header.read_u32::<BigEndian>()?;
let height = header.read_u32::<BigEndian>()?;