/// <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); }
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)) {