crashanalysercmd/Libraries/File Formats/Plugins/DExcPlugin/Extractor/DExcExtractor.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/Libraries/File Formats/Plugins/DExcPlugin/Extractor/DExcExtractor.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,286 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+* 
+* Description:
+*
+*/
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Collections.Generic;
+using SymbianUtils.Range;
+using EM=DExcPlugin.ExpressionManager.DExcExpressionManager;
+
+namespace DExcPlugin.Extractor
+{
+	internal class DExcExtractor
+	{
+        #region Events
+        public enum TEvent
+        {
+            EEventExtractedAllData
+        }
+
+        public delegate void EventHandler( TEvent aEvent, DExcExtractor aExtractor );
+        public event EventHandler StateChanged;
+        #endregion
+
+        #region Constructors
+        public DExcExtractor()
+		{
+            Init();
+        }
+		#endregion
+
+		#region API
+        public void Init()
+        {
+            iState = TState.EStateIdle;
+            iData = new DExcExtractedData();
+            iLists = new Dictionary<TState, DExcExtractorList>();
+            iCurrentLineNumber = 0;
+		    
+            // Null (really just exists to catch a state transition)
+            // =======================================================
+            CreateList( TState.EStateIdle, DExcExtractorListType.EListNull ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) );
+		    
+            // Header
+            // =======================================================
+            CreateList( TState.EStateHeader, DExcExtractorListType.EListHeader ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.ThreadName, TState.EStateThreadInfo ) );
+
+            // Thread info
+            // ===========
+            DExcExtractorListThreadInfo listThreadInfo = new DExcExtractorListThreadInfo( TState.EStateThreadInfo, DExcExtractorListType.EListThread );
+            PrepareList( listThreadInfo, EM.ThreadName, EM.ThreadId, EM.ThreadStackRange, EM.ThreadPanicDetails );
+            listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersExceptionStart, TState.EStateRegisterInfoException ) );
+            listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) );
+
+            // Registers (exception)
+            // =====================
+            DExcExtractorList listRegisterInfoException = CreateList( TState.EStateRegisterInfoException, DExcExtractorListType.EListRegistersException,
+                                                                        EM.RegistersExceptionSet1,
+                                                                        EM.RegistersExceptionSet2 );
+            listRegisterInfoException.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) );
+
+            // Registers (user)
+            // ================
+            DExcExtractorList listRegisterInfoUser = CreateList( TState.EStateRegisterInfoUser, DExcExtractorListType.EListRegistersUser,
+                                                                   EM.RegistersUserCPSR,
+                                                                   EM.RegistersUserSet );
+
+            // Since code segs are optional, we want to record that we at least saw the header text (which is mandatory). This
+            // tracking allows us to validate that we have received/observed data for all states.
+            listRegisterInfoUser.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.CodeSegmentsStart, TState.EStateCodeSegments ) );
+
+            // Code segments
+            // =============
+            DExcExtractorList listCodeSegments = CreateList( TState.EStateCodeSegments, DExcExtractorListType.EListCodeSegments, EM.CodeSegmentsEntry );
+
+            // We need to transition state to "stack data", but we must be sure not to throw away the state line we just encountered.
+            listCodeSegments.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.StackDataEntry, TState.EStateStackData ) );
+
+            // Stack data
+            // ==========
+            DExcExtractorListStackData listStackData = new DExcExtractorListStackData( TState.EStateStackData, DExcExtractorListType.EListStackData );
+            PrepareList( listStackData, EM.StackDataEntry );
+            listStackData.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) );
+
+            // We want to observe the stack data as it arrives so that we can identify when all stack data has been supplied.
+            listStackData.StackChanged += new DExcExtractorListStackData.StackDataChangeHandler( StackDataChanged );
+        }
+
+        public void Init( string aStackFileName )
+        {
+            Init();
+            //
+            DExcExtractorListStackData stackData = (DExcExtractorListStackData) iLists[ TState.EStateStackData ];
+            stackData.Prime( aStackFileName );
+        }
+
+        public bool Offer( string aLine, long aLineNumber )
+		{
+            bool consumed = false;
+
+            // Cache line number - we use this to update the data starting position
+            // when the state is changed.
+            iCurrentLineNumber = aLineNumber;
+
+            // Get list for current state
+            DExcExtractorList list = CurrentList;
+            if ( list != null )
+            {
+                consumed = list.Offer( aLine, aLineNumber, this );
+            }
+
+            return consumed;
+		}
+
+        public void Finialize()
+		{
+			// If we were parsing code segs but we didn't get any stack
+			// data then we must ensure we still notify when we've reached
+			// the end of the code seg data (or else no crash item will be
+			// created).
+            switch ( State )
+            {
+            case TState.EStateIdle:
+                // Already finished or not started
+                return;
+            default:
+                break;
+            }
+
+            // Did we create entries in all non-idle lists?
+            bool haveEntriesForAllLists = ListsAreValid;
+            if ( haveEntriesForAllLists )
+            {
+                NotifyEvent( TEvent.EEventExtractedAllData );
+                State = TState.EStateIdle;
+            }
+		}
+		#endregion
+
+        #region Properties
+        public TState State
+		{
+            get { return iState; }
+            set
+            {
+                if ( value != iState )
+                {
+                    TState oldState = value;
+                    iState = value;
+                    //
+                    if ( oldState == TState.EStateIdle )
+                    {
+                        // Was idle, now not - set starting line number
+                        iData.LineNumber = iCurrentLineNumber;
+                    }
+                    else if ( iState == TState.EStateIdle )
+                    {
+                        Init();
+                    }
+                }
+            }
+		}
+
+        public DExcExtractedData CurrentData
+        {
+            get { return iData; }
+        }
+
+        public DExcExtractorList CurrentList
+        {
+            get
+            {
+                DExcExtractorList ret = null;
+                //
+                if ( iLists.ContainsKey( State ) )
+                {
+                    ret = iLists[ State ];
+                }
+                //
+                return ret;
+            }
+        }
+		#endregion
+
+        #region Event handlers
+        private void StackDataChanged( DExcExtractorListStackData aSelf )
+        {
+            DExcExtractorListThreadInfo threadInfo = (DExcExtractorListThreadInfo) iLists[ TState.EStateThreadInfo ];
+            AddressRange range = threadInfo.StackRange;
+            if ( range.IsValid )
+            {
+                uint lastAddress = aSelf.StackData.Last.Address;
+                if ( lastAddress == range.Max - 1 )
+                {
+                    NotifyEvent( TEvent.EEventExtractedAllData );
+                    State = TState.EStateIdle;
+                }
+            }
+        }
+        #endregion
+        
+        #region Internal enumerations
+        internal enum TState
+        {
+            EStateIdle = 0,
+            EStateHeader,
+            EStateThreadInfo,
+            EStateRegisterInfoException,
+            EStateRegisterInfoUser,
+            EStateCodeSegments,
+            EStateStackData,
+        }
+        #endregion
+
+        #region Internal methods
+        private void NotifyEvent( TEvent aEvent )
+        {
+            if ( StateChanged != null )
+            {
+                StateChanged( aEvent, this );
+            }
+        }
+
+        private void PrepareList( DExcExtractorList aList, params Regex[] aExpressions )
+        {
+            foreach ( Regex exp in aExpressions )
+            {
+                DExcExtractorEntry entry = DExcExtractorEntry.NewMatchAndSave( exp );
+                aList.AddExpression( entry );
+            }
+            //
+            iLists.Add( aList.State, aList );
+            iData.Add( aList );
+        }
+
+        private DExcExtractorList CreateList( TState aAssociatedState, DExcExtractorListType aType, params Regex[] aExpressions )
+        {
+            DExcExtractorList ret = new DExcExtractorList( aAssociatedState, aType );
+            PrepareList( ret, aExpressions );
+            return ret;
+        }
+
+        private bool ListsAreValid
+        {
+            get
+            {
+                int countThreadInfo = iLists[ TState.EStateThreadInfo ].Count;
+                int countRegUser = iLists[ TState.EStateRegisterInfoUser ].Count;
+                int countCodeSegs = iLists[ TState.EStateCodeSegments ].Count;
+                int countStackData = ((DExcExtractorListStackData) iLists[ TState.EStateStackData ]).StackData.Count;
+                //
+                bool valid = ( countThreadInfo >= 3 ) && ( countRegUser > 0 ) && ( countCodeSegs > 0 ) && ( countStackData > 0 );
+                return valid;
+            }
+        }
+        #endregion
+
+        #region From System.Object
+        public override string ToString()
+        {
+            string ret = iData.ToString();
+            return ret;
+        }
+        #endregion
+
+        #region Data members
+        private TState iState;
+        private long iCurrentLineNumber = 0;
+        private DExcExtractedData iData = new DExcExtractedData();
+        private Dictionary<TState, DExcExtractorList> iLists = new Dictionary<TState, DExcExtractorList>();
+		#endregion
+	}
+}