use std::fmt;
use std::io::{Cursor, Read, Seek, SeekFrom, Write, Result};
use byteorder::{LE, ReadBytesExt, WriteBytesExt};
use crate::header::Header;
use crate::Label;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum FieldType {
Byte,
Char,
Word,
Short,
Dword,
Int,
Dword64,
Int64,
Float,
Double,
String,
ResRef,
LocString,
Void,
Struct,
List,
}
impl FieldType {
#[inline]
pub fn is_complex(&self) -> bool {
use self::FieldType::*;
match *self {
Dword64 | Int64 | Double | String | ResRef | LocString | Void => true,
_ => false
}
}
#[inline]
pub fn is_simple(&self) -> bool {
!self.is_complex() && *self != FieldType::Struct && *self != FieldType::List
}
#[inline]
fn from_u32(value: u32) -> Option<Self> {
use self::FieldType::*;
Some(match value {
0 => Byte,
1 => Char,
2 => Word,
3 => Short,
4 => Dword,
5 => Int,
6 => Dword64,
7 => Int64,
8 => Float,
9 => Double,
10 => String,
11 => ResRef,
12 => LocString,
13 => Void,
14 => Struct,
15 => List,
_ => return None,
})
}
}
#[cfg(nightly)]
impl TryFrom<u32> for FieldType {
type Error = NoneError;
#[inline]
fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(self.from_u32(value)?)
}
}
pub struct Struct {
pub tag: u32,
pub offset: u32,
pub fields: u32,
}
impl Struct {
#[inline]
pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Struct {
tag: reader.read_u32::<LE>()?,
offset: reader.read_u32::<LE>()?,
fields: reader.read_u32::<LE>()?,
})
}
#[inline]
pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
writer.write_u32::<LE>(self.tag)?;
writer.write_u32::<LE>(self.offset)?;
writer.write_u32::<LE>(self.fields)?;
Ok(())
}
}
impl fmt::Debug for Struct {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Struct {{ tag: {:?}, offset: {:?}, fields: {:?} }}", self.tag, self.offset, self.fields)
}
}
pub struct Field {
pub tag: u32,
pub label: u32,
pub data: [u8; 4],
}
impl Field {
#[inline]
pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
let tag = reader.read_u32::<LE>()?;
let label = reader.read_u32::<LE>()?;
let mut data = [0u8; 4];
reader.read_exact(&mut data)?;
Ok(Field { tag, label, data })
}
#[inline]
pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
writer.write_u32::<LE>(self.tag as u32)?;
writer.write_u32::<LE>(self.label)?;
writer.write_all(&self.data)?;
Ok(())
}
}
impl fmt::Debug for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Field {{ tag: {:?}, label: {:?}, data: {:?} }}", self.tag, self.label, self.data)
}
}
struct FieldData<'a>(&'a [u8]);
impl<'a> fmt::Debug for FieldData<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[derive(Debug)]
struct DebugFieldData<'a> {
by_field: Vec<FieldData<'a>>,
raw: &'a [u8],
}
struct FieldIndex<'a>(&'a [u32]);
impl<'a> fmt::Debug for FieldIndex<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[derive(Debug)]
struct DebugFieldIndex<'a> {
by_struct: Vec<FieldIndex<'a>>,
raw: &'a [u32],
}
struct ListIndex<'a>(&'a [u32]);
impl<'a> fmt::Debug for ListIndex<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[derive(Debug)]
struct DebugListIndex<'a> {
by_list: Vec<ListIndex<'a>>,
raw: &'a [u32],
}
pub struct Gff {
pub header: Header,
pub structs: Vec<Struct>,
pub fields: Vec<Field>,
pub labels: Vec<Label>,
pub field_data: Vec<u8>,
pub field_indices: Vec<u32>,
pub list_indices: Vec<u32>,
}
macro_rules! read_exact {
($reader:expr, $section:expr, $type:ident) => ({
$reader.seek(SeekFrom::Start($section.offset as u64))?;
let mut vec = Vec::with_capacity($section.count as usize);
for _ in 0..$section.count {
vec.push($type::read($reader)?);
}
vec
});
}
macro_rules! read_into {
($reader:expr, $section:expr) => ({
$reader.seek(SeekFrom::Start($section.offset as u64))?;
let mut vec = Vec::with_capacity($section.count as usize);
unsafe { vec.set_len(($section.count / 4) as usize); }
$reader.read_u32_into::<LE>(&mut vec[..])?;
vec
});
}
macro_rules! write_all {
($writer:expr, $list:expr) => (
for elem in &$list {
elem.write($writer)?;
}
);
($writer:expr, $list:expr, LE) => (
for elem in &$list {
$writer.write_u32::<LE>(*elem)?;
}
);
}
impl Gff {
pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Gff> {
let header = Header::read(reader)?;
let structs = read_exact!(reader, header.structs, Struct);
let fields = read_exact!(reader, header.fields , Field);
reader.seek(SeekFrom::Start(header.labels.offset as u64))?;
let mut labels = Vec::with_capacity(header.labels.count as usize);
for _ in 0..header.labels.count {
let mut label = [0u8; 16];
reader.read_exact(&mut label)?;
labels.push(label.into());
}
reader.seek(SeekFrom::Start(header.field_data.offset as u64))?;
let mut field_data = Vec::with_capacity(header.field_data.count as usize);
unsafe { field_data.set_len(header.field_data.count as usize); }
reader.read_exact(&mut field_data[..])?;
let field_indices = read_into!(reader, header.field_indices);
let list_indices = read_into!(reader, header.list_indices);
Ok(Gff { header, structs, fields, labels, field_data, field_indices, list_indices })
}
pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
self.header.write(writer)?;
write_all!(writer, self.structs);
write_all!(writer, self.fields);
for label in &self.labels {
writer.write_all(label.as_ref())?;
}
writer.write_all(&self.field_data)?;
write_all!(writer, self.field_indices, LE);
write_all!(writer, self.list_indices, LE);
Ok(())
}
fn split_data<'a>(data: &'a [u8], offsets: &[u32]) -> DebugFieldData<'a> {
let it1 = offsets.iter();
let it2 = offsets.iter().skip(1);
let mut vec = Vec::with_capacity(offsets.len() - 1);
for (s, e) in it1.zip(it2) {
vec.push(FieldData(&data[*s as usize .. *e as usize]));
}
DebugFieldData { by_field: vec, raw: data }
}
fn split_fields<'a>(data: &'a [u32], offsets: &[(u32, u32)]) -> DebugFieldIndex<'a> {
let mut vec = Vec::with_capacity(offsets.len() - 1);
for (s, cnt) in offsets {
vec.push(FieldIndex(&data[*s as usize .. (*s + cnt) as usize]));
}
DebugFieldIndex { by_struct: vec, raw: data }
}
fn split_lists<'a>(data: &'a [u32]) -> DebugListIndex<'a> {
let mut vec = Vec::new();
let mut it = data.iter().enumerate();
while let Some((i, cnt)) = it.next() {
let from = i + 1;
let to = from + *cnt as usize;
vec.push(ListIndex(&data[from..to]));
while let Some((j, _)) = it.next() {
if j >= to { break; }
}
}
DebugListIndex { by_list: vec, raw: data }
}
}
impl fmt::Debug for Gff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let data_offsets: Vec<_> = self.fields.iter()
.filter(|f| FieldType::from_u32(f.tag).as_ref().map(FieldType::is_complex).unwrap_or(false))
.map(|f| Cursor::new(f.data).read_u32::<LE>().unwrap())
.collect();
let field_offsets: Vec<_> = self.structs.iter()
.filter(|s| s.fields > 1)
.map(|s| (s.offset / 4, s.fields))
.collect();
f.debug_struct("Gff")
.field("header", &self.header)
.field("structs", &self.structs)
.field("fields", &self.fields)
.field("labels", &self.labels)
.field("field_data", &Self::split_data(&self.field_data, &data_offsets))
.field("field_indices", &Self::split_fields(&self.field_indices, &field_offsets))
.field("list_indices", &Self::split_lists(&self.list_indices))
.finish()
}
}