Exemplo n.º 1
0
        /// <summary>
        /// Gets all properties decorated with <see cref="RecordFieldAttribute"/> from the given type.
        /// </summary>
        /// <param name="recordType">The type to get the properties from.</param>
        /// <returns>An unordered set of properties.</returns>
        /// <exception cref="IncompatibleRecordArrayTypeException">
        /// Thrown if a property which does not support a <see cref="RecordFieldArrayAttribute"/> is decorated with one.
        /// </exception>
        /// <exception cref="InvalidFieldAttributeException">
        /// Thrown if a property is decorated with an invalid <see cref="RecordFieldAttribute"/>.
        /// </exception>
        public static IEnumerable <PropertyInfo> GetRecordProperties(Type recordType)
        {
            var recordProperties = recordType.GetProperties
                                   (
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.FlattenHierarchy
                                   )
                                   .Where(p => p.IsDefined(typeof(RecordFieldAttribute)))
                                   .ToList();

            // Do a bit of error checking
            foreach (var property in recordProperties)
            {
                if (property.GetCustomAttributes().Any(a => a is RecordFieldArrayAttribute))
                {
                    if (!DBCDeserializer.IsPropertyTypeCompatibleWithArrayAttribute(property.PropertyType))
                    {
                        throw new IncompatibleRecordArrayTypeException
                              (
                                  "Incompatible property definition decorated with RecordFieldArray. Use an array or something that implements IList<T>.", property.PropertyType
                              );
                    }
                }

                var versionAttribute = GetPropertyFieldAttribute(property);
                if ((versionAttribute.RemovedIn < versionAttribute.IntroducedIn) && versionAttribute.RemovedIn != WarcraftVersion.Unknown)
                {
                    throw new InvalidFieldAttributeException("The field was marked as having been removed before it was introduced.");
                }
            }

            return(recordProperties);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Gets the absolute size in bytes of the given record type.
        /// </summary>
        /// <param name="version">The version of the record.</param>
        /// <param name="recordType">The type to get the size of.</param>
        /// <returns>The absolute size in bytes of the record.</returns>
        public static int GetRecordSize(WarcraftVersion version, Type recordType)
        {
            var size = 0;

            foreach (var recordProperty in GetVersionRelevantProperties(version, recordType))
            {
                switch (recordProperty.PropertyType)
                {
                // Single-field types
                case Type foreignKeyType when foreignKeyType.IsGenericType && foreignKeyType.GetGenericTypeDefinition() == typeof(ForeignKey <>):
                case Type stringRefType when stringRefType == typeof(StringReference):
                case Type enumType when enumType.IsEnum:
                {
                    var underlyingType = DBCDeserializer.GetUnderlyingStoredPrimitiveType(recordProperty.PropertyType);

                    size += Marshal.SizeOf(underlyingType);
                    break;
                }

                // Multi-field types
                case Type genericListType when genericListType.IsGenericType && genericListType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList <>)):
                case Type arrayType when arrayType.IsArray:
                {
                    var elementSize        = Marshal.SizeOf(DBCDeserializer.GetUnderlyingStoredPrimitiveType(recordProperty.PropertyType));
                    var arrayInfoAttribute = GetVersionRelevantPropertyFieldArrayAttribute(version, recordProperty);

                    size += (int)(elementSize * arrayInfoAttribute.Count);

                    break;
                }

                // Special version-variant length handling
                case Type locStringRefType when locStringRefType == typeof(LocalizedStringReference):
                {
                    size += LocalizedStringReference.GetFieldCount(version) * sizeof(uint);
                    break;
                }

                case Type registeredType when CustomFieldTypeStorageSizes.ContainsKey(registeredType):
                {
                    size += CustomFieldTypeStorageSizes[registeredType];
                    break;
                }

                default:
                {
                    size += Marshal.SizeOf(recordProperty.PropertyType);
                    break;
                }
                }
            }

            return(size);
        }