From 4deac1e38c0db43479cb1295dd4028e1599ee0bc Mon Sep 17 00:00:00 2001
From: Daniel Schadt <kingdread@gmx.de>
Date: Fri, 24 May 2019 16:49:34 +0200
Subject: add support for partially parsing an EVTC file

---
 src/raw/parser.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 46 insertions(+), 7 deletions(-)

(limited to 'src')

diff --git a/src/raw/parser.rs b/src/raw/parser.rs
index a3a1cd5..fa3b36c 100644
--- a/src/raw/parser.rs
+++ b/src/raw/parser.rs
@@ -97,6 +97,16 @@ pub struct Evtc {
     pub events: Vec<CbtEvent>,
 }
 
+/// A partially-parsed EVTC file, containing everything but the events.
+/// This can speed up parsing for applications which can work with the header.
+#[derive(Clone, Debug)]
+pub struct PartialEvtc {
+    pub header: Header,
+    pub skill_count: u32,
+    pub agents: Vec<Agent>,
+    pub skills: Vec<Skill>,
+}
+
 quick_error! {
     #[derive(Debug)]
     pub enum ParseError {
@@ -391,25 +401,54 @@ pub fn parse_event_rev1<T: Read>(input: &mut T) -> ParseResult<CbtEvent> {
         is_offcycle,
     })
 }
-/// Parse a complete EVTC file.
+
+
+
+/// Parse a partial EVTC file.
 ///
 /// * `input` - Input stream.
-pub fn parse_file<T: Read>(input: &mut T) -> ParseResult<Evtc> {
+pub fn parse_partial_file<T: Read>(input: &mut T) -> ParseResult<PartialEvtc> {
     let header = parse_header(input)?;
     let agents = parse_agents(input, header.agent_count)?;
     let skill_count = input.read_u32::<LittleEndian>()?;
     let skills = parse_skills(input, skill_count)?;
-    let events = match header.revision {
+
+    Ok(PartialEvtc {
+        header,
+        skill_count,
+        agents,
+        skills,
+    })
+}
+
+
+
+/// Finish a partial EVTC by reading the events.
+///
+/// * `partial` - The partial EVTC.
+/// * `input` - The input stream.
+pub fn finish_parsing<T: Read>(partial: PartialEvtc, input: &mut T) -> ParseResult<Evtc> {
+    let events = match partial.header.revision {
         0 => parse_events(input, parse_event_rev0)?,
         1 => parse_events(input, parse_event_rev1)?,
         x => return Err(ParseError::UnknownRevision(x)),
     };
 
     Ok(Evtc {
-        header,
-        skill_count,
-        agents,
-        skills,
+        header: partial.header,
+        skill_count: partial.skill_count,
+        agents: partial.agents,
+        skills: partial.skills,
         events,
     })
 }
+
+
+
+/// Parse a complete EVTC file.
+///
+/// * `input` - Input stream.
+pub fn parse_file<T: Read>(input: &mut T) -> ParseResult<Evtc> {
+    let partial = parse_partial_file(input)?;
+    finish_parsing(partial, input)
+}
-- 
cgit v1.2.3


From 3c94665d71d4b9be746d5e3456c3d2ef7521b7fd Mon Sep 17 00:00:00 2001
From: Daniel Schadt <kingdread@gmx.de>
Date: Fri, 24 May 2019 17:41:09 +0200
Subject: add public method to parse raw::Agent to Agent

---
 src/lib.rs | 121 ++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 63 insertions(+), 58 deletions(-)

(limited to 'src')

diff --git a/src/lib.rs b/src/lib.rs
index 010944f..a3bf64d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -133,6 +133,68 @@ pub struct Agent {
     master_agent: Option<u64>,
 }
 
+impl Agent {
+    /// Parse a raw agent.
+    pub fn from_raw(raw_agent: &raw::Agent) -> Result<Agent, EvtcError> {
+        let kind = if raw_agent.is_character() {
+            AgentKind::Character(raw_agent.prof as u16)
+        } else if raw_agent.is_gadget() {
+            AgentKind::Gadget(raw_agent.prof as u16)
+        } else if raw_agent.is_player() {
+            AgentKind::Player {
+                profession: raw_agent.prof,
+                elite: raw_agent.is_elite,
+            }
+        } else {
+            return Err(EvtcError::InvalidData);
+        };
+
+        let name = if raw_agent.is_player() {
+            let first = raw_agent
+                .name
+                .iter()
+                .cloned()
+                .take_while(|c| *c != 0)
+                .collect::<Vec<_>>();
+            let second = raw_agent
+                .name
+                .iter()
+                .cloned()
+                .skip(first.len() + 1)
+                .take_while(|c| *c != 0)
+                .collect::<Vec<_>>();
+            let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
+            AgentName::Player {
+                character_name: String::from_utf8(first)?,
+                account_name: String::from_utf8(second)?,
+                subgroup: third,
+            }
+        } else {
+            let name = raw_agent
+                .name
+                .iter()
+                .cloned()
+                .take_while(|c| *c != 0)
+                .collect::<Vec<_>>();
+            AgentName::Single(String::from_utf8(name)?)
+        };
+
+        Ok(Agent {
+            addr: raw_agent.addr,
+            kind,
+            toughness: raw_agent.toughness,
+            concentration: raw_agent.concentration,
+            healing: raw_agent.healing,
+            condition: raw_agent.condition,
+            name,
+            instance_id: 0,
+            first_aware: 0,
+            last_aware: u64::max_value(),
+            master_agent: None,
+        })
+    }
+}
+
 /// A fully processed log file.
 #[derive(Debug, Clone)]
 pub struct Log {
@@ -243,64 +305,7 @@ fn setup_agents(data: &raw::Evtc) -> Result<Vec<Agent>, EvtcError> {
     let mut agents = Vec::with_capacity(data.agents.len());
 
     for raw_agent in &data.agents {
-        let kind = if raw_agent.is_character() {
-            AgentKind::Character(raw_agent.prof as u16)
-        } else if raw_agent.is_gadget() {
-            AgentKind::Gadget(raw_agent.prof as u16)
-        } else if raw_agent.is_player() {
-            AgentKind::Player {
-                profession: raw_agent.prof,
-                elite: raw_agent.is_elite,
-            }
-        } else {
-            return Err(EvtcError::InvalidData);
-        };
-
-        let name = if raw_agent.is_player() {
-            let first = raw_agent
-                .name
-                .iter()
-                .cloned()
-                .take_while(|c| *c != 0)
-                .collect::<Vec<_>>();
-            let second = raw_agent
-                .name
-                .iter()
-                .cloned()
-                .skip(first.len() + 1)
-                .take_while(|c| *c != 0)
-                .collect::<Vec<_>>();
-            let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
-            AgentName::Player {
-                character_name: String::from_utf8(first)?,
-                account_name: String::from_utf8(second)?,
-                subgroup: third,
-            }
-        } else {
-            let name = raw_agent
-                .name
-                .iter()
-                .cloned()
-                .take_while(|c| *c != 0)
-                .collect::<Vec<_>>();
-            AgentName::Single(String::from_utf8(name)?)
-        };
-
-        let agent = Agent {
-            addr: raw_agent.addr,
-            kind,
-            toughness: raw_agent.toughness,
-            concentration: raw_agent.concentration,
-            healing: raw_agent.healing,
-            condition: raw_agent.condition,
-            name,
-            instance_id: 0,
-            first_aware: 0,
-            last_aware: u64::max_value(),
-            master_agent: None,
-        };
-
-        agents.push(agent);
+        agents.push(Agent::from_raw(raw_agent)?);
     }
     Ok(agents)
 }
-- 
cgit v1.2.3