All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.yezhihao.protostar.schema.StringSchema Maven / Gradle / Ivy

package io.github.yezhihao.protostar.schema;

import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.field.BasicField;
import io.github.yezhihao.protostar.field.LengthUnitField;
import io.github.yezhihao.protostar.util.CharsBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.util.internal.StringUtil;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class StringSchema {

    public static final Schema HEX = new HEX(-1);
    public static final Schema BCD = new BCD(-1);
    public static final Schema GBK = new STR(Charset.forName("GBK"), -1);
    public static final Schema UTF8 = new STR(StandardCharsets.UTF_8, -1);
    public static final Schema ASCII = new STR(StandardCharsets.US_ASCII, -1);

    public static BasicField getInstance(String charset, int length, int lengthUnit) {
        final String cs = charset.toUpperCase();
        BasicField schema;
        if ("BCD".equals(cs))
            schema = new BCD(length);
        else if ("HEX".equals(cs))
            schema = new HEX(length);
        else
            schema = new STR(Charset.forName(charset), length);

        if (lengthUnit > 0)
            schema = new LengthUnitField(schema, lengthUnit);

        return schema;
    }

    public static class STR extends BasicField {
        private static final ByteBuffer EMPTY = ByteBuffer.allocate(0);
        private final Charset charset;
        private final int length;
        private final boolean fixed;

        private STR(Charset charset, int length) {
            this.charset = charset;
            this.length = length;
            this.fixed = length > -1;
        }

        @Override
        public String readFrom(ByteBuf input) {
            int len = input.readableBytes();

            if (fixed && len > length)
                len = length;

            byte[] bytes = new byte[len];
            input.readBytes(bytes);

            int st = 0;
            while ((st < len) && (bytes[st] == 0))
                st++;
            while ((st < len) && (bytes[len - 1] == 0))
                len--;
            return new String(bytes, st, len - st, charset);
        }

        @Override
        public void writeTo(ByteBuf output, String value) {
            if (fixed) {
                ByteBuffer buffer;
                if (value == null) buffer = EMPTY;
                else buffer = charset.encode(value);

                int srcPos = length - buffer.limit();

                if (srcPos > 0) {
                    output.writeBytes(buffer);
                    output.writeBytes(new byte[srcPos]);
                } else if (srcPos < 0) {
                    buffer.position(-srcPos);
                    output.writeBytes(buffer);
                } else {
                    output.writeBytes(buffer);
                }
            } else {
                if (value != null)
                    output.writeBytes(charset.encode(value));
            }
        }
    }

    public static class HEX extends BasicField {
        protected final int length;
        protected final int charSize;
        protected final boolean fixed;

        public HEX(int length) {
            this.length = length;
            this.charSize = length << 1;
            this.fixed = length > -1;
        }

        @Override
        public String readFrom(ByteBuf input) {
            return readCharsBuilder(input).toString();
        }

        protected CharsBuilder readCharsBuilder(ByteBuf input) {
            int len = fixed ? length : input.readableBytes();
            byte[] bytes = new byte[len];
            input.readBytes(bytes);

            CharsBuilder cb = new CharsBuilder(charSize);
            StringUtil.toHexStringPadded(cb, bytes);
            return cb;
        }

        @Override
        public void writeTo(ByteBuf output, String value) {
            if (value == null) {
                if (fixed) output.writeBytes(new byte[length]);
                return;
            }

            int charSize = this.charSize;
            int strLength = value.length();

            if (!fixed) charSize = strLength + (strLength & 1);

            char[] chars = new char[charSize];
            int i = charSize - strLength;
            if (i >= 0) {
                value.getChars(0, charSize - i, chars, i);
                while (i > 0)
                    chars[--i] = '0';
            } else {
                value.getChars(-i, charSize - i, chars, 0);
            }
            byte[] src = StringUtil.decodeHexDump(new CharsBuilder(chars));
            output.writeBytes(src);
        }
    }

    public static class BCD extends HEX {
        public BCD(int length) {
            super(length);
        }

        @Override
        public String readFrom(ByteBuf input) {
            return readCharsBuilder(input).leftStrip('0');
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy