#![recursion_limit = "256"]
#![deny(unsafe_code)]
extern crate async_stream;
extern crate byteorder;
extern crate error_chain;
extern crate futures_core;
extern crate tokio;
use error_chain::{bail, error_chain};
use futures_core::stream::Stream;
use tokio::io::{AsyncRead, AsyncReadExt as _};
pub struct Decoder<R> {
read: R,
}
impl<R> Decoder<R> {
pub fn new(read: R) -> Self {
Decoder { read }
}
}
impl<R> Decoder<R>
where
R: AsyncRead + Unpin,
{
pub async fn read_async(
self,
) -> Result<(
HeaderInfo,
impl Stream<Item = Result<(FrameInfo, Vec<u8>)>> + Unpin,
)> {
let mut read = self.read;
let info = read_header_async(&mut read).await?;
let stream = new_async_stream(read, &info);
Ok((info, stream))
}
}
fn new_async_stream(
read: impl AsyncRead + Unpin,
info: &HeaderInfo,
) -> impl Stream<Item = Result<(FrameInfo, Vec<u8>)>> + Unpin {
use async_stream::try_stream;
use byteorder::{ByteOrder as _, NativeEndian as NE};
use std::cmp::max;
let pixel_width = info.pixel_width;
let pixel_height = info.pixel_height;
let pixel_depth = info.pixel_depth;
let nlayers = max(1, info.number_of_array_elements);
let nfaces = max(1, info.number_of_faces);
let nlevels = info.number_of_mipmap_levels;
let is_cubemap = info.number_of_faces == 6 && info.number_of_array_elements == 0;
Box::pin(try_stream! {
let mut read = read;
for level in 0..nlevels {
let image_size = {
let mut buf = [0_u8; 4];
read.read_exact(&mut buf).await?;
NE::read_u32(&buf)
};
assert!(image_size % 4 == 0);
let pixel_width = max(1, pixel_width >> level);
let pixel_height = max(1, pixel_height >> level);
let pixel_depth = max(1, pixel_depth >> level);
let face_size = if is_cubemap {
image_size
} else {
assert!(image_size % nlayers == 0);
let layer_size = image_size / nlayers;
assert!(layer_size % 4 == 0);
assert!(layer_size % nfaces == 0);
layer_size / nfaces
};
assert!(face_size % 4 == 0);
let buf_size = face_size as usize;
for layer in 0..nlayers {
for face in 0..nfaces {
let mut buf = vec![0_u8; buf_size];
read.read_exact(&mut buf).await?;
let frame_info = FrameInfo {
level,
layer,
face,
pixel_width,
pixel_height,
pixel_depth,
};
yield (frame_info, buf);
}
}
}
})
}
#[derive(Debug, Clone)]
pub struct FrameInfo {
pub level: u32,
pub layer: u32,
pub face: u32,
pub pixel_width: u32,
pub pixel_height: u32,
pub pixel_depth: u32,
}
#[derive(Debug, Clone)]
pub struct HeaderInfo {
pub gl_type: u32,
pub gl_type_size: u32,
pub gl_format: u32,
pub gl_internal_format: u32,
pub gl_base_internal_format: u32,
pub pixel_width: u32,
pub pixel_height: u32,
pub pixel_depth: u32,
pub number_of_array_elements: u32,
pub number_of_faces: u32,
pub number_of_mipmap_levels: u32,
pub key_value_data: KeyValueData,
}
impl HeaderInfo {
pub fn mipmap_size(&self, level: u32) -> (u32, u32, u32) {
use std::cmp::max;
let w = max(1, self.pixel_width >> level);
let h = max(1, self.pixel_height >> level);
let d = max(1, self.pixel_depth >> level);
(w, h, d)
}
}
async fn read_header_async(mut reader: impl AsyncRead + Unpin) -> Result<HeaderInfo> {
use byteorder::{ByteOrder as _, NativeEndian as NE};
let buf = {
let mut v = [0_u8; 64];
reader.read_exact(&mut v).await?;
v
};
{
let magic: &[u8] = &buf[0..12];
if magic != MAGIC {
let mut m = [0_u8; 12];
m.copy_from_slice(magic);
bail!(ErrorKind::InvalidFormat(m));
}
}
let endianness = NE::read_u32(&buf[12..16]);
let gl_type = NE::read_u32(&buf[16..20]);
let gl_type_size = NE::read_u32(&buf[20..24]);
let gl_format = NE::read_u32(&buf[24..28]);
let gl_internal_format = NE::read_u32(&buf[28..32]);
let gl_base_internal_format = NE::read_u32(&buf[32..36]);
let pixel_width = NE::read_u32(&buf[36..40]);
let pixel_height = NE::read_u32(&buf[40..44]);
let pixel_depth = NE::read_u32(&buf[44..48]);
let number_of_array_elements = NE::read_u32(&buf[48..52]);
let number_of_faces = NE::read_u32(&buf[52..56]);
let number_of_mipmap_levels = NE::read_u32(&buf[56..60]);
let bytes_of_key_value_data = NE::read_u32(&buf[60..64]);
if number_of_mipmap_levels == 0 {
bail!(ErrorKind::InvalidNumberOfMipmapLevels(
number_of_mipmap_levels
));
}
if (endianness == ENDIANNESS) && (bytes_of_key_value_data % 4 == 0) {
let mut kvbuf = vec![0; bytes_of_key_value_data as usize];
reader.read_exact(&mut kvbuf).await?;
let info = HeaderInfo {
gl_type,
gl_type_size,
gl_format,
gl_internal_format,
gl_base_internal_format,
pixel_width,
pixel_height,
pixel_depth,
number_of_array_elements,
number_of_faces,
number_of_mipmap_levels,
key_value_data: KeyValueData { raw: kvbuf },
};
Ok(info)
} else {
bail!(ErrorKind::MismatchedEndianness(ENDIANNESS, endianness));
}
}
error_chain! {
types {
Error, ErrorKind, ResultExt, Result;
}
foreign_links {
Io(::std::io::Error);
}
errors {
InvalidFormat(magic: [u8;12]) {
}
MismatchedEndianness(expect: u32, actual: u32) {
}
InvalidNumberOfMipmapLevels(v: u32) {
}
}
}
const MAGIC: [u8; 12] = [
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A,
];
const ENDIANNESS: u32 = 0x0403_0201;
#[derive(Clone)]
pub struct KeyValueData {
raw: Vec<u8>,
}
pub struct Entries<'a>(&'a [u8]);
impl KeyValueData {
pub fn iter(&self) -> Entries {
Entries(&self.raw)
}
}
impl<'a> Iterator for Entries<'a> {
type Item = (&'a str, &'a [u8]);
fn next(&mut self) -> Option<Self::Item> {
use byteorder::{ByteOrder, NativeEndian};
use std::str::from_utf8;
if self.0.is_empty() {
return None;
}
let (len_bytes, resting) = self.0.split_at(4);
let len = NativeEndian::read_u32(len_bytes);
let (kv, nextbuf) = resting.split_at(force_align(len) as usize);
let (kv, _padding) = kv.split_at(len as usize);
self.0 = nextbuf;
let nul_idx = kv
.iter()
.enumerate()
.filter(|(_, x)| **x == 0)
.map(|(i, _)| i)
.nth(0)
.unwrap();
let (key, value) = kv.split_at(nul_idx);
let value = value.split_at(1).1;
let key = from_utf8(key).unwrap();
Some((key, value))
}
}
impl std::fmt::Debug for KeyValueData {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "KeyValueData[")?;
for (key, value) in self.iter() {
write!(f, "({:?}, bytes(len={})), ", key, value.len())?;
}
write!(f, "]")
}
}
#[inline]
fn force_align(x: u32) -> u32 {
(x + 0x3) & 0xFFFF_FFFC
}