/// <inheritdoc />
        protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context)
        {
            if (!context.HasContextualKey())
            {
                throw new InvalidOperationException($"No contextual key was built for Type: {context.TargetType} in {GetType().FullName}");
            }

            if (!CanHandle(context))
            {
                throw new InvalidOperationException($"Cannot create serializer for Type: {context.TargetType} and Context: {context?.BuiltContextKey?.ToString()}");
            }

            //The only type of context available to decorate primitive types with
            //is ReverseData for now
            ITypeSerializerStrategy <TType> serializer = null;

            if (serializerProviderService.HasSerializerFor <TType>())
            {
                serializer = serializerProviderService.Get <TType>();
            }

            if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.Reverse))
            {
                serializer = new EndianReverseDecorator <TType>(serializer);
            }

            return(serializer);
        }
Ejemplo n.º 2
0
 private void RegisterNewSerializerStrategy(ISerializableTypeContext context, ITypeSerializerStrategy strategy)
 {
     if (strategy.ContextRequirement == SerializationContextRequirement.Contextless)
     {
         StrategyRegistry.RegisterType(context.TargetType, strategy);
     }
     else
     {
         //TODO: Clean this up
         if (context.HasContextualKey())
         {
             //Register the serializer with the context key that was built into the serialization context.
             StrategyRegistry.RegisterType(context.BuiltContextKey.Value.ContextFlags, context.BuiltContextKey.Value.ContextSpecificKey, context.TargetType, strategy);
         }
         else
         {
             throw new InvalidOperationException($"Serializer was created but Type: {context.TargetType} came with no contextual key in the end for a contextful serialization context.");
         }
     }
 }
        //TODO: Refactor
        /// <inheritdoc />
        protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (typeof(TType) != typeof(string))
            {
                throw new InvalidOperationException($"{nameof(StringSerializerDecoratorHandler)} cannot handle creation of serializer decorators involves {typeof(string).FullName}.");
            }

            if (!context.HasContextualKey())
            {
                throw new ArgumentException($"Provided context {nameof(context)} did not contain a valid {nameof(context.BuiltContextKey)}.");
            }

            if (context.ContextRequirement == SerializationContextRequirement.Contextless)
            {
                return((ITypeSerializerStrategy <TType>)serializerProviderService.Get <string>());               //The caller should know what he's doing.
            }
            //TODO: Throw on invalid metadata combinations
            ITypeSerializerStrategy <string> serializer = null;
            Encoding encoding = Encoding.ASCII;

            if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.Encoding))
            {
                if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.ASCII))
                {
                    encoding   = Encoding.ASCII;
                    serializer = new StringSerializerStrategy(Encoding.ASCII, SerializationContextRequirement.RequiresContext);
                }
                else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF16))
                {
                    encoding   = Encoding.Unicode;
                    serializer = new StringSerializerStrategy(Encoding.Unicode, SerializationContextRequirement.RequiresContext);
                }
                else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF32))
                {
                    encoding   = Encoding.UTF32;
                    serializer = new StringSerializerStrategy(Encoding.UTF32, SerializationContextRequirement.RequiresContext);
                }
                else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF8))
                {
                    encoding   = Encoding.UTF8;
                    serializer = new StringSerializerStrategy(Encoding.UTF8, SerializationContextRequirement.RequiresContext);
                }
                else
                {
                    throw new InvalidOperationException($"String had encoding flags but no specified encoding.");
                }
            }
            else
            {
                //If we have a context, but don't have an encoding context, then we should grab the default that uses ASCII
                serializer = serializerProviderService.Get <string>();
            }


            bool shouldTerminate = !context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.DontTerminate);

            //If we shouldn't null terminate or if we're using a fixed/known size (meaning we never want to append a null terminator past the size)
            if (!shouldTerminate || context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize))
            {
                serializer = new DontTerminateStringSerializerDecorator(serializer, encoding);
            }

            //It is possible that the WoW protocol expects a fixed-size string that both client and server know the length of
            //This can be seen in the first packet Auth_Challenge: uint8   gamename[4];
            //It can be seen that this field is a fixed length string (byte array)
            if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize))
            {
                //read the key. It will have the size
                int size = context.BuiltContextKey.Value.ContextSpecificKey.Key;

                serializer = new SizeStringSerializerDecorator(new FixedSizeStringSizeStrategy(context.BuiltContextKey.Value.ContextSpecificKey.Key), serializer, encoding);
            }
            //It is also possible that the WoW protocol expects a length prefixed string
            else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.SendSize))
            {
                byte addedSize = (byte)(context.BuiltContextKey.Value.ContextSpecificKey.Key >> 4);
                //This is an odd choice but if they mark it with conflicting metdata maybe we should throw?
                switch ((SendSizeAttribute.SizeType)(context.BuiltContextKey.Value.ContextSpecificKey.Key & 0b0000_0000_0000_1111))
                {