606 lines · 23.2 KB · C#
RawDownload
//******************************************************************************************************//  BinaryImageParserBase.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  02/12/2007 - J. Ritchie Carroll//       Generated original version of source code.//  08/07/2009 - Josh L. Patterson//       Edited Comments.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  11/23/2011 - J. Ritchie Carroll//       Modified to support buffer optimized ISupportBinaryImage.//  12/14/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.ComponentModel;using System.IO;using System.Text;using GSF.Units; namespace GSF.Parsing{    /// <summary>    /// This class defines the fundamental functionality for parsing any stream of binary data.    /// </summary>    /// <remarks>    /// This parser is designed as a write-only stream such that data can come from any source.    /// </remarks>    public abstract class BinaryImageParserBase : Stream, IBinaryImageParser    {        #region [ Members ]         /// <summary>        /// Specifies the default value for the <see cref="ProtocolSyncBytes"/> property.        /// </summary>        public static readonly byte[] DefaultProtocolSyncBytes = new byte[] { 0xAA };         // Events         /// <summary>        /// Occurs when data image fails deserialized due to an exception.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the remaining portion of the binary image that failed to parse.        /// </remarks>        public event EventHandler<EventArgs<byte[]>> DataDiscarded;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered while attempting to parse data.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the <see cref="Exception"/> encountered while parsing data.        /// </remarks>        public event EventHandler<EventArgs<Exception>> ParsingException;         /// <summary>        /// Occurs when buffer parsing has completed.        /// </summary>        public event EventHandler BufferParsed;         // Fields         /// <summary>        /// Tracks if data stream has been initialized.        /// </summary>        /// <remarks>        /// Only relevant if <see cref="ProtocolUsesSyncBytes"/> is true.        /// </remarks>        protected bool StreamInitialized;         /// <summary>        /// Remaining unparsed buffer from last parsing execution, if any.        /// </summary>        protected byte[] UnparsedBuffer;         private byte[] m_protocolSyncBytes;        private long m_buffersProcessed;        private string m_name;        private Ticks m_startTime;        private Ticks m_stopTime;        private bool m_enabled;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="BinaryImageParserBase"/> class.        /// </summary>        protected BinaryImageParserBase()        {            m_protocolSyncBytes = DefaultProtocolSyncBytes;            m_name = this.GetType().Name;        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets a boolean value that indicates whether the data parser is currently enabled.        /// </summary>        /// <remarks>        /// Setting <see cref="Enabled"/> to true will start the <see cref="BinaryImageParserBase"/> if it is not started,        /// setting to false will stop the <see cref="BinaryImageParserBase"/> if it is started.        /// </remarks>        public virtual bool Enabled        {            get            {                return m_enabled;            }            set            {                if (value && !m_enabled)                    Start();                else if (!value && m_enabled)                    Stop();            }        }         /// <summary>        /// Gets flag that determines if this protocol parsing implementation uses synchronization bytes.        /// </summary>        public abstract bool ProtocolUsesSyncBytes        {            get;        }         /// <summary>        /// Gets or sets synchronization bytes for this parsing implementation, if used.        /// </summary>        public virtual byte[] ProtocolSyncBytes        {            get            {                return m_protocolSyncBytes;            }            set            {                m_protocolSyncBytes = value;            }        }         /// <summary>        /// Gets the total amount of time, in seconds, that the <see cref="BinaryImageParserBase"/> has been active.        /// </summary>        public Time RunTime        {            get            {                Ticks processingTime = 0;                 if (m_startTime > 0)                {                    if (m_stopTime > 0)                        processingTime = m_stopTime - m_startTime;                    else                        processingTime = DateTime.Now.Ticks - m_startTime;                }                 if (processingTime < 0)                    processingTime = 0;                 return processingTime.ToSeconds();            }        }         /// <summary>        /// Gets the total number of buffer images processed so far.        /// </summary>        /// <returns>Total number of buffer images processed so far.</returns>        public long TotalProcessedBuffers        {            get            {                return m_buffersProcessed;            }        }         /// <summary>        /// Gets a value indicating whether the current stream supports reading.        /// </summary>        /// <remarks>        /// The <see cref="BinaryImageParserBase"/> is implemented as a WriteOnly stream, so this defaults to false.        /// </remarks>        public override bool CanRead        {            get            {                return false;            }        }         /// <summary>        /// Gets a value indicating whether the current stream supports seeking.        /// </summary>        /// <remarks>        /// The <see cref="BinaryImageParserBase"/> is implemented as a WriteOnly stream, so this defaults to false.        /// </remarks>        public override bool CanSeek        {            get            {                return false;            }        }         /// <summary>        /// Gets a value indicating whether the current stream supports writing.        /// </summary>        /// <remarks>        /// The <see cref="BinaryImageParserBase"/> is implemented as a WriteOnly stream, so this defaults to true.        /// </remarks>        public override bool CanWrite        {            get            {                return true;            }        }         /// <summary>        /// Gets current status of <see cref="BinaryImageParserBase"/>.        /// </summary>        public virtual string Status        {            get            {                StringBuilder status = new StringBuilder();                 status.Append("      Current parser state: ");                status.Append(m_enabled ? "Active" : "Idle");                status.AppendLine();                 if (ProtocolUsesSyncBytes)                {                    status.Append("Data synchronization bytes: 0x");                    status.Append(ByteEncoding.Hexadecimal.GetString(ProtocolSyncBytes));                    status.AppendLine();                }                 status.Append("     Total parser run-time: ");                status.Append(RunTime.ToString());                status.AppendLine();                status.Append("   Total buffers processed: ");                status.Append(m_buffersProcessed);                status.AppendLine();                 return status.ToString();            }        }         /// <summary>        /// Gets the name of <see cref="BinaryImageParserBase"/>.        /// </summary>        public virtual string Name        {            get            {                return m_name;            }            set            {                m_name = value;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Start the streaming data parser.        /// </summary>        public virtual void Start()        {            // Reset statistics            m_buffersProcessed = 0;            m_stopTime = 0;            m_startTime = DateTime.Now.Ticks;             // Initialized state depends whether or not derived class uses a protocol synchronization byte            StreamInitialized = !ProtocolUsesSyncBytes;             m_enabled = true;        }         /// <summary>        /// Stops the streaming data parser.        /// </summary>        public virtual void Stop()        {            m_enabled = false;            m_stopTime = DateTime.Now.Ticks;        }         /// <summary>        /// Parses the object implementing the <see cref="ISupportBinaryImage"/> interface.        /// </summary>        /// <param name="image">Object to be parsed that implements the <see cref="ISupportBinaryImage"/> interface.</param>        /// <remarks>        /// This function takes the binary image from <see cref="ISupportBinaryImage"/> and writes the buffer to the <see cref="BinaryImageParserBase"/> stream for parsing.        /// </remarks>        public virtual void Parse(ISupportBinaryImage image)        {            int length = image.BinaryLength;            byte[] buffer = new byte[length];             // Generate the binary image            image.GenerateBinaryImage(buffer, 0);             // Write the buffer to the parsing queue            Write(buffer, 0, length);        }         // Stream implementation overrides         /// <summary>        /// Writes a sequence of bytes onto the stream for parsing.        /// </summary>        /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>        /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>        /// <param name="count">The number of bytes to be written to the current stream.</param>        public override void Write(byte[] buffer, int offset, int count)        {            if (m_enabled)            {                // If ProtocolUsesSyncByte is true, first call to write after start will be uninitialized,                // thus the attempt below to "align" data stream to specified ProtocolSyncBytes.                if (StreamInitialized)                {                    // Directly parse frame using calling thread (typically communications thread)                    ParseBuffer(buffer, offset, count);                }                else                {                    // Initial stream may be anywhere in the middle of a frame, so we attempt to locate sync byte(s) to "line-up" data stream                    int syncBytesPosition = buffer.IndexOfSequence(ProtocolSyncBytes, offset, count);                     if (syncBytesPosition > -1)                    {                        StreamInitialized = true;                        ParseBuffer(buffer, syncBytesPosition, count - (syncBytesPosition - offset));                    }                }                 // Track total processed buffer images                m_buffersProcessed++;            }        }         /// <summary>        /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data        /// to be written to the underlying device.        /// </summary>        public override void Flush()        {        }         #region [ Unimplemented Stream Overrides ]         // The parser is designed as a write only stream - so the following methods do not apply         /// <summary>        /// The parser is designed as a write only stream, so this method is not implemented.        /// </summary>        /// <exception cref="NotImplementedException">Cannot read from WriteOnly stream.</exception>        /// <param name="buffer">Array of <see cref="Byte"/>s.</param>        /// <param name="count">An <see cref="Int32"/> value for the offset.</param>        /// <param name="offset">An <see cref="Int32"/> value for the count.</param>        /// <returns>An <see cref="Int32"/> as the number of bytes read. Well. It would, if implemented.</returns>        [EditorBrowsable(EditorBrowsableState.Never)]        public override int Read(byte[] buffer, int offset, int count)        {            throw new NotImplementedException("Cannot read from WriteOnly stream");        }         /// <summary>        /// The parser is designed as a write only stream, so this method is not implemented.        /// </summary>        /// <exception cref="NotImplementedException">WriteOnly stream has no position.</exception>        /// <param name="offset">A <see cref="Int64"/> value for the offset.</param>        /// <param name="origin">A <see cref="SeekOrigin"/>.</param>        /// <returns>Returns a <see cref="Int64"/> value indicating the point that was sought.</returns>        [EditorBrowsable(EditorBrowsableState.Never)]        public override long Seek(long offset, SeekOrigin origin)        {            throw new NotImplementedException("WriteOnly stream has no position");        }         /// <summary>        /// The parser is designed as a write only stream, so this method is not implemented.        /// </summary>        /// <exception cref="NotImplementedException">WriteOnly stream has no length.</exception>        /// <param name="value">A <see cref="Int64"/> value.</param>        [EditorBrowsable(EditorBrowsableState.Never)]        public override void SetLength(long value)        {            throw new NotImplementedException("WriteOnly stream has no length");        }         /// <summary>        /// The parser is designed as a write only stream, so this method is not implemented.        /// </summary>        /// <remarks>        /// WriteOnly stream has no length. Returned value will always be -1.        /// </remarks>        [EditorBrowsable(EditorBrowsableState.Never)]        public override long Length        {            get            {                return -1;            }        }         /// <summary>        /// The parser is designed as a write only stream, so this method is not implemented.        /// </summary>        /// <remarks>        /// WriteOnly stream has no position. Returned value will always be -1 and any assigned value will be ignored.        /// </remarks>        [EditorBrowsable(EditorBrowsableState.Never)]        public override long Position        {            get            {                return -1;            }            set            {            }        }         #endregion         // Parse buffer image - user implements protocol specific "ParseFrame" function to extract data from image        private void ParseBuffer(byte[] buffer, int offset, int count)        {            int endOfBuffer = 0;             try            {                // Prepend any left over buffer data from last parse call                if ((object)UnparsedBuffer != null)                {                    // Combine remaining buffer from last call and current buffer together as a single image                    buffer = UnparsedBuffer.Combine(0, UnparsedBuffer.Length, buffer, offset, count);                    offset = 0;                    count = buffer.Length;                    UnparsedBuffer = null;                }                 endOfBuffer = offset + count - 1;                int parsedFrameLength;                 // Move through buffer parsing all available frames                while (!(offset > endOfBuffer) && m_enabled)                {                    try                    {                        // Call derived class frame parsing algorithm - this is protocol specific                        parsedFrameLength = ParseFrame(buffer, offset, endOfBuffer - offset + 1);                    }                    catch (Exception ex)                    {                        // If protocol defines synchronization bytes there's a chance at recovering any unused portion of this buffer,                        // otherwise we'll just rethrow the exception and scrap the buffer...                        if (ProtocolUsesSyncBytes)                        {                            // Attempt to locate sync byte(s) after exception to line data stream back up                            int syncBytesPosition = buffer.IndexOfSequence(ProtocolSyncBytes, offset + 1, endOfBuffer - offset);                             if (syncBytesPosition > -1)                            {                                // Found the next sync byte(s), pass through malformed frame                                parsedFrameLength = syncBytesPosition - offset;                                 // We'll still let consumer know there was an issue                                OnDataDiscarded(buffer.BlockCopy(offset, parsedFrameLength));                                OnParsingException(ex);                            }

Lines 1–500 of 606.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t