diff --git a/pom.xml b/pom.xml index 6b386bb..364a4fb 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ io.netty netty-buffer - 4.1.65.Final + 4.1.66.Final provided diff --git a/src/main/java/io/github/yezhihao/protostar/DataType.java b/src/main/java/io/github/yezhihao/protostar/DataType.java index 98a1b33..124230b 100644 --- a/src/main/java/io/github/yezhihao/protostar/DataType.java +++ b/src/main/java/io/github/yezhihao/protostar/DataType.java @@ -19,6 +19,8 @@ public enum DataType { BYTES(-1), /** BCD8421码 */ BCD8421(-1), + /** 十六进制字符串 */ + HEX(-1), /** 字符串 */ STRING(-1), /** 对象 */ diff --git a/src/main/java/io/github/yezhihao/protostar/DefaultLoadStrategy.java b/src/main/java/io/github/yezhihao/protostar/DefaultLoadStrategy.java index ece7b6e..ef90f5c 100644 --- a/src/main/java/io/github/yezhihao/protostar/DefaultLoadStrategy.java +++ b/src/main/java/io/github/yezhihao/protostar/DefaultLoadStrategy.java @@ -14,7 +14,7 @@ import java.util.Map; */ public class DefaultLoadStrategy extends LoadStrategy { - private Map>> typeClassMapping = new HashMap(140); + private Map>> typeClassMapping = new HashMap(256); public DefaultLoadStrategy() { } diff --git a/src/main/java/io/github/yezhihao/protostar/FieldFactory.java b/src/main/java/io/github/yezhihao/protostar/FieldFactory.java index 63d34f9..794a0e8 100644 --- a/src/main/java/io/github/yezhihao/protostar/FieldFactory.java +++ b/src/main/java/io/github/yezhihao/protostar/FieldFactory.java @@ -52,6 +52,9 @@ public abstract class FieldFactory { else fieldSchema = ArraySchema.ByteArraySchema.INSTANCE; break; + case HEX: + fieldSchema = StringSchema.HEX.INSTANCE; + break; case STRING: fieldSchema = StringSchema.Chars.getInstance(field.pad(), field.charset()); break; diff --git a/src/main/java/io/github/yezhihao/protostar/Schema.java b/src/main/java/io/github/yezhihao/protostar/Schema.java index b2b3c98..8bbe21a 100644 --- a/src/main/java/io/github/yezhihao/protostar/Schema.java +++ b/src/main/java/io/github/yezhihao/protostar/Schema.java @@ -1,8 +1,6 @@ package io.github.yezhihao.protostar; import io.netty.buffer.ByteBuf; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * 消息结构 @@ -11,8 +9,6 @@ import org.slf4j.LoggerFactory; */ public interface Schema { - Logger log = LoggerFactory.getLogger(Schema.class.getSimpleName()); - T readFrom(ByteBuf input); void writeTo(ByteBuf output, T message); diff --git a/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java index f86971f..01478e8 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java @@ -1,15 +1,20 @@ package io.github.yezhihao.protostar.schema; import io.github.yezhihao.protostar.Schema; -import io.github.yezhihao.protostar.util.Bcd; import io.github.yezhihao.protostar.util.Cache; +import io.github.yezhihao.protostar.util.CharsBuilder; import io.netty.buffer.ByteBuf; +import io.netty.util.internal.StringUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.Arrays; public class StringSchema { + private static final Logger log = LoggerFactory.getLogger(StringSchema.class.getSimpleName()); + public static class Chars implements Schema { private static final Cache cache = new Cache<>(); @@ -65,7 +70,7 @@ public class StringSchema { output.writeBytes(bytes); } else if (srcPos < 0) { output.writeBytes(bytes, -srcPos, length); - log.error("字符长度超出限制: 长度[{}],数据长度[{}],{}", length, bytes.length, value); + log.info("字符长度超出限制: 长度[{}],数据长度[{}],{}", length, bytes.length, value); } else { output.writeBytes(bytes); } @@ -75,7 +80,6 @@ public class StringSchema { } } - public static class BCD implements Schema { public static final Schema INSTANCE = new BCD(); @@ -91,12 +95,10 @@ public class StringSchema { public String readFrom(ByteBuf input, int length) { byte[] bytes = new byte[length]; input.readBytes(bytes); - char[] chars = Bcd.toChars(bytes); - int i = Bcd.indexOf(chars, '0'); - if (i == 0) - return new String(chars); - return new String(chars, i, chars.length - i); + CharsBuilder cb = new CharsBuilder(length << 1); + StringUtil.toHexStringPadded(cb, bytes); + return cb.leftStrip('0'); } @Override @@ -115,9 +117,53 @@ public class StringSchema { chars[--i] = '0'; } else { value.getChars(-i, charLength - i, chars, 0); - log.warn("字符长度超出限制: 长度[{}],[{}]", charLength, value); + log.info("字符长度超出限制: 长度[{}],[{}]", charLength, value); } - byte[] src = Bcd.from(chars); + byte[] src = StringUtil.decodeHexDump(new CharsBuilder(chars)); + output.writeBytes(src); + } + } + + public static class HEX implements Schema { + public static final Schema INSTANCE = new HEX(); + + private HEX() { + } + + @Override + public String readFrom(ByteBuf input) { + return readFrom(input, input.readableBytes()); + } + + @Override + public String readFrom(ByteBuf input, int length) { + byte[] bytes = new byte[length]; + input.readBytes(bytes); + + CharsBuilder cb = new CharsBuilder(length << 1); + StringUtil.toHexStringPadded(cb, bytes); + return cb.toString(); + } + + @Override + public void writeTo(ByteBuf output, String value) { + writeTo(output, value.length() >> 1, value); + } + + @Override + public void writeTo(ByteBuf output, int length, String value) { + int charLength = length << 1; + char[] chars = new char[charLength]; + int i = charLength - value.length(); + if (i >= 0) { + value.getChars(0, charLength - i, chars, i); + while (i > 0) + chars[--i] = '0'; + } else { + value.getChars(-i, charLength - i, chars, 0); + log.info("字符长度超出限制: 长度[{}],[{}]", charLength, value); + } + byte[] src = StringUtil.decodeHexDump(new CharsBuilder(chars)); output.writeBytes(src); } } diff --git a/src/main/java/io/github/yezhihao/protostar/util/Bcd.java b/src/main/java/io/github/yezhihao/protostar/util/Bcd.java index 01ba79d..04435da 100644 --- a/src/main/java/io/github/yezhihao/protostar/util/Bcd.java +++ b/src/main/java/io/github/yezhihao/protostar/util/Bcd.java @@ -17,35 +17,6 @@ public class Bcd { public static final int YEAR_RANGE = YEAR - 30; public static final int HUNDRED_YEAR = YEAR_RANGE / 100 * 100; - /** BCD转String */ - public static String toString(byte[] bcd) { - return new String(toChars(bcd)); - } - - /** BCD转char[] */ - public static char[] toChars(byte[] bcd) { - char[] chars = new char[bcd.length * 2]; - for (int i = 0, j = 0; i < bcd.length; i++) { - chars[j++] = (char) (48 + (bcd[i] >> 4 & 0xf)); - chars[j++] = (char) (48 + (bcd[i] & 0xf)); - } - return chars; - } - - /** String转BCD */ - public static byte[] from(String str) { - return from(str.toCharArray()); - } - - /** char[]转BCD */ - public static byte[] from(char[] chars) { - byte[] bcd = new byte[chars.length / 2]; - for (int i = 0, j = 0; i < bcd.length; i++) { - bcd[i] = (byte) ((chars[j++] - 48 << 4) | ((chars[j++] - 48 & 0xf))); - } - return bcd; - } - /** 时间转BCD (yyMMddHHmmss) */ public static byte[] from(LocalDateTime dateTime) { byte[] bcd = new byte[6]; @@ -113,10 +84,4 @@ public class Bcd { public static int num(byte bcd) { return (bcd >> 4 & 0xf) * 10 + (bcd & 0xf); } - - public static int indexOf(char[] chars, char pad) { - int i = 0, len = chars.length; - while (i < len && chars[i] == pad) i++; - return i; - } } \ No newline at end of file diff --git a/src/main/java/io/github/yezhihao/protostar/util/CharsBuilder.java b/src/main/java/io/github/yezhihao/protostar/util/CharsBuilder.java new file mode 100644 index 0000000..e278b79 --- /dev/null +++ b/src/main/java/io/github/yezhihao/protostar/util/CharsBuilder.java @@ -0,0 +1,82 @@ +package io.github.yezhihao.protostar.util; + +import java.util.Arrays; + +public class CharsBuilder implements CharSequence, Appendable { + + private char[] value; + private int pos; + + public CharsBuilder(int length) { + this.value = new char[length]; + } + + public CharsBuilder(char[] chars) { + this.value = chars; + } + + @Override + public Appendable append(CharSequence s) { + return append(s, 0, s.length()); + } + + @Override + public Appendable append(CharSequence s, int start, int end) { + int len = end - start; + for (int i = start, j = pos; i < end; i++, j++) + value[j] = s.charAt(i); + pos += len; + return this; + } + + @Override + public Appendable append(char c) { + value[pos++] = c; + return this; + } + + @Override + public char charAt(int index) { + return value[index]; + } + + @Override + public CharSequence subSequence(int start, int end) { + if (start == end) { + return new CharsBuilder(Math.min(16, value.length)); + } + return new CharsBuilder(Arrays.copyOfRange(value, start, end)); + } + + @Override + public int length() { + return value.length; + } + + @Override + public String toString() { + return new String(value); + } + + public String leftStrip(char c) { + int i = leftOf(value, c); + return new String(value, i, value.length - i); + } + + public String rightStrip(char c) { + int i = rightOf(value, c); + return new String(value, 0, i); + } + + public static int leftOf(char[] chars, char pad) { + int i = 0, len = chars.length; + while (i < len && chars[i] == pad) i++; + return i; + } + + public static int rightOf(char[] chars, char pad) { + int i = 0, len = chars.length; + while ((i < len) && (chars[len - 1] <= pad)) len--; + return len; + } +} diff --git a/src/test/java/io/github/yezhihao/protostar/convert/AttributeConverterV2.java b/src/test/java/io/github/yezhihao/protostar/convert/AttributeConverterV2.java new file mode 100644 index 0000000..51318e1 --- /dev/null +++ b/src/test/java/io/github/yezhihao/protostar/convert/AttributeConverterV2.java @@ -0,0 +1,35 @@ +package io.github.yezhihao.protostar.convert; + +import io.github.yezhihao.protostar.PrepareLoadStrategy; +import io.github.yezhihao.protostar.converter.MapConverter; +import io.github.yezhihao.protostar.schema.NumberSchema; +import io.github.yezhihao.protostar.schema.StringSchema; +import io.netty.buffer.ByteBuf; + +public class AttributeConverterV2 extends MapConverter { + + @Override + protected void addSchemas(PrepareLoadStrategy schemaRegistry) { + schemaRegistry + .addSchema(1, NumberSchema.Int32.INSTANCE) + .addSchema(2, StringSchema.Chars.getInstance((byte) 0, "UTF-8")) + + .addSchema(3, Attr1.class) + .addSchema(4, Attr2.Schema.INSTANCE); + } + + @Override + protected Integer readKey(ByteBuf input) { + return (int) input.readUnsignedByte(); + } + + @Override + protected void writeKey(ByteBuf output, Integer key) { + output.writeByte(key); + } + + @Override + protected int valueSize() { + return 1; + } +} \ No newline at end of file