diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianParserLib/ValueStores/ValueStore.cs --- /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 args = new List(); + // + if ( iMethodArgumentSpecifier == null ) + { + iMethodArgumentSpecifier = new TValueStoreMethodArguments[] { TValueStoreMethodArguments.EValueStoreMethodArgumentCalculateAtRuntime }; + } + // + bool done = false; + int count = iMethodArgumentSpecifier.Length; + for( int i=0; i 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 args = new List(); + // + 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 + } +}