/* * Yubeshi GPS Parser * * This software is distributed under a zlib-style license. * See license.txt for more information. */ using System; using System.Collections.Generic; using System.Text; using System.IO; namespace Yubeshi { public class Parser { #region type definitions public enum Protocol : int { Nmea = 0, Ubx, } public delegate bool TrialParser( byte[] sentence, out UnknownPacket packet); public delegate int SyncSearcher(byte[] input, int offset); protected struct ParserFunctions { public TrialParser TryParse; public SyncSearcher SearchSyncFrom; public ParserFunctions(TrialParser parser, SyncSearcher searcher) { TryParse = parser; SearchSyncFrom = searcher; } } private struct SyncIndex { public int Index; public Protocol Protocol; public SyncIndex(int index, Protocol protocol) { Index = index; Protocol = protocol; } } #endregion #region fields private byte[] buffer = new byte[0]; private List packets = new List(); private static Dictionary functions = new Dictionary(); #endregion #region constructors static Parser() { Bind(Protocol.Nmea, Nmea.Parser.TryParse, Nmea.Parser.SearchSyncFrom); Bind(Protocol.Ubx, Ubx.Parser.TryParse, Ubx.Parser.SearchSyncFrom); } public Parser() { } #endregion #region public methods public void Push(byte[] fragment) { Concat(fragment); ParseBuffer(functions); } public UnknownPacket Peek() { if (packets.Count < 1) { return null; } UnknownPacket head = packets[0]; packets.RemoveAt(0); return head; } public static bool TryParse(byte[] sentence, out UnknownPacket packet) { foreach (Protocol p in functions.Keys) { if (functions[p].TryParse(sentence, out packet)) { return true; } } packet = null; return false; } public static void Bind(Protocol protocol, TrialParser parser, SyncSearcher searcher) { functions[protocol] = new ParserFunctions(parser, searcher); } public static void Unbind(Protocol protocol) { functions.Remove(protocol); } #endregion #region protected methods protected void Concat(byte[] fragment) { buffer = OctetString.Concat(buffer, fragment); } protected void ParseBuffer( Dictionary functions) { Comparison sorter = delegate(SyncIndex a, SyncIndex b) { return a.Index - b.Index; }; List found = new List(); int offset = 0; while (offset < buffer.Length) { foreach (Protocol p in functions.Keys) { int index = functions[p].SearchSyncFrom(buffer, offset); if (index >= 0) { SyncIndex s = new SyncIndex(index, p); if (!found.Contains(s)) { found.Add(s); } } } if (found.Count == 0) { if (offset == 0) { packets.Add(new UnknownPacket(buffer, buffer.Length)); buffer = new byte[0]; } return; } found.Sort(sorter); SyncIndex first = found[0]; byte[] synced = OctetString.Substring(buffer, first.Index); UnknownPacket packet = null; if (functions[first.Protocol].TryParse(synced, out packet)) { if (first.Index > 0) { packets.Add(new UnknownPacket(buffer, first.Index)); } packets.Add(packet); buffer = OctetString.Substring(synced, packet.Raw.Length); ParseBuffer(functions); return; } offset = first.Index + 1; found.RemoveAt(0); } } #endregion #region private methods #endregion } }