mmd 0.0.6

Miku Miku Dance format parser for rust programming language
use crate::{pmx::types::*, reader::helpers::ReadHelpers, Error, Settings};
use byteorder::{ReadBytesExt, LE};
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::io::Read;

pub struct HeaderReader<R> {
  pub version: f32,
  pub settings: Settings,
  pub model_local_name: String,
  pub model_universal_name: String,
  pub local_comments: String,
  pub universal_comments: String,
  pub(crate) read: R,
}

impl<R: Read> HeaderReader<R> {
  pub fn new(mut read: R) -> Result<HeaderReader<R>, Error> {
    let mut magic = [0u8; 4];
    read.read_exact(&mut magic)?;
    if magic != [0x50, 0x4D, 0x58, 0x20] {
      return Err(Error::WrongSignature(magic));
    }

    let version = read.read_f32::<LE>()?;
    let globals_count = read.read_u8()?;
    if globals_count < 8 {
      return Err(Error::GlobalsCountLessThan8(globals_count));
    }

    let mut globals = Vec::with_capacity(globals_count as usize);
    globals.resize(globals_count as usize, 0u8);
    read.read_exact(&mut globals)?;

    let settings = Settings {
      text_encoding: TextEncoding::try_from(globals[0])?,
      additional_vec4_count: globals[1],
      vertex_index_size: IndexSize::try_from(globals[2])?,
      texture_index_size: IndexSize::try_from(globals[3])?,
      material_index_size: IndexSize::try_from(globals[4])?,
      bone_index_size: IndexSize::try_from(globals[5])?,
      morph_index_size: IndexSize::try_from(globals[6])?,
      rigidbody_index_size: IndexSize::try_from(globals[7])?,
    };

    Ok(HeaderReader::<R> {
      version,
      settings,
      model_local_name: read.read_text(settings.text_encoding)?,
      model_universal_name: read.read_text(settings.text_encoding)?,
      local_comments: read.read_text(settings.text_encoding)?,
      universal_comments: read.read_text(settings.text_encoding)?,
      read,
    })
  }
}

impl<R> Display for HeaderReader<R> {
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    write!(f, "version: {}, ", self.version)?;
    self.settings.fmt(f)?;
    writeln!(
      f,
      "local name: {}, universal name: {}\nLocal comments\n{}\nUniversal comments\n{}",
      self.model_local_name,
      self.model_universal_name,
      self.local_comments,
      self.universal_comments
    )
  }
}