crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianParserLib/ValueStores/ValueStore.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 * 
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 using System;
       
    18 using System.Collections.Generic;
       
    19 using System.Text;
       
    20 using System.Reflection;
       
    21 using System.ComponentModel;
       
    22 using SymbianParserLib.Enums;
       
    23 using SymbianParserLib.BaseStructures;
       
    24 using SymbianParserLib.Elements;
       
    25 using SymbianParserLib.Elements.SubFields;
       
    26 
       
    27 namespace SymbianParserLib.ValueStores
       
    28 {
       
    29     public class ValueStore
       
    30     {
       
    31         #region Enumerations
       
    32         internal enum TValueStoreType
       
    33         {
       
    34             EValueStoreTypeProperty = 0,
       
    35             EValueStoreTypeMethod,
       
    36             EValueStoreTypeStoreInternally
       
    37         }
       
    38         #endregion
       
    39 
       
    40         #region Constructors
       
    41         public ValueStore()
       
    42         {
       
    43         }
       
    44         #endregion
       
    45 
       
    46         #region API
       
    47         public void SetTargetProperty( object aPropertyObject, string aPropertyName )
       
    48         {
       
    49             iValueStore = aPropertyObject;
       
    50             iValueStoreType = TValueStoreType.EValueStoreTypeProperty;
       
    51             iValueStoreMemberName = aPropertyName;
       
    52             //
       
    53         }
       
    54 
       
    55         public void SetTargetMethod( object aMethodObject, string aMethodName, params TValueStoreMethodArguments[] aArgs )
       
    56         {
       
    57             iValueStore = aMethodObject;
       
    58             iValueStoreType = TValueStoreType.EValueStoreTypeMethod;
       
    59             iValueStoreMemberName = aMethodName;
       
    60             //
       
    61             iMethodArgumentSpecifier = aArgs;
       
    62         }
       
    63         #endregion
       
    64 
       
    65         #region Internal API
       
    66         internal void SetValue( ParserFieldFormatSpecifier aFieldFormatSpecifier, ParserFieldFormatValue aFieldFormatValue )
       
    67         {
       
    68             CheckForValidValueStore();
       
    69             //
       
    70             if ( iValueStoreType == TValueStoreType.EValueStoreTypeProperty )
       
    71             {
       
    72                 // Store value to user-supplied property within object
       
    73                 Binder binder = null;
       
    74                 Type typeInfo = iValueStore.GetType();
       
    75                 PropertyInfo propInfo = typeInfo.GetProperty( iValueStoreMemberName, PropertyBindingFlags );
       
    76                 if ( propInfo == null )
       
    77                 {
       
    78                     throw new MissingMemberException( "A property called: \"" + iValueStoreMemberName + "\" was not found within object: " + iValueStore.ToString() );
       
    79                 }
       
    80                 //
       
    81                 Type propType = propInfo.PropertyType;
       
    82                 object[] args = PrepareMethodArgument( aFieldFormatValue.Value, propType );
       
    83                 typeInfo.InvokeMember( iValueStoreMemberName, PropertyBindingFlags, binder, iValueStore, args );
       
    84             }
       
    85             else if ( iValueStoreType == TValueStoreType.EValueStoreTypeMethod )
       
    86             {
       
    87                 object[] args = null;
       
    88                 //
       
    89                 try
       
    90                 {
       
    91                     // Store value to user-supplied method
       
    92                     Binder binder = null;
       
    93 
       
    94                     // Build arguments
       
    95                     Type valueTypeInfo = aFieldFormatValue.Value.GetType();
       
    96                     TValueStoreMethodArguments[] argumentSpecification = BuildMethodArgumentSpecification( valueTypeInfo, iValueStore, iValueStoreMemberName );
       
    97                     args = BuildCustomFunctionArguments( argumentSpecification, aFieldFormatSpecifier, aFieldFormatValue );
       
    98                     
       
    99                     // Sanity check number of arguments for method implementation actually agrees with our run-time generated
       
   100                     // object array of parameters.
       
   101                     Type valueStoreTypeInfo = iValueStore.GetType();
       
   102                     MethodInfo methodInfo = valueStoreTypeInfo.GetMethod( iValueStoreMemberName, MethodBindingFlags );
       
   103                     ParameterInfo[] methodParams = methodInfo.GetParameters();
       
   104                     if ( args.Length != methodParams.Length )
       
   105                     {
       
   106                         throw new MissingMethodException( "Argument specification doesn't align with method implementation" );
       
   107                     }
       
   108                     else
       
   109                     {
       
   110                         valueStoreTypeInfo.InvokeMember( iValueStoreMemberName, MethodBindingFlags, binder, iValueStore, args );
       
   111                     }
       
   112                 }
       
   113                 catch ( Exception exception )
       
   114                 {
       
   115                     if ( exception is TargetInvocationException || 
       
   116                          exception is MissingMethodException || 
       
   117                          exception is MissingMemberException || 
       
   118                          exception is AmbiguousMatchException )
       
   119                     {
       
   120                         StringBuilder funcDetails = new StringBuilder();
       
   121                         funcDetails.Append( iValueStoreMemberName + "( " );
       
   122                         //
       
   123                         int count = ( args != null ) ? args.Length : 0;
       
   124                         for ( int i = 0; i < count; i++ )
       
   125                         {
       
   126                             object arg = args[ i ];
       
   127                             string argTypeName = ( arg != null ) ? arg.GetType().ToString() : "null";
       
   128                             funcDetails.Append( argTypeName );
       
   129                             //
       
   130                             if ( i < count - 1 )
       
   131                             {
       
   132                                 funcDetails.Append( ", " );
       
   133                             }
       
   134                         }
       
   135                         //
       
   136                         funcDetails.Append( " )" );
       
   137                         System.Diagnostics.Debug.WriteLine( "Failed to invoke method: " + funcDetails.ToString() );
       
   138                     }
       
   139                     else
       
   140                     {
       
   141                         throw exception;
       
   142                     }
       
   143                 }
       
   144             }
       
   145             else if ( iValueStoreType == TValueStoreType.EValueStoreTypeStoreInternally )
       
   146             {
       
   147                 // Store it in the value store and the client can extract it via the public properties...
       
   148                 iValueStore = aFieldFormatValue.Value;
       
   149             }
       
   150         }
       
   151         #endregion
       
   152 
       
   153         #region Properties
       
   154         public bool IsInt
       
   155         {
       
   156             get
       
   157             {
       
   158                 bool ret = IsDynamicAndOfType( typeof( int ) );
       
   159                 return ret;
       
   160             }
       
   161         }
       
   162 
       
   163         public bool IsUint
       
   164         {
       
   165             get
       
   166             {
       
   167                 bool ret = IsDynamicAndOfType( typeof( uint ) );
       
   168                 return ret;
       
   169             }
       
   170         }
       
   171 
       
   172         public bool IsString
       
   173         {
       
   174             get
       
   175             {
       
   176                 bool ret = IsDynamicAndOfType( typeof( string ) );
       
   177                 return ret;
       
   178             }
       
   179         }
       
   180 
       
   181         public int AsInt
       
   182         {
       
   183             get
       
   184             {
       
   185                 int ret = 0;
       
   186                 //
       
   187                 if ( IsInt )
       
   188                 {
       
   189                     ret = (int) iValueStore;
       
   190                 }
       
   191                 //
       
   192                 return ret;
       
   193             }
       
   194         }
       
   195 
       
   196         public uint AsUint
       
   197         {
       
   198             get
       
   199             {
       
   200                 uint ret = 0;
       
   201                 //
       
   202                 if ( IsUint )
       
   203                 {
       
   204                     ret = (uint) iValueStore;
       
   205                 }
       
   206                 //
       
   207                 return ret;
       
   208             }
       
   209         }
       
   210 
       
   211         public string AsString
       
   212         {
       
   213             get
       
   214             {
       
   215                 string ret = string.Empty;
       
   216                 //
       
   217                 if ( IsString )
       
   218                 {
       
   219                     ret = (string) iValueStore;
       
   220                 }
       
   221                 //
       
   222                 return ret;
       
   223             }
       
   224         }
       
   225 
       
   226         internal TValueStoreType ValueStoreType
       
   227         {
       
   228             get
       
   229             {
       
   230                 return iValueStoreType;
       
   231             }
       
   232         }
       
   233 
       
   234         internal BindingFlags MethodBindingFlags
       
   235         {
       
   236             get
       
   237             {
       
   238                 BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod;
       
   239                 return bindingFlags;
       
   240             }
       
   241         }
       
   242 
       
   243         internal BindingFlags PropertyBindingFlags
       
   244         {
       
   245             get
       
   246             {
       
   247                 BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty;
       
   248                 return bindingFlags;
       
   249             }
       
   250         }
       
   251         #endregion
       
   252 
       
   253         #region Internal methods
       
   254         private bool IsDynamicAndOfType( Type aExpectedType )
       
   255         {
       
   256             bool ret = false;
       
   257             //
       
   258             object vs = iValueStore;
       
   259             TValueStoreType vsType = ValueStoreType;
       
   260             if ( vs != null && vsType == TValueStoreType.EValueStoreTypeStoreInternally )
       
   261             {
       
   262                 Type typeInfo = vs.GetType();
       
   263                 ret = ( typeInfo == aExpectedType );
       
   264             }
       
   265             //
       
   266             return ret;
       
   267         }
       
   268 
       
   269         private void CheckForValidValueStore()
       
   270         {
       
   271             if ( iValueStoreType == TValueStoreType.EValueStoreTypeProperty ||
       
   272                  iValueStoreType == TValueStoreType.EValueStoreTypeMethod )
       
   273             {
       
   274                 if ( iValueStore == null )
       
   275                 {
       
   276                     throw new Exception( "Missing value store" );
       
   277                 }
       
   278             }
       
   279         }
       
   280 
       
   281         private object[] PrepareMethodArgument( object aValue, Type aExpectedPropertyType )
       
   282         {
       
   283             // If we're calling a property where the expected property type doesn't match the value
       
   284             // we have been asked to use (for example, a property expects an enumerator, but we are given
       
   285             // a uint or int) then we must convert from the value type to the expected property type.
       
   286             object[] ret = { aValue };
       
   287             Type valueType = aValue.GetType();
       
   288             //
       
   289             if ( aExpectedPropertyType != valueType )
       
   290             {
       
   291                 // Get a type converter to perform the operation. Note that some of the built-in type
       
   292                 // converters are very "dumb" in that they only convert from strings to numbers (and vice
       
   293                 // versa). This doesn't help us when we need to convert from e.g. a uint to a long.
       
   294                 TypeConverter conv = TypeDescriptor.GetConverter( aExpectedPropertyType );
       
   295                 if ( conv == null )
       
   296                 {
       
   297                     throw new NotSupportedException( "No type converter exists to convert between " + valueType.ToString() + " and " + aExpectedPropertyType.ToString() );
       
   298                 }
       
   299                 else if ( conv.CanConvertFrom( valueType ) )
       
   300                 {
       
   301                     object converted = conv.ConvertFrom( aValue );
       
   302                     ret = new object[] { converted };
       
   303                 }
       
   304                 else
       
   305                 {
       
   306                     // Might be one of the built-in type converters that only works
       
   307                     // with strings. Convert the value to a string and try once more
       
   308                     string asString = aValue.ToString();
       
   309                     try
       
   310                     {
       
   311                         object converted = conv.ConvertFrom( asString );
       
   312                         ret = new object[] { converted };
       
   313                     }
       
   314                     catch ( NotSupportedException )
       
   315                     {
       
   316                         throw new NotSupportedException( "No type converter exists to convert between " + valueType.ToString() + " and " + aExpectedPropertyType.ToString() );
       
   317                     }
       
   318                 }
       
   319             }
       
   320             //
       
   321             return ret;
       
   322         }
       
   323 
       
   324         private TValueStoreMethodArguments[] BuildMethodArgumentSpecification( Type aValueTypeInfo, object aObject, string aMethodName )
       
   325         {
       
   326             List<TValueStoreMethodArguments> args = new List<TValueStoreMethodArguments>();
       
   327             //
       
   328             if ( iMethodArgumentSpecifier == null )
       
   329             {
       
   330                 iMethodArgumentSpecifier = new TValueStoreMethodArguments[] { TValueStoreMethodArguments.EValueStoreMethodArgumentCalculateAtRuntime };
       
   331             }
       
   332             //
       
   333             bool done = false;
       
   334             int count = iMethodArgumentSpecifier.Length;
       
   335             for( int i=0; i<count && !done; i++ )
       
   336             {
       
   337                 TValueStoreMethodArguments argType = iMethodArgumentSpecifier[ i ];
       
   338                 switch ( argType )
       
   339                 {
       
   340                 default:
       
   341                     args.Add( argType );
       
   342                     break;
       
   343                 case TValueStoreMethodArguments.EValueStoreMethodArgumentCalculateAtRuntime:
       
   344                     args.Clear();
       
   345                     BuildRuntimeGeneratedArgumentList( aValueTypeInfo, aObject, aMethodName, ref args );
       
   346                     done = true;
       
   347                     break;
       
   348                 }
       
   349             }
       
   350             //
       
   351             return args.ToArray();
       
   352         }
       
   353 
       
   354         private void BuildRuntimeGeneratedArgumentList( Type aValueTypeInfo, object aObject, string aMethodName, ref List<TValueStoreMethodArguments> aArgs )
       
   355         {
       
   356             Type typeInfo = aObject.GetType();
       
   357             MethodInfo methodInfo = typeInfo.GetMethod( aMethodName, MethodBindingFlags );
       
   358             if ( methodInfo == null )
       
   359             {
       
   360                 throw new MissingMemberException( "Method: " + aMethodName + " was not found within object: " + aObject.ToString() );
       
   361             }
       
   362             ParameterInfo[] methodParams = methodInfo.GetParameters();
       
   363 
       
   364             // Check if the parameters include an explicit request for a ParserFieldName object
       
   365             // If so, we'll not send the "argument name as string" since the client has
       
   366             // explicitly requested it as an object...
       
   367             bool requestingArgNameAsObject = false;
       
   368             foreach ( ParameterInfo info in methodParams )
       
   369             {
       
   370                 if ( info.ParameterType == typeof( ParserFieldName ) )
       
   371                 {
       
   372                     requestingArgNameAsObject = true;
       
   373                     break;
       
   374                 }
       
   375             }
       
   376 
       
   377             // Second pass to build real list...
       
   378             foreach ( ParameterInfo info in methodParams )
       
   379             {
       
   380                 Type paramType = info.ParameterType;
       
   381                 //
       
   382                 if ( paramType == typeof( ParserFieldName ) )
       
   383                 {
       
   384                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsObject );
       
   385                 }
       
   386                 else if ( paramType == typeof( ParserField ) )
       
   387                 {
       
   388                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentField );
       
   389                 }
       
   390                 else if ( paramType == typeof( ParserLine ) )
       
   391                 {
       
   392                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentLine );
       
   393                 }
       
   394                 else if ( paramType == typeof( ParserParagraph ) )
       
   395                 {
       
   396                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentParagraph );
       
   397                 }
       
   398                 else if ( paramType == typeof( string ) && !requestingArgNameAsObject )
       
   399                 {
       
   400                     // Best guess - if the first argument of the method is actually
       
   401                     // a string-based "value" argument (rather than field name argument) then we'll
       
   402                     // pass the parameter out of order - hence the "name as object" approach used
       
   403                     // above, which let's us accurately infer type...
       
   404                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsString );
       
   405                 }
       
   406                 else if ( paramType == aValueTypeInfo )
       
   407                 {
       
   408                     aArgs.Add( TValueStoreMethodArguments.EValueStoreMethodArgumentValue );
       
   409                 }
       
   410             }
       
   411         }
       
   412 
       
   413         private object[] BuildCustomFunctionArguments( TValueStoreMethodArguments[] aArgumentSpecification, ParserFieldFormatSpecifier aFieldFormatSpecifier, ParserFieldFormatValue aFieldFormatValue )
       
   414         {
       
   415 
       
   416             List<object> args = new List<object>();
       
   417             //
       
   418             foreach ( TValueStoreMethodArguments argType in aArgumentSpecification )
       
   419             {
       
   420                 if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsString )
       
   421                 {
       
   422                     args.Add( aFieldFormatSpecifier.Name.ToString() );
       
   423                 }
       
   424                 else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentNameAsObject )
       
   425                 {
       
   426                     args.Add( aFieldFormatSpecifier.Name );
       
   427                 }
       
   428                 else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentValue )
       
   429                 {
       
   430                     args.Add( aFieldFormatValue.Value );
       
   431                 }
       
   432                 else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentParagraph )
       
   433                 {
       
   434                     ParserParagraph para = null;
       
   435                     //
       
   436                     if ( aFieldFormatSpecifier.Field.Parent != null && aFieldFormatSpecifier.Field.Parent is ParserLine )
       
   437                     {
       
   438                         ParserLine line = (ParserLine) aFieldFormatSpecifier.Field.Parent;
       
   439                         if ( line.Parent != null && line.Parent is ParserParagraph )
       
   440                         {
       
   441                             para = (ParserParagraph) line.Parent;
       
   442                         }
       
   443                     }
       
   444                     //
       
   445                     args.Add( para );
       
   446                 }
       
   447                 else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentLine )
       
   448                 {
       
   449                     ParserLine line = null;
       
   450                     //
       
   451                     if ( aFieldFormatSpecifier.Field.Parent != null && aFieldFormatSpecifier.Field.Parent is ParserLine )
       
   452                     {
       
   453                         line = (ParserLine) aFieldFormatSpecifier.Field.Parent;
       
   454                     }
       
   455                     //
       
   456                     args.Add( line );
       
   457                 }
       
   458                 else if ( argType == TValueStoreMethodArguments.EValueStoreMethodArgumentField )
       
   459                 {
       
   460                     args.Add( aFieldFormatSpecifier.Field );
       
   461                 }
       
   462                 else
       
   463                 {
       
   464                     System.Diagnostics.Debug.Assert( false, "Argument specification contains unresolved runtime reference" );
       
   465                 }
       
   466             }
       
   467             //
       
   468             return args.ToArray();
       
   469         }
       
   470         #endregion
       
   471 
       
   472         #region Internal constants
       
   473         #endregion
       
   474 
       
   475         #region From System.Object
       
   476         public override string ToString()
       
   477         {
       
   478             return base.ToString();
       
   479         }
       
   480         #endregion
       
   481 
       
   482         #region Data members
       
   483         // Common members
       
   484         private object iValueStore = null;
       
   485         private string iValueStoreMemberName = string.Empty;
       
   486         private TValueStoreType iValueStoreType = TValueStoreType.EValueStoreTypeStoreInternally;
       
   487 
       
   488         // Method-specific members
       
   489         private TValueStoreMethodArguments[] iMethodArgumentSpecifier = null;
       
   490         #endregion
       
   491     }
       
   492 }