示例#1
0
            public override bool SupportsSourceMapping(ASSourceMappingDescriptor descriptor)
            {
                ASTypeKind sourceKind = descriptor.SourceKind;

                return(descriptor.TargetNativeType.IsEnum &&
                       (sourceKind == ASTypeKind.Int29 || sourceKind == ASTypeKind.Number || sourceKind == ASTypeKind.String));
            }
示例#2
0
        private object InternalToNative(IASValue asValue, Type nativeType)
        {
            if (asValue == null)
            {
                // Note: We cannot just map all null values to null references here
                //       because doing so would prevent mappers from expressing different
                //       preferences for null object mappings.  For example, consider the
                //       case of DBNull which is a reference-type for which all null
                //       values need to be mapped to the special DBNull.Value singleton.
                //       (Admittedly this is a somewhat contrived example since it's unlikely
                //       someone would ever declare a field of type DBNull.)
                //       Moreover, returning a null reference won't work for value types
                //       so at the least we must handle those by going through the mappers.
                //       So while we could perhaps apply a dubious optimization just for reference
                //       types here, we do not!
                return(UncachedToNative(ASNull.Value, nativeType));
            }

            // Look in the reference cache.
            ASTypeKind kind      = asValue.Kind;
            bool       cacheable = IsEligibleForASReferenceCache(kind);

            if (cacheable)
            {
                ASReferenceCacheKey key = new ASReferenceCacheKey(asValue, nativeType);
                object nativeValue;
                if (asReferenceCache.TryGetValue(key, out nativeValue))
                {
                    if (nativeValue == null)
                    {
                        throw new ActionScriptException("FIXME: A circular reference was encountered that could not be resolved by the current implementation.");
                    }
                    return(nativeValue);
                }

                asReferenceCache.Add(key, null); // add a sentinel to detect the cycle

                try
                {
                    nativeValue = UncachedToNative(asValue, nativeType);
                }
                catch (Exception)
                {
                    asReferenceCache.Remove(key);
                    throw;
                }

                asReferenceCache[key] = nativeValue;
                return(nativeValue);
            }
            else
            {
                return(UncachedToNative(asValue, nativeType));
            }
        }
示例#3
0
        /// <summary>
        /// Determines if ActionScript values of the specified type should be cached to
        /// preserve referential identity.
        /// </summary>
        /// <param name="kind"></param>
        /// <returns></returns>
        private static bool IsEligibleForASReferenceCache(ASTypeKind kind)
        {
            switch (kind)
            {
            case ASTypeKind.String:
            case ASTypeKind.Object:
            case ASTypeKind.Array:
            case ASTypeKind.Xml:
            case ASTypeKind.ByteArray:
                return(true);

            default:
                return(false);
            }
        }
示例#4
0
        /// <summary>
        /// Initializes an ActionScript source mapping descriptor.
        /// </summary>
        /// <param name="sourceKind">The source value kind</param>
        /// <param name="sourceClassAlias">The source class alias, may be empty but never null</param>
        /// <param name="targetNativeType">The type of native objects to which values are mapped, never null</param>
        /// <param name="sourceContentFlags">Flags that describe abstract properties of the contents of the source value</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="targetNativeType"/> or
        /// <see cref="sourceClassAlias" /> is null</exception>
        public ASSourceMappingDescriptor(ASTypeKind sourceKind, string sourceClassAlias, ASValueContentFlags sourceContentFlags,
                                         Type targetNativeType)
        {
            if (targetNativeType == null)
            {
                throw new ArgumentNullException("sourceNativeType");
            }
            if (sourceClassAlias == null)
            {
                throw new ArgumentNullException("sourceClassAlias");
            }

            this.sourceKind         = sourceKind;
            this.sourceClassAlias   = sourceClassAlias;
            this.sourceContentFlags = sourceContentFlags;
            this.targetNativeType   = targetNativeType;
        }
示例#5
0
 /// <summary>
 /// Creates an exception to indicate that the specified mapping to a native value is not supported.
 /// </summary>
 /// <param name="kind">The kind of ActionScript value to be mapped</param>
 /// <param name="nativeType">The native type</param>
 /// <returns>A suitable exception</returns>
 protected static ActionScriptException ToNativeNotSupported(ASTypeKind kind, Type nativeType)
 {
     return(new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                    "This mapper does not support mapping from an ActionScript '{0}' to an instance of '{1}'.", kind, nativeType.FullName)));
 }
        /// <summary>
        /// Gets the default native type to use for mapping ActionScript values with certain properties.
        /// </summary>
        /// <remarks>
        /// The default native type can be used when insufficient type information is available to
        /// perform a mapping unambiguously.
        /// </remarks>
        /// <param name="kind">The value's kind</param>
        /// <param name="classAlias">The value's class alias or an empty string if none</param>
        /// <param name="contentFlags">The value's content flags</param>
        /// <returns>The default native type</returns>
        public Type GetDefaultNativeType(ASTypeKind kind, string classAlias, ASValueContentFlags contentFlags)
        {
            switch (kind)
            {
                case ASTypeKind.Array:
                    if ((contentFlags & ASValueContentFlags.HasDynamicProperties) == 0)
                        return typeof(object[]);
                    if ((contentFlags & ASValueContentFlags.HasIndexedValues) == 0)
                        return typeof(Dictionary<string, object>);
                    return typeof(MixedArray<object>);

                case ASTypeKind.Boolean:
                    return typeof(bool);

                case ASTypeKind.ByteArray:
                    return typeof(byte[]);

                case ASTypeKind.Date:
                    return typeof(DateTime);

                case ASTypeKind.Int29:
                    return typeof(int);

                case ASTypeKind.Null:
                    return typeof(object);

                case ASTypeKind.Number:
                    return typeof(double);

                case ASTypeKind.Object:
                    if (classAlias.Length != 0)
                    {
                        ActionScriptClassMapping classMapping = GetClassMappingByAlias(classAlias);
                        if (classMapping != null)
                            return classMapping.NativeType;
                    }

                    // Map untyped and unknown objects to dictionaries.
                    return typeof(Dictionary<string, object>);

                case ASTypeKind.String:
                    return typeof(string);

                case ASTypeKind.Undefined:
                    return typeof(ASUndefined);

                case ASTypeKind.Unsupported:
                    return typeof(ASUnsupported);

                case ASTypeKind.Xml:
                    return typeof(XmlDocument);

                default:
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                        "Unsupported type kind '{0}'.", kind));
            }
        }
示例#7
0
        private object UncachedToNative(IASValue asValue, Type nativeType)
        {
            ASTypeKind          kind         = asValue.Kind;
            ASClass             asClass      = asValue.Class;
            string              classAlias   = asClass != null ? asClass.ClassAlias : "";
            ASValueContentFlags contentFlags = asValue.ContentFlags;

            Type defaultNativeType = mappingTable.GetDefaultNativeType(kind, classAlias, contentFlags);

            // If the requested native type is not as precise as the default native type,
            // then use the default native type instead.  This rule is intended to avoid
            // the ambiguities that occur if we try to map to type "object" or some other
            // type that is too general.
            if (nativeType == null || nativeType.IsAssignableFrom(defaultNativeType))
            {
                nativeType = defaultNativeType;
            }

            // Quick short circuit if the desired type is a subtype of IASValue so mapping won't help.
            if (!typeof(IASValue).IsAssignableFrom(nativeType))
            {
                // Note: This will handle uninitialized values by returning null if no trivial
                //       conversion is possible without complete initialization.
                object value = asValue.GetNativeValue(nativeType);
                if (value != null)
                {
                    return(value);
                }

                // If the value isn't initialized then give up because we might have to do mapping.
                if (!asValue.IsInitialized)
                {
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                                  "The ActionScript value cannot be mapped to type '{0}' because it is not completely initialized.",
                                                                  nativeType != null ? nativeType.FullName : "<default>"));
                }

                // Use mappers.
                // FIXME: This won't work if mapping ends up being recursive!
                ASSourceMappingDescriptor descriptor = new ASSourceMappingDescriptor(kind, classAlias, contentFlags, nativeType);
                IASSourceMapper           mapper     = mappingTable.GetASSourceMapper(descriptor);
                if (mapper != null)
                {
                    return(mapper.ToNative(this, asValue, nativeType));
                }
            }

            // Apply default handling for null references.
            if (asValue == ASNull.Value && !nativeType.IsValueType)
            {
                return(null);
            }

            // As a last resort, if we can assign the AS value to the original type requested then
            // do so.  We generally prefer mappings over returning IASValue instances, but if there
            // is no other choice...
            if (nativeType.IsInstanceOfType(asValue))
            {
                return(asValue);
            }

            // Give up!
            throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                          "Cannot find a suitable mapper for mapping an ActionScript value of kind '{0}' with class alias '{1}' to an instance of type '{2}'.",
                                                          asValue.Kind, classAlias, nativeType != null ? nativeType.FullName : "<default>"));
        }
示例#8
0
        /// <summary>
        /// Gets the default native type to use for mapping ActionScript values with certain properties.
        /// </summary>
        /// <remarks>
        /// The default native type can be used when insufficient type information is available to
        /// perform a mapping unambiguously.
        /// </remarks>
        /// <param name="kind">The value's kind</param>
        /// <param name="classAlias">The value's class alias or an empty string if none</param>
        /// <param name="contentFlags">The value's content flags</param>
        /// <returns>The default native type</returns>
        public Type GetDefaultNativeType(ASTypeKind kind, string classAlias, ASValueContentFlags contentFlags)
        {
            switch (kind)
            {
            case ASTypeKind.Array:
                if ((contentFlags & ASValueContentFlags.HasDynamicProperties) == 0)
                {
                    return(typeof(object[]));
                }
                if ((contentFlags & ASValueContentFlags.HasIndexedValues) == 0)
                {
                    return(typeof(Dictionary <string, object>));
                }
                return(typeof(MixedArray <object>));

            case ASTypeKind.Boolean:
                return(typeof(bool));

            case ASTypeKind.ByteArray:
                return(typeof(byte[]));

            case ASTypeKind.Date:
                return(typeof(DateTime));

            case ASTypeKind.Int29:
                return(typeof(int));

            case ASTypeKind.Null:
                return(typeof(object));

            case ASTypeKind.Number:
                return(typeof(double));

            case ASTypeKind.Object:
                if (classAlias.Length != 0)
                {
                    ActionScriptClassMapping classMapping = GetClassMappingByAlias(classAlias);
                    if (classMapping != null)
                    {
                        return(classMapping.NativeType);
                    }
                }

                // Map untyped and unknown objects to dictionaries.
                return(typeof(Dictionary <string, object>));

            case ASTypeKind.String:
                return(typeof(string));

            case ASTypeKind.Undefined:
                return(typeof(ASUndefined));

            case ASTypeKind.Unsupported:
                return(typeof(ASUnsupported));

            case ASTypeKind.Xml:
                return(typeof(XmlDocument));

            default:
                throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                              "Unsupported type kind '{0}'.", kind));
            }
        }
示例#9
0
 /// <summary>
 /// Creates an exception to indicate that the specified mapping to a native value is not supported.
 /// </summary>
 /// <param name="kind">The kind of ActionScript value to be mapped</param>
 /// <param name="nativeType">The native type</param>
 /// <returns>A suitable exception</returns>
 protected static ActionScriptException ToNativeNotSupported(ASTypeKind kind, Type nativeType)
 {
     return new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
         "This mapper does not support mapping from an ActionScript '{0}' to an instance of '{1}'.", kind, nativeType.FullName));
 }