Package gwlpr.protocol.serialization

Source Code of gwlpr.protocol.serialization.NettySerializationFilter$UShort

/**
* For copyright information see the LICENSE document.
*/

package gwlpr.protocol.serialization;

import gwlpr.protocol.util.IsArray;
import gwlpr.protocol.util.NestedMarker;
import gwlpr.protocol.util.Vector2;
import gwlpr.protocol.util.Vector3;
import gwlpr.protocol.util.Vector4;
import gwlpr.protocol.util.WorldPosition;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Defines the serialization methods. And standard classes.
*
* All standard classes must make sure that they keep the buffer's original
* state when they fail to deserialize something. When this happens, new
* incoming data must be attached to the buffer and its position must remain
* unchanged.
*
* CAUTION! THE METHODS NEED TO BE CAREFUL WITH SIGNING!
*
* @author _rusty
*/
public interface NettySerializationFilter
{
   
    static final Logger LOGGER = LoggerFactory.getLogger(NettySerializationFilter.class);
    static final Charset CHARSET_UTF16 = Charset.forName("utf-16le");
    static final Charset CHARSET_ASCII = Charset.forName("us-ascii");
   
   
    /**
     * Serializes a certain field of an object and puts the data
     * into the given buffer.
     * NO LENGTH CHECKS HERE! MAKE SURE THE BUFFER IS LONG ENOUGH!
     */
    void serialize(ByteBuf buf, Object object);
   
   
    /**
     * Deserializes a certain amount of bytes of the given buffer into
     * a certain field of the object.
     */
    boolean deserialize(ByteBuf buf, Object object);
   
   
    /**
     * Null-object.
     */
    public final static class Empty implements NettySerializationFilter
    {
       
        @Override
        public boolean deserialize(ByteBuf buf, Object object)
        {
            return true;
        }

       
        @Override
        public void serialize(ByteBuf buf, Object object)
        {
        }
    }
   
   
    /**
     * Chain of responsibility in a composite pattern.
     */
    public final static class Chain implements NettySerializationFilter
    {
       
        List<NettySerializationFilter> filters = new ArrayList<>();
       
       
        public void register(NettySerializationFilter filter)
        {
            filters.add(filter);
        }
       
       
        @Override
        public void serialize(ByteBuf buf, Object object)
        {
            for (NettySerializationFilter filter : filters)
            {
                filter.serialize(buf, object);
            }
        }
       
       
        @Override
        public boolean deserialize(ByteBuf buf, Object object)
        {
            for (NettySerializationFilter filter : filters)
            {
                if (!filter.deserialize(buf, object))
                {
                    return false;
                }
            }
           
            return true;
        }
    }
   
   
    /**
     * Superclass of all serialization filters
     */
    public abstract static class Generic implements NettySerializationFilter
    {
       
        protected final Field field;
       
       
        public Generic(Field field)
        {
            field.setAccessible(true);
            this.field = field;
        }
       
       
        @Override
        public void serialize(ByteBuf buf, Object object)
        {
            try
            {
                put(buf, object);
            }
            catch (Exception ex)
            {
                LOGGER.error("Could not serialize.", ex);
            }
        }
       
        protected abstract void put(ByteBuf buf, Object object)
                throws Exception;
       
       
        @Override
        public boolean deserialize(ByteBuf buf, Object object)
        {
            try
            {
                Object value = get(buf);
               
                if (value == null)
                {
                    return false;
                }
               
                field.set(object, value);
            }
            catch (Exception ex)
            {
                LOGGER.error("Could not deserialize.", ex); return false;
            }
           
            return true;
        }
       
        protected abstract Object get(ByteBuf buf)
                throws Exception;
    }
   
   
    /**
     * Arrays can use this class to automatically and safely
     * (no buffer changes when data not available) parse their length.
     */
    public static abstract class Array extends Generic
    {
        private final boolean constant;
        private final int arraySize;
        private final int prefixSize;
       
        public Array(Field field)
        {
            super(field);
           
            IsArray packetArray = field.getAnnotation(IsArray.class);
            constant = packetArray.constant();
            arraySize = packetArray.size();
            prefixSize = packetArray.prefixLength();
        }
       
       
        protected void setLength(ByteBuf buf, int length)
        {
            if (constant) { return; }
           
            if (prefixSize == 1)
            {
                buf.writeByte(length);
            }
            if (prefixSize == 2)
            {
                buf.writeShort(length);
            }
        }
       
       
        protected int getLength(ByteBuf buf)
        {
            if (constant) { return arraySize; }
           
            if (prefixSize == 1)
            {
                return buf.readableBytes() >= 1 ? buf.readUnsignedByte() : -1;
            }
            if (prefixSize == 2)
            {
                return buf.readableBytes() >= 2 ? buf.readUnsignedShort() : -1;
            }
           
            // unknown prefix length
            return -1;
        }
    }
   
   
    public final static class UByte extends Generic
    {
        public UByte(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            buf.writeByte(field.getShort(object));
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 1 ? buf.readUnsignedByte() : null;
        }
    }
   
   
    public final static class UShort extends Generic
    {
        public UShort(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            buf.writeShort(field.getInt(object));
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 2 ? buf.readUnsignedShort() : null;
        }
    }
   
   
    public final static class UInt extends Generic
    {
        public UInt(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            buf.writeInt((int)field.getLong(object));
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 4 ? buf.readUnsignedInt() : null;
        }
    }
   
   
    public final static class Long extends Generic
    {
        public Long(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            buf.writeLong(field.getLong(object));
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 8 ? buf.readLong() : null;
        }
    }
   
   
    public final static class Float extends Generic
    {
        public Float(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            buf.writeFloat(field.getFloat(object));
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 4 ? buf.readFloat() : null;
        }
    }
   
   
    public final static class Vec2 extends Generic
    {
        public Vec2(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            Vector2 vec = (Vector2)field.get(object);
            buf.writeFloat(vec.getX());
            buf.writeFloat(vec.getY());
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 8 ? new Vector2(buf.readFloat(), buf.readFloat()) : null;
        }
    }
   
   
    public final static class Vec3 extends Generic
    {
        public Vec3(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            Vector3 vec = (Vector3)field.get(object);
            buf.writeFloat(vec.getX());
            buf.writeFloat(vec.getY());
            buf.writeFloat(vec.getZ());
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 12 ? new Vector3(buf.readFloat(), buf.readFloat(), buf.readFloat()) : null;
        }
    }
   
   
    public final static class Vec4 extends Generic
    {
        public Vec4(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            Vector4 vec = (Vector4)field.get(object);
            buf.writeFloat(vec.getX());
            buf.writeFloat(vec.getY());
            buf.writeFloat(vec.getZ());
            buf.writeFloat(vec.getA());
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 16 ? new Vector4(buf.readFloat(), buf.readFloat(), buf.readFloat(), buf.readFloat()) : null;
        }
    }
   
   
    public final static class DW3 extends Generic
    {
        public DW3(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            WorldPosition wp = (WorldPosition)field.get(object);
            buf.writeFloat(wp.getX());
            buf.writeFloat(wp.getY());
            buf.writeFloat(wp.getZ());
            buf.writeInt((int)wp.getW());
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            return buf.readableBytes() >= 16 ? new WorldPosition(buf.readFloat(), buf.readFloat(), buf.readFloat(), buf.readUnsignedInt()) : null;
        }
    }
   
   
    public final static class VInt extends Generic
    {
        public VInt(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            int value = field.getInt(object);
           
            // Taken from GW2Emu.
            boolean first = true;

            while (first || value > 0)
            {
                first = false;
                byte lower7bits = (byte)(value & 0x7f);
                value >>= 7;

                if (value > 0)
                {
                    lower7bits |= 128;
                }

                buf.writeByte(lower7bits);
            }
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            // Taken from GW2Emu.
            boolean more = true;
            int result = 0;
            int shift = 0;

            while (more)
            {
                // failcheck
                if (buf.readableBytes() < 1) { return null; }
               
                byte lower7bits = buf.readByte();
                more = (lower7bits & 128) != 0;
                result |= (lower7bits & 0x7f) << shift;
                shift += 7;
            }

            return result;
        }
    }
   
   
    public final static class ASCII extends Generic
    {
        public ASCII(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            String txt = (String)field.get(object);
            byte[] txtBytes = txt.getBytes(CHARSET_ASCII);
           
            // put the size of the string (UTF16 char count)
            buf.writeShort(txt.length());
           
            // then put the string itself
            buf.writeBytes(txtBytes);
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            // do we have a string length indicator?
            if (buf.readableBytes() < 2) { return null; }
           
            int length = buf.readUnsignedShort();
           
            // do we have the trailing data? (length)
            if (buf.readableBytes() < length) { return null; }
           
            byte[] result = new byte[length];
            buf.readBytes(result);

            return new String(result, CHARSET_ASCII);
        }
    }

   
    public final static class UTF16 extends Generic
    {
        public UTF16(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            String txt = (String)field.get(object);
            byte[] txtBytes = txt.getBytes(CHARSET_UTF16);
           
            // put the size of the string (UTF16 char count)
            buf.writeShort(txt.length());
           
            // then put the string itself
            buf.writeBytes(txtBytes);
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            // do we have a string length indicator?
            if (buf.readableBytes() < 2) { return null; }
           
            int length = buf.readUnsignedShort();
           
            // do we have the trailing data? (length * byte-per-char)
            if (buf.readableBytes() < length * 2) { return null; }
           
            byte[] result = new byte[length * 2];
            buf.readBytes(result);

            return new String(result, CHARSET_UTF16);
        }
    }
   
   
    public final static class ByteArray extends Array
    {
        public ByteArray(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            byte[] sa = (byte[])field.get(object);
           
            // put the byte-count
            setLength(buf, sa.length);
          
            // then put the array itself
            buf.writeBytes(sa);
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            int length = getLength(buf);
           
            // failcheck (length could not be determined)
            if (length == -1) { return null; }
           
            // do we have the trailing data?
            if (buf.readableBytes() < length) { return null; }
           
            byte[] result = new byte[length];
            buf.readBytes(result);
           
            return result;
        }
    }
   
   
    public final static class UID16 extends Generic
    {
        public UID16(Field field) { super(field); }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            UUID uid = (UUID) field.get(object);
           
            buf.writeLong(uid.getMostSignificantBits());
            buf.writeLong(uid.getLeastSignificantBits());
        }
       
        @Override
        protected Object get(ByteBuf buf)
        {
            if (buf.readableBytes() < 16) { return null; }
           
            return new UUID(buf.readLong(), buf.readLong());
        }
    }
   
   
    public final static class Nested implements NettySerializationFilter
    {
        private final Field field;
        private final Class<?> nestedClass;
        private final NettySerializationFilter innerFilter;
       
       
        public Nested(Field field, Class<?> nestedClass, NettySerializationFilter innerFilter)
        {
            field.setAccessible(true);
            this.field = field;
            this.nestedClass = nestedClass;
            this.innerFilter = innerFilter;
        }
       
       
        @Override
        public void serialize(ByteBuf buf, Object object)
        {
            try
            {
                Object nested = field.get(object);
           
                // put the byte indicating whether this is null or not
                buf.writeBoolean(nested != null);

                if (nested != null)
                {
                    innerFilter.serialize(buf, field.get(object));
                }
            }
            catch (Exception ex)
            {
                LOGGER.error("Could not serialize.", ex);
            }
        }
       
       
        @Override
        public boolean deserialize(ByteBuf buf, Object object)
        {
            try
            {
                Object value = nestedClass.newInstance();
           
                if (buf.readableBytes() < 1) { return false; }

                // read the byte indicating whether this is null or not
                boolean isPresent = buf.readByte() == 1;
               
                // failcheck
                if (!isPresent)
                {
                    field.set(object, null);
                    return true;
                }

                if (!innerFilter.deserialize(buf, value))
                {
                    return false;
                }
               
                field.set(object, value);
            }
            catch (Exception ex)
            {
                LOGGER.error("Could not deserialize.", ex); return false;
            }
           
            return true;
        }      
    }
   
   
    public final static class NestedArray<T extends NestedMarker> extends Array
    {
        private final Class<T> nestedClass;
        private final NettySerializationFilter innerFilter;
       
        public NestedArray(Field field, Class<T> nestedClass, NettySerializationFilter innerFilter)
        {
            super(field);
            this.nestedClass = nestedClass;
            this.innerFilter = innerFilter;
        }
       
        @Override
        protected void put(ByteBuf buf, Object object)
                throws Exception
        {
            Object[] oa = (Object[])field.get(object);
           
            // put the byte-count
            setLength(buf, oa.length);
          
            // then put the array itself
            for (Object o : oa)
            {
                innerFilter.serialize(buf, o);
            }            
        }
       
        @Override
        protected Object get(ByteBuf buf)
                throws Exception
        {
            int length = getLength(buf);
           
            // failcheck (length could not be determined)
            if (length == -1) { return null; }
           
            // TODO can this be avoided?
            T[] result = (T[]) java.lang.reflect.Array.newInstance(nestedClass, length);
           
            for (int i = 0; i < length; i++)
            {
                T nested = nestedClass.newInstance();
               
                if (!innerFilter.deserialize(buf, nested))
                {
                    return null;
                }
               
                result[i] = nested;
            }
           
            return result;
        }
    }
}
TOP

Related Classes of gwlpr.protocol.serialization.NettySerializationFilter$UShort

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.