use std::io::Read;
use reader::error::{Result, Error, ErrorKind};
use reader::{FbxEvent, ParserConfig};
use common::FbxFormatType;
use self::binary::BinaryParser;
use self::ascii::AsciiParser;
mod macros;
mod ascii;
mod binary;
#[derive(Debug, Clone)]
enum ParserState {
Magic,
Binary(BinaryParser),
Ascii(AsciiParser),
}
#[derive(Debug, Clone)]
struct CommonState {
pos: u64,
final_result: Option<Result<FbxEvent>>,
}
pub struct Parser {
config: ParserConfig,
common: CommonState,
state: ParserState,
}
impl Parser {
pub fn new(config: ParserConfig) -> Self {
Parser {
config: config,
common: CommonState {
pos: 0,
final_result: None,
},
state: ParserState::Magic,
}
}
pub fn next<R: Read>(&mut self, reader: &mut R) -> Result<FbxEvent> {
if let Some(ref result) = self.common.final_result {
return result.clone();
}
let result;
loop {
let r = match self.state {
ParserState::Magic => self.magic_next(reader),
ParserState::Binary(ref mut parser) => parser.next(reader, &mut self.common),
ParserState::Ascii(ref mut parser) => parser.next(reader, &mut self.common),
};
if self.config.ignore_comments {
match r {
Ok(FbxEvent::Comment(_)) => {},
r => {
result = r;
break;
}
}
} else {
result = r;
break;
}
}
match result {
Ok(FbxEvent::EndFbx) | Err(_) => {
self.common.final_result = Some(result.clone());
},
_ => {}
}
result
}
fn magic_next<R: Read>(&mut self, reader: &mut R) -> Result<FbxEvent> {
let mut first_line_bytes = Vec::with_capacity(20);
let magic_end_byte;
loop {
let c = try_read_le_u8!(self.common.pos, reader);
if (c == 0) || (c == ('\n' as u8)) {
magic_end_byte = c;
break;
}
first_line_bytes.push(c);
}
if magic_end_byte == 0 {
if first_line_bytes == b"Kaydara FBX Binary " {
{
let bytes = try_read_exact!(self.common.pos, reader, 2);
if bytes != vec![0x1A, 0x00] {
warn!("expected [0x1A, 0x00] right after magic, but got {:?}", bytes);
}
}
let version = try_read_le_u32!(self.common.pos, reader);
debug!("magic binary read, Binary FBX (version={})", version);
self.state = ParserState::Binary(BinaryParser::new(version));
Ok(FbxEvent::StartFbx(FbxFormatType::Binary(version)))
} else {
Err(Error::new(self.common.pos, ErrorKind::InvalidMagic))
}
} else {
assert_eq!(magic_end_byte, ('\n' as u8));
let mut buffer;
if first_line_bytes[0] != (';' as u8) {
buffer = try_with_pos!(self.common.pos, String::from_utf8(first_line_bytes));
buffer.push('\n');
} else {
buffer = String::new();
}
self.state = ParserState::Ascii(AsciiParser::new(buffer));
Ok(FbxEvent::StartFbx(FbxFormatType::Ascii))
}
}
}