use std::fmt;
use crate::{Img, ImgBuf, ImgFmt, ImgMut, ImgRef};
use super::*;
pub const HEADER_SIZE: u64 = 8;
const RESERVED: u32 = 0;
const UTF8: u32 = 1;
const UTF16: u32 = 2;
#[allow(unused)]
const UTF8_SORT: u32 = 4;
#[allow(unused)]
const UTF16_SORT: u32 = 5;
const JPEG: u32 = 13;
const PNG: u32 = 14;
const BE_SIGNED: u32 = 21;
#[allow(unused)]
const BE_UNSIGNED: u32 = 22;
#[allow(unused)]
const BE_F32: u32 = 23;
#[allow(unused)]
const BE_F64: u32 = 24;
#[allow(unused)]
const BMP: u32 = 27;
#[allow(unused)]
const QT_META: u32 = 28;
#[allow(unused)]
const I8: u32 = 65;
#[allow(unused)]
const BE_I16: u32 = 66;
#[allow(unused)]
const BE_I32: u32 = 67;
#[allow(unused)]
const BE_POINT_F32: u32 = 70;
#[allow(unused)]
const BE_DIMS_F32: u32 = 71;
#[allow(unused)]
const BE_RECT_F32: u32 = 72;
#[allow(unused)]
const BE_I64: u32 = 74;
#[allow(unused)]
const U8: u32 = 75;
#[allow(unused)]
const BE_U16: u32 = 76;
#[allow(unused)]
const BE_U32: u32 = 77;
#[allow(unused)]
const BE_U64: u32 = 78;
#[allow(unused)]
const AFFINE_TRANSFORM_F64: u32 = 79;
#[derive(Clone, PartialEq, Eq)]
pub enum Data {
Reserved(Vec<u8>),
Utf8(String),
Utf16(String),
Jpeg(Vec<u8>),
Png(Vec<u8>),
Bmp(Vec<u8>),
BeSigned(Vec<u8>),
Unknown {
code: u32,
data: Vec<u8>,
},
}
impl fmt::Debug for Data {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Reserved(d) => write!(f, "Data::Reserved({d:?})"),
Self::Utf8(d) => write!(f, "Data::Utf8({d:?})"),
Self::Utf16(d) => write!(f, "Data::Utf16({d:?})"),
Self::Jpeg(_) => write!(f, "Data::Jpeg"),
Self::Png(_) => write!(f, "Data::Png"),
Self::BeSigned(d) => write!(f, "Data::BeSigned({d:?})"),
Self::Bmp(_) => write!(f, "Data::Bmp"),
Self::Unknown { code, data } => {
f.debug_struct("Data::Unknown").field("code", code).field("data", data).finish()
}
}
}
}
impl<T: Into<Vec<u8>>> From<Img<T>> for Data {
fn from(image: Img<T>) -> Self {
match image.fmt {
ImgFmt::Bmp => Self::Bmp(image.data.into()),
ImgFmt::Jpeg => Self::Jpeg(image.data.into()),
ImgFmt::Png => Self::Png(image.data.into()),
}
}
}
impl Atom for Data {
const FOURCC: Fourcc = DATA;
}
impl Data {
pub fn parse(
reader: &mut (impl Read + Seek),
cfg: &ParseConfig<'_>,
size: Size,
) -> crate::Result<Data> {
let mut buf = [0; 8];
reader.read_exact(&mut buf)?;
let [version, b2, b1, b0, _locale @ ..] = buf;
if version != 0 {
return Err(crate::Error::new(
crate::ErrorKind::UnknownVersion(version),
"Unknown data atom (data) version",
));
}
let datatype = u32::from_be_bytes([0, b2, b1, b0]);
expect_min_size("Data (data)", size, HEADER_SIZE)?;
let len = size.content_len() - HEADER_SIZE;
Ok(match datatype {
RESERVED => Data::Reserved(reader.read_u8_vec(len)?),
UTF8 => Data::Utf8(reader.read_utf8(len)?),
UTF16 => Data::Utf16(reader.read_be_utf16(len)?),
JPEG => Data::Jpeg(read_image(reader, cfg.cfg.read_image_data, len)?),
PNG => Data::Png(read_image(reader, cfg.cfg.read_image_data, len)?),
BE_SIGNED => Data::BeSigned(reader.read_u8_vec(len)?),
BMP => Data::Bmp(read_image(reader, cfg.cfg.read_image_data, len)?),
_ => {
Data::Unknown { code: datatype, data: reader.read_u8_vec(len)? }
}
})
}
pub fn write(&self, writer: &mut impl Write) -> crate::Result<()> {
head::write(writer, Head::new(false, self.len(), DATA))?;
let datatype = match self {
Self::Reserved(_) => RESERVED,
Self::Utf8(_) => UTF8,
Self::Utf16(_) => UTF16,
Self::Jpeg(_) => JPEG,
Self::Png(_) => PNG,
Self::BeSigned(_) => BE_SIGNED,
Self::Bmp(_) => BMP,
Self::Unknown { code, .. } => *code,
};
writer.write_all(&datatype.to_be_bytes())?;
writer.write_all(&[0; 4])?; match self {
Self::Reserved(v) => writer.write_all(v)?,
Self::Utf8(s) => writer.write_utf8(s)?,
Self::Utf16(s) => writer.write_be_utf16(s)?,
Self::Jpeg(v) => writer.write_all(v)?,
Self::Png(v) => writer.write_all(v)?,
Self::BeSigned(v) => writer.write_all(v)?,
Self::Bmp(v) => writer.write_all(v)?,
Self::Unknown { data, .. } => writer.write_all(data)?,
}
Ok(())
}
pub fn len(&self) -> u64 {
Head::NORMAL_SIZE + HEADER_SIZE + self.data_len()
}
}
impl Data {
pub fn data_len(&self) -> u64 {
(match self {
Self::Reserved(v) => v.len(),
Self::Utf8(s) => s.len(),
Self::Utf16(s) => 2 * s.encode_utf16().count(),
Self::Jpeg(v) => v.len(),
Self::Png(v) => v.len(),
Self::BeSigned(v) => v.len(),
Self::Bmp(v) => v.len(),
Self::Unknown { data, .. } => data.len(),
}) as u64
}
pub fn is_empty(&self) -> bool {
self.data_len() == 0
}
pub const fn is_bytes(&self) -> bool {
matches!(self, Self::Reserved(_) | Self::BeSigned(_))
}
pub const fn is_string(&self) -> bool {
matches!(self, Self::Utf8(_) | Self::Utf16(_))
}
pub const fn is_image(&self) -> bool {
matches!(self, Self::Jpeg(_) | Self::Png(_) | Self::Bmp(_))
}
pub const fn is_reserved(&self) -> bool {
matches!(self, Self::Reserved(_))
}
pub const fn is_utf8(&self) -> bool {
matches!(self, Self::Utf8(_))
}
pub const fn is_utf16(&self) -> bool {
matches!(self, Self::Utf16(_))
}
pub const fn is_jpeg(&self) -> bool {
matches!(self, Self::Jpeg(_))
}
pub const fn is_png(&self) -> bool {
matches!(self, Self::Png(_))
}
pub const fn is_bmp(&self) -> bool {
matches!(self, Self::Bmp(_))
}
pub const fn is_be_signed(&self) -> bool {
matches!(self, Self::BeSigned(_))
}
pub fn bytes(&self) -> Option<&[u8]> {
match self {
Self::Reserved(v) => Some(v),
Self::BeSigned(v) => Some(v),
_ => None,
}
}
pub fn bytes_mut(&mut self) -> Option<&mut Vec<u8>> {
match self {
Self::Reserved(v) => Some(v),
Self::BeSigned(v) => Some(v),
_ => None,
}
}
pub fn into_bytes(self) -> Option<Vec<u8>> {
match self {
Self::Reserved(v) => Some(v),
Self::BeSigned(v) => Some(v),
_ => None,
}
}
pub fn string(&self) -> Option<&str> {
match self {
Self::Utf8(s) => Some(s.as_str()),
Self::Utf16(s) => Some(s.as_str()),
_ => None,
}
}
pub fn string_mut(&mut self) -> Option<&mut String> {
match self {
Self::Utf8(s) => Some(s),
Self::Utf16(s) => Some(s),
_ => None,
}
}
pub fn into_string(self) -> Option<String> {
match self {
Self::Utf8(s) => Some(s),
Self::Utf16(s) => Some(s),
_ => None,
}
}
pub fn image(&self) -> Option<ImgRef<'_>> {
match self {
Self::Jpeg(v) => Some(Img::new(ImgFmt::Jpeg, v)),
Self::Png(v) => Some(Img::new(ImgFmt::Png, v)),
Self::Bmp(v) => Some(Img::new(ImgFmt::Bmp, v)),
_ => None,
}
}
pub fn image_mut(&mut self) -> Option<ImgMut<'_>> {
match self {
Self::Jpeg(v) => Some(Img::new(ImgFmt::Jpeg, v)),
Self::Png(v) => Some(Img::new(ImgFmt::Png, v)),
Self::Bmp(v) => Some(Img::new(ImgFmt::Bmp, v)),
_ => None,
}
}
pub fn into_image(self) -> Option<ImgBuf> {
match self {
Self::Jpeg(v) => Some(Img::new(ImgFmt::Jpeg, v)),
Self::Png(v) => Some(Img::new(ImgFmt::Png, v)),
Self::Bmp(v) => Some(Img::new(ImgFmt::Bmp, v)),
_ => None,
}
}
pub fn image_data(&self) -> Option<&[u8]> {
self.image().map(|i| i.data)
}
pub fn image_data_mut(&mut self) -> Option<&mut Vec<u8>> {
self.image_mut().map(|i| i.data)
}
pub fn into_image_data(self) -> Option<Vec<u8>> {
self.into_image().map(|i| i.data)
}
pub fn reserved(&self) -> Option<&[u8]> {
match self {
Self::Reserved(v) => Some(v),
_ => None,
}
}
pub fn utf8(&self) -> Option<&str> {
match self {
Self::Utf8(s) => Some(s),
_ => None,
}
}
pub fn utf16(&self) -> Option<&str> {
match self {
Self::Utf16(s) => Some(s),
_ => None,
}
}
pub fn jpeg(&self) -> Option<&[u8]> {
match self {
Self::Jpeg(v) => Some(v),
_ => None,
}
}
pub fn png(&self) -> Option<&[u8]> {
match self {
Self::Png(v) => Some(v),
_ => None,
}
}
pub fn bmp(&self) -> Option<&[u8]> {
match self {
Self::Bmp(v) => Some(v),
_ => None,
}
}
pub fn be_signed(&self) -> Option<&[u8]> {
match self {
Self::BeSigned(v) => Some(v),
_ => None,
}
}
}
fn read_image(reader: &mut (impl Read + Seek), parse: bool, len: u64) -> crate::Result<Vec<u8>> {
if parse {
Ok(reader.read_u8_vec(len)?)
} else {
reader.skip(len as i64)?;
Ok(Vec::new())
}
}