//****************************************************************************************************** // LogicalParser.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: // ---------------------------------------------------------------------------------------------------- // 05/03/2012 - Stephen C. Wills, Grid Protection Alliance // Generated original version of source code. // 12/17/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using GSF.PQDIF.Physical; namespace GSF.PQDIF.Logical { /// /// Represents a parser which parses the logical structure of a PQDIF file. /// /// /// /// This class makes the data from PQD files readily available to applications and defines several /// redundant properties throughout the logical hierarchy of the PQDIF file to also facilitate /// the association of definitions with instances within the logical structure. The following /// list enumerates some of the more useful associations within the hierarchy. /// /// /// /// /// /// /// /// /// /// /// /// Usage consists of iterating through observations () to /// examine each of the the measurements recorded in the file. As was noted in the list above, /// the data source () and settings for the monitor /// () associated with each observation is exposed as a /// property on the observation record. Note that the same data source and monitor settings /// records may be referenced by multiple observation records in the file. /// /// /// /// The following example demonstrates how to read all observation records from a PQDIF file /// using the logical parser. /// /// /// observationRecords = new List(); /// string fileName = args[0]; /// /// using (LogicalParser parser = new LogicalParser(fileName)) /// { /// parser.Open(); /// containerRecord = parser.ContainerRecord; /// /// while (parser.HasNextObservationRecord()) /// observationRecords.Add(parser.NextObservationRecord()); /// } /// ]]> /// public class LogicalParser : IDisposable { #region [ Members ] // Fields private readonly PhysicalParser m_physicalParser; private ContainerRecord m_containerRecord; private DataSourceRecord m_currentDataSourceRecord; private MonitorSettingsRecord m_currentMonitorSettingsRecord; private ObservationRecord m_nextObservationRecord; private List m_allDataSourceRecords; #endregion #region [ Constructors ] /// /// Creates a new instance of the class. /// /// Path to the PQDIF file to be parsed. public LogicalParser(string filePath) { m_physicalParser = new PhysicalParser(filePath); m_allDataSourceRecords = new List(); } /// /// Creates a new instance of the class. /// /// The stream containing the PQDIF file data. /// True if the stream should be closed when the parser is closed; false otherwise. /// is null. /// is not both readable and seekable. public LogicalParser(Stream stream, bool leaveOpen = false) { m_physicalParser = new PhysicalParser(null); m_allDataSourceRecords = new List(); Open(stream, leaveOpen); } #endregion #region [ Properties ] /// /// Gets or sets the file path (not just the name) of the PQDIF file to be parsed. /// Obsolete in favor of . /// [Obsolete("Property is deprecated. Please use FilePath instead.")] [EditorBrowsable(EditorBrowsableState.Never)] public string FileName { get { return m_physicalParser.FilePath; } set { m_physicalParser.FilePath = value; } } /// /// Gets or sets the file path of the PQDIF file to be parsed. /// public string FilePath { get { return m_physicalParser.FilePath; } set { m_physicalParser.FilePath = value; } } /// /// Gets the container record from the PQDIF file. This is /// parsed as soon as the parser is ed. /// public ContainerRecord ContainerRecord { get { return m_containerRecord; } } /// /// Gets a list of all DataSource records from the PQDIF file. This is /// parsed when passing throug the observation records ed. /// public List DataSourceRecords { get { return m_allDataSourceRecords; } } #endregion #region [ Methods ] /// /// Opens the parser and parses the . /// /// has not been defined. /// An unsupported compression mode was defined in the PQDIF file. public void Open() { m_physicalParser.Open(); m_containerRecord = ContainerRecord.CreateContainerRecord(m_physicalParser.NextRecord()); m_physicalParser.CompressionAlgorithm = m_containerRecord.CompressionAlgorithm; m_physicalParser.CompressionStyle = m_containerRecord.CompressionStyle; } /// /// Opens the parser and parses the . /// /// The stream containing the PQDIF file data. /// True if the stream should be closed when the parser is closed; false otherwise. /// is null. /// is not both readable and seekable. /// An unsupported compression mode was defined in the PQDIF file. public void Open(Stream stream, bool leaveOpen = false) { m_physicalParser.Open(stream, leaveOpen); m_containerRecord = ContainerRecord.CreateContainerRecord(m_physicalParser.NextRecord()); m_physicalParser.CompressionAlgorithm = m_containerRecord.CompressionAlgorithm; m_physicalParser.CompressionStyle = m_containerRecord.CompressionStyle; } /// /// Determines whether there are any more /// s to be /// read from the PQDIF file. /// /// true if there is another observation record to be read from PQDIF file; false otherwise public bool HasNextObservationRecord() { Record physicalRecord; RecordType recordType; // Read records from the file until we encounter an observation record or end of file while ((object)m_nextObservationRecord == null && m_physicalParser.HasNextRecord()) { physicalRecord = m_physicalParser.NextRecord(); recordType = physicalRecord.Header.TypeOfRecord; switch (recordType) { case RecordType.DataSource: // Keep track of the latest data source record in order to associate it with observation records m_currentDataSourceRecord = DataSourceRecord.CreateDataSourceRecord(physicalRecord); m_allDataSourceRecords.Add(m_currentDataSourceRecord); break; case RecordType.MonitorSettings: // Keep track of the latest monitor settings record in order to associate it with observation records m_currentMonitorSettingsRecord = MonitorSettingsRecord.CreateMonitorSettingsRecord(physicalRecord); break; case RecordType.Observation: // Found an observation record! m_nextObservationRecord = ObservationRecord.CreateObservationRecord(physicalRecord, m_currentDataSourceRecord, m_currentMonitorSettingsRecord); break; case RecordType.Container: // The container record is parsed when the file is opened; it should never be encountered here throw new InvalidOperationException("Found more than one container record in PQDIF file."); default: // Ignore unrecognized record types as the rest of the file might be valid. //throw new ArgumentOutOfRangeException(string.Format("Unknown record type: {0}", physicalRecord.Header.RecordTypeTag)); break; } } return (object)m_nextObservationRecord != null; } /// /// Gets the next observation record from the PQDIF file. /// /// The next observation record. public ObservationRecord NextObservationRecord() { ObservationRecord nextObservationRecord; // Call this first to read ahead to the next // observation record if we haven't already HasNextObservationRecord(); // We need to set m_nextObservationRecord to null so that // subsequent calls to HasNextObservationRecord() will // continue to parse new records nextObservationRecord = m_nextObservationRecord; m_nextObservationRecord = null; return nextObservationRecord; } /// /// Resets the parser to the beginning of the PQDIF file. /// public void Reset() { m_currentDataSourceRecord = null; m_currentMonitorSettingsRecord = null; m_nextObservationRecord = null; m_allDataSourceRecords = new List(); m_physicalParser.Reset(); m_physicalParser.NextRecord(); // skip container record } /// /// Closes the PQDIF file. /// public void Close() { m_physicalParser.Close(); } /// /// Releases resources held by the parser. /// public void Dispose() { m_physicalParser.Dispose(); } #endregion } }