crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianParserLib/ValueStores/ValueStore.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianParserLib/ValueStores/ValueStore.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,492 @@
+/*
+* 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.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.ComponentModel;
+using SymbianParserLib.Enums;
+using SymbianParserLib.BaseStructures;
+using SymbianParserLib.Elements;
+using SymbianParserLib.Elements.SubFields;
+
+namespace SymbianParserLib.ValueStores
+{
+    public class ValueStore
+    {
+        #region Enumerations
+        internal enum TValueStoreType
+        {
+            EValueStoreTypeProperty = 0,
+            EValueStoreTypeMethod,
+            EValueStoreTypeStoreInternally
+        }
+        #endregion
+
+        #region Constructors
+        public ValueStore()
+        {
+        }
+        #endregion
+
+        #region API
+        public void SetTargetProperty( object aPropertyObject, string aPropertyName )
+        {
+            iValueStore = aPropertyObject;
+            iValueStoreType = TValueStoreType.EValueStoreTypeProperty;
+            iValueStoreMemberName = aPropertyName;
+            //
+        }
+
+        public void SetTargetMethod( object aMethodObject, string aMethodName, params TValueStoreMethodArguments[] aArgs )
+        {
+            iValueStore = aMethodObject;
+            iValueStoreType = TValueStoreType.EValueStoreTypeMethod;
+            iValueStoreMemberName = aMethodName;
+            //
+            iMethodArgumentSpecifier = aArgs;
+        }
+        #endregion
+
+        #region Internal API
+        internal void SetValue( ParserFieldFormatSpecifier aFieldFormatSpecifier, ParserFieldFormatValue aFieldFormatValue )
+        {
+            CheckForValidValueStore();
+            //
+            if ( iValueStoreType == TValueStoreType.EValueStoreTypeProperty )
+            {
+                // Store value to user-supplied property within object
+                Binder binder = null;
+                Type typeInfo = iValueStore.GetType();
+                PropertyInfo propInfo = typeInfo.GetProperty( iValueStoreMemberName, PropertyBindingFlags );
+                if ( propInfo == null )
+                {
+                    throw new MissingMemberException( "A property called: \"" + iValueStoreMemberName + "\" was not found within object: " + iValueStore.ToString() );
+                }
+                //
+                Type propType = propInfo.PropertyType;
+                object[] args = PrepareMethodArgument( aFieldFormatValue.Value, propType );
+                typeInfo.InvokeMember( iValueStoreMemberName, PropertyBindingFlags, binder, iValueStore, args );
+            }
+            else if ( iValueStoreType == TValueStoreType.EValueStoreTypeMethod )
+            {
+                object[] args = null;
+                //
+                try
+                {
+                    // Store value to user-supplied method
+                    Binder binder = null;
+
+                    // Build arguments
+                    Type valueTypeInfo = aFieldFormatValue.Value.GetType();
+                    TValueStoreMethodArguments[] argumentSpecification = BuildMethodArgumentSpecification( valueTypeInfo, iValueStore, iValueStoreMemberName );
+                    args = BuildCustomFunctionArguments( argumentSpecification, aFieldFormatSpecifier, aFieldFormatValue );
+                    
+                    // Sanity check number of arguments for method implementation actually agrees with our run-time generated
+                    // object array of parameters.
+                    Type valueStoreTypeInfo = iValueStore.GetType();
+                    MethodInfo methodInfo = valueStoreTypeInfo.GetMethod( iValueStoreMemberName, MethodBindingFlags );
+                    ParameterInfo[] methodParams = methodInfo.GetParameters();
+                    if ( args.Length != methodParams.Length )
+                    {
+                        throw new MissingMethodException( "Argument specification doesn't align with method implementation" );
+                    }
+                    else
+                    {
+                        valueStoreTypeInfo.InvokeMember( iValueStoreMemberName, MethodBindingFlags, binder, iValueStore, args );
+                    }
+                }
+                catch ( Exception exception )
+                {
+                    if ( exception is TargetInvocationException || 
+                         exception is MissingMethodException || 
+                         exception is MissingMemberException || 
+                         exception is AmbiguousMatchException )
+                    {
+                        StringBuilder funcDetails = new StringBuilder();
+                        funcDetails.Append( iValueStoreMemberName + "( " );
+                        //
+                        int count = ( args != null ) ? args.Length : 0;
+                        for ( int i = 0; i < count; i++ )
+                        {
+                            object arg = args[ i ];
+                            string argTypeName = ( arg != null ) ? arg.GetType().ToString() : "null";
+                            funcDetails.Append( argTypeName );
+                            //
+                            if ( i < count - 1 )
+                            {
+                                funcDetails.Append( ", " );
+                            }
+                        }
+                        //
+                        funcDetails.Append( " )" );
+                        System.Diagnostics.Debug.WriteLine( "Failed to invoke method: " + funcDetails.ToString() );
+                    }
+                    else
+                    {
+                        throw exception;
+                    }
+                }
+            }
+            else if ( iValueStoreType == TValueStoreType.EValueStoreTypeStoreInternally )
+            {
+                // Store it in the value store and the client can extract it via the public properties...
+                iValueStore = aFieldFormatValue.Value;
+            }
+        }
+        #endregion
+
+        #region Properties
+        public bool IsInt
+        {
+            get
+            {
+                bool ret = IsDynamicAndOfType( typeof( int ) );
+                return ret;
+            }
+        }
+
+        public bool IsUint
+        {
+            get
+            {
+                bool ret = IsDynamicAndOfType( typeof( uint ) );
+                return ret;
+            }
+        }
+
+        public bool IsString
+        {
+            get
+            {
+                bool ret = IsDynamicAndOfType( typeof( string ) );
+                return ret;
+            }
+        }
+
+        public int AsInt
+        {
+            get
+            {
+                int ret = 0;
+                //
+                if ( IsInt )
+                {
+                    ret = (int) iValueStore;
+                }
+                //
+                return ret;
+            }
+        }
+
+        public uint AsUint
+        {
+            get
+            {
+                uint ret = 0;
+                //
+                if ( IsUint )
+                {
+                    ret = (uint) iValueStore;
+                }
+                //
+                return ret;
+            }
+        }
+
+        public string AsString
+        {
+            get
+            {
+                string ret = string.Empty;
+                //
+                if ( IsString )
+                {
+                    ret = (string) iValueStore;
+                }
+                //
+                return ret;
+            }
+        }
+
+        internal TValueStoreType ValueStoreType
+        {
+            get
+            {
+                return iValueStoreType;
+            }
+        }
+
+        internal BindingFlags MethodBindingFlags
+        {
+            get
+            {
+                BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod;
+                return bindingFlags;
+            }
+        }
+
+        internal BindingFlags PropertyBindingFlags
+        {
+            get
+            {
+                BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty;
+                return bindingFlags;
+            }
+        }
+        #endregion
+
+        #region Internal methods
+        private bool IsDynamicAndOfType( Type aExpectedType )
+        {
+            bool ret = false;
+            //
+            object vs = iValueStore;
+            TValueStoreType vsType = ValueStoreType;
+            if ( vs != null && vsType == TValueStoreType.EValueStoreTypeStoreInternally )
+            {
+                Type typeInfo = vs.GetType();
+                ret = ( typeInfo == aExpectedType );
+            }
+            //
+            return ret;
+        }
+
+        private void CheckForValidValueStore()
+        {
+            if ( iValueStoreType == TValueStoreType.EValueStoreTypeProperty ||
+                 iValueStoreType == TValueStoreType.EValueStoreTypeMethod )
+            {
+                if ( iValueStore == null )
+                {
+                    throw new Exception( "Missing value store" );
+                }
+            }
+        }
+
+        private object[] PrepareMethodArgument( object aValue, Type aExpectedPropertyType )
+        {
+            // If we're calling a property where the expected property type doesn't match the value
+            // we have been asked to use (for example, a property expects an enumerator, but we are given
+            // a uint or int) then we must convert from the value type to the expected property type.
+            object[] ret = { aValue };
+            Type valueType = aValue.GetType();
+            //
+            if ( aExpectedPropertyType != valueType )
+            {
+                // Get a type converter to perform the operation. Note that some of the built-in type
+                // converters are very "dumb" in that they only convert from strings to numbers (and vice
+                // versa). This doesn't help us when we need to convert from e.g. a uint to a long.
+                TypeConverter conv = TypeDescriptor.GetConverter( aExpectedPropertyType );
+                if ( conv == null )
+                {
+                    throw new NotSupportedException( "No type converter exists to convert between " + valueType.ToString() + " and " + aExpectedPropertyType.ToString() );
+                }
+                else if ( conv.CanConvertFrom( valueType ) )
+                {
+                    object converted = conv.ConvertFrom( aValue );
+                    ret = new object[] { converted };
+                }
+                else
+                {
+                    // Might be one of the built-in type converters that only works
+                    // with strings. Convert the value to a string and try once more
+                    string asString = aValue.ToString();
+                    try
+                    {
+                        object converted = conv.ConvertFrom( asString );
+                        ret = new object[] { converted };
+                    }
+                    catch ( NotSupportedException )
+                    {
+                        throw new NotSupportedException( "No type converter exists to convert between " + valueType.ToString() + " and " + aExpectedPropertyType.ToString() );
+                    }
+                }
+            }
+            //
+            return ret;
+        }
+
+        private TValueStoreMethodArguments[] BuildMethodArgumentSpecification( Type aValueTypeInfo, object aObject, string aMethodName )
+        {
+            List<TValueStoreMethodArguments> args = new List<TValueStoreMethodArguments>();
+            //
+            if ( iMethodArgumentSpecifier == null )
+            {
+                iMethodArgumentSpecifier = new TValueStoreMethodArguments[] { TValueStoreMethodArguments.EValueStoreMethodArgumentCalculateAtRuntime };
+            }
+            //
+            bool done = false;
+            int count = iMethodArgumentSpecifier.Length;
+            for( int i=0; i<count && !done; i++ )
+            {
+                TValueStoreMethodArguments argType = iMethodArgumentSpecifier[ i ];
+                switch ( argType )
+                {
+                default:
+                    args.Add( argType );
+                    break;
+                case TValueStoreMethodArguments.EValueStoreMethodArgumentCalculateAtRuntime:
+                    args.Clear();
+                    BuildRuntimeGeneratedArgumentList( aValueTypeInfo, aObject, aMethodName, ref args );
+                    done = true;
+                    break;
+                }
+            }
+            //
+            return args.ToArray();
+        }
+
+        private void BuildRuntimeGeneratedArgumentList( Type aValueTypeInfo, object aObject, string aMethodName, ref List<TValueStoreMethodArguments> aArgs )
+        {
+            Type typeInfo = aObject.GetType();
+            MethodInfo methodInfo = typeInfo.GetMethod( aMethodName, MethodBindingFlags );
+            if ( methodInfo == null )
+            {
+                throw new MissingMemberException( "Method: " + aMethodName + " was not found within object: " + aObject.ToString() );
+            }
+            ParameterInfo[] methodParams = methodInfo.GetParameters();
+
+            // Check if the parameters include an explicit request for a ParserFieldName object
+            // If so, we'll not send the "argument name as string" since the client has
+            // explicitly requested it as an object...
+            bool requestingArgNameAsObject = false;
+            foreach ( ParameterInfo info in methodParams )
+            {
+                if ( info.ParameterType == typeof( ParserFieldName ) )
+                {
+                    requestingArgNameAsObject = true;
+                    break;
+                }
+            }
+
+            // Second pass to build real list...
+            foreach ( ParameterInfo info in methodParams )
+            {
+                Type paramType = info.ParameterType;
+                //
+                if ( paramType == typeof( ParserFieldName ) )
+                {
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsObject );
+                }
+                else if ( paramType == typeof( ParserField ) )
+                {
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentField );
+                }
+                else if ( paramType == typeof( ParserLine ) )
+                {
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentLine );
+                }
+                else if ( paramType == typeof( ParserParagraph ) )
+                {
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentParagraph );
+                }
+                else if ( paramType == typeof( string ) && !requestingArgNameAsObject )
+                {
+                    // Best guess - if the first argument of the method is actually
+                    // a string-based "value" argument (rather than field name argument) then we'll
+                    // pass the parameter out of order - hence the "name as object" approach used
+                    // above, which let's us accurately infer type...
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsString );
+                }
+                else if ( paramType == aValueTypeInfo )
+                {
+                    aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentValue );
+                }
+            }
+        }
+
+        private object[] BuildCustomFunctionArguments( TValueStoreMethodArguments[] aArgumentSpecification, ParserFieldFormatSpecifier aFieldFormatSpecifier, ParserFieldFormatValue aFieldFormatValue )
+        {
+
+            List<object> args = new List<object>();
+            //
+            foreach ( TValueStoreMethodArguments argType in aArgumentSpecification )
+            {
+                if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsString )
+                {
+                    args.Add( aFieldFormatSpecifier.Name.ToString() );
+                }
+                else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsObject )
+                {
+                    args.Add( aFieldFormatSpecifier.Name );
+                }
+                else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentValue )
+                {
+                    args.Add( aFieldFormatValue.Value );
+                }
+                else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentParagraph )
+                {
+                    ParserParagraph para = null;
+                    //
+                    if ( aFieldFormatSpecifier.Field.Parent != null && aFieldFormatSpecifier.Field.Parent is ParserLine )
+                    {
+                        ParserLine line = (ParserLine) aFieldFormatSpecifier.Field.Parent;
+                        if ( line.Parent != null && line.Parent is ParserParagraph )
+                        {
+                            para = (ParserParagraph) line.Parent;
+                        }
+                    }
+                    //
+                    args.Add( para );
+                }
+                else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentLine )
+                {
+                    ParserLine line = null;
+                    //
+                    if ( aFieldFormatSpecifier.Field.Parent != null && aFieldFormatSpecifier.Field.Parent is ParserLine )
+                    {
+                        line = (ParserLine) aFieldFormatSpecifier.Field.Parent;
+                    }
+                    //
+                    args.Add( line );
+                }
+                else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentField )
+                {
+                    args.Add( aFieldFormatSpecifier.Field );
+                }
+                else
+                {
+                    System.Diagnostics.Debug.Assert( false, "Argument specification contains unresolved runtime reference" );
+                }
+            }
+            //
+            return args.ToArray();
+        }
+        #endregion
+
+        #region Internal constants
+        #endregion
+
+        #region From System.Object
+        public override string ToString()
+        {
+            return base.ToString();
+        }
+        #endregion
+
+        #region Data members
+        // Common members
+        private object iValueStore = null;
+        private string iValueStoreMemberName = string.Empty;
+        private TValueStoreType iValueStoreType = TValueStoreType.EValueStoreTypeStoreInternally;
+
+        // Method-specific members
+        private TValueStoreMethodArguments[] iMethodArgumentSpecifier = null;
+        #endregion
+    }
+}