From faf17d314cd7a83ca0adb39e3c4a7b09d524dd39 Mon Sep 17 00:00:00 2001 From: free will <2647778488@qq.com> Date: Fri, 5 Mar 2021 22:04:19 +0800 Subject: [PATCH 1/2] solve meaven error & writing encoder ... --- src/main/java/encoding/Block.java | 4 +- src/main/java/encoding/Encoder.java | 167 +++++++++++++++++++++++++++ src/main/java/encoding/SizeT.java | 25 +++- src/main/java/encoding/TLV.java | 4 +- src/main/java/encoding/VlInt.java | 13 ++- src/main/java/encoding/VlInt_V1.java | 2 +- src/main/java/util/ByteHelper.java | 4 +- 7 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 src/main/java/encoding/Encoder.java diff --git a/src/main/java/encoding/Block.java b/src/main/java/encoding/Block.java index cb92f54..0b796bd 100644 --- a/src/main/java/encoding/Block.java +++ b/src/main/java/encoding/Block.java @@ -1,6 +1,6 @@ -package main.java.encoding; +package encoding; -import main.java.util.ByteHelper; +import util.ByteHelper; import java.util.LinkedList; import java.util.List; diff --git a/src/main/java/encoding/Encoder.java b/src/main/java/encoding/Encoder.java new file mode 100644 index 0000000..2562083 --- /dev/null +++ b/src/main/java/encoding/Encoder.java @@ -0,0 +1,167 @@ +package encoding; + +/* + * @Author: Wang Feng + * @Description: 一个工具类,用来便捷的实现TLV编码 + * @Version: 1.0.0 + * @Date: 20:21 2021/3/5 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ +public class Encoder { + private byte[] buffer; + private int left; // 左指针 => 指向 Prepend* 操作下一个可以插入的位置 + private int right; // 右指针 => 指向 Append* 操作下一个可以插入的位置 + private boolean isInitial; // 是否初始化 + private boolean isEstimator;// 是否仅测量编码后的长度,而不实际进行编码 + private SizeT totalReserve; // 编码缓存数组的大小 + + /** + * 编码测量初始化 + * @Description: + * 1. 一旦调用这个函数进行初始化,则调用所有的编码函数只会测量编码后的长度,不会执行实际的编码 + */ + public void estimatorReset(){ + this.left=0; + this.right=1; + this.isInitial=true; + this.isEstimator=true; + this.totalReserve=new SizeT(Long.MAX_VALUE); //todo: 这里可能越界。 + } + + /** + * 编码初始化 + * @Description: + * @param totalReserve 总的存储编码结果的数组长度 + * @param reserveFromBack 默认情况下,左右指针都指向数组的最右侧,表示totalReserve指定的所有空间都是预留给 Prepend* 操作的 + * reserveFromBack 可以指定需要预留多少空间给 Append*操作 + */ + public boolean estimatorReset(SizeT totalReserve,SizeT reserveFromBack){ + if(reserveFromBack.compareTo(totalReserve)>0){ + return false; + } + this.isInitial=true; + this.isEstimator=false; + this.totalReserve=totalReserve; + this.buffer=new byte[totalReserve.getVlIntValue2Int()]; //todo: 特殊情况下,可能越界。 + this.left=totalReserve.subtract(reserveFromBack)-1;//todo: 特殊情况下,可能越界。 + this.right=totalReserve.subtract(reserveFromBack);//todo: 特殊情况下,可能越界。 + return true; + } + + /** + * 判断是否为空 + * @return + */ + public boolean empty(){ + return (this.left+1)>=this.right; + } + + /** + * 编码后的大小 + * @return + */ + public SizeT size(){ + return new SizeT(this.right-this.left-1); + } + + + /** + * 在每个操作之前进行有效性检查 + * @Description: + * 1. 首先检查 Encoder 实例有没有初始化,没有初始化则返回错误; + * 2. 然后检查预计新增 size 个字节,会不会超出最大包限制,超出则返回错误; + * 3. 否则返回 nil + * @param size + * @return + */ + public boolean check(SizeT size){ + if(!this.isInitial){ + return false; + } + if(this.totalReserve.compareTo(this.size().add(size))<0){ + return false; + } + return true; + } + + /** + * Prepend a byte + * @param value + * @return 返回成功插入的字节数 + */ + public int prependByte(byte value){ + if(this.isEstimator){ + this.left--; + return 1; + } + if(check(new SizeT(1))){ + this.buffer[this.left]=value; + this.left--; + return 1; + }else{ + return 0; + } + } + + /** + * @param value + * @return 返回插入成功的字节数 + */ + public int appendByte(byte value){ + if(this.isEstimator){ + this.right++; + return 1; + } + if(check(new SizeT(1))){ + this.buffer[this.right]=value; + this.right++; + return 1; + }else{ + return 0; + } + } + + + /** + * @param array + * @param size + * @return 返回插入成功的字节数 + */ + public int prependByteArray(byte[] array,SizeT size){ + if(check(size)&&(size.compareTo(array.length)<=0)){ + if(this.isEstimator){ + this.left-=array.length; + return size.getVlIntValue2Int(); + }else{ + System.arraycopy(array,0,this.buffer, + this.left-size.getVlIntValue2Int()+1,size.getVlIntValue2Int()); + this.left-=array.length; + return size.getVlIntValue2Int(); + } + } + return 0; + } + + /** + * @param array + * @param size + * @return 返回插入成功的字节数 + */ + public int appendByteArray(byte[] array,SizeT size){ + if(check(size)&&(size.compareTo(array.length)<=0)){ + if(this.isEstimator){ + this.right+=array.length; + return size.getVlIntValue2Int(); + }else{ + System.arraycopy(array,0,this.buffer, + this.right,size.getVlIntValue2Int()); + this.right+=array.length; + return size.getVlIntValue2Int(); + } + } + return 0; + } + + + +} diff --git a/src/main/java/encoding/SizeT.java b/src/main/java/encoding/SizeT.java index 0d6c599..9a20daf 100644 --- a/src/main/java/encoding/SizeT.java +++ b/src/main/java/encoding/SizeT.java @@ -1,4 +1,4 @@ -package main.java.encoding; +package encoding; import java.math.BigInteger; @@ -7,6 +7,7 @@ import static java.lang.Math.pow; /* * @Author: Wang Feng * @Description:变长无符号整型,用于表示TLV中的T和L + * todo: 本类需要在VlInt经过彻底测试之后,再进行完善。或可直接继承vlint * @Version: 1.0.0 * @Date: 18:13 2021/3/1 * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 @@ -68,22 +69,27 @@ public class SizeT { this.VlIntBytes=bigInteger2vlintBytes(this.VlIntValue); } + public SizeT(long l){ + this.VlIntValue=BigInteger.valueOf(l); + this.VlIntBytes=bigInteger2vlintBytes(this.VlIntValue); + } + // todo:传入一个long,将它解析成一个VlInt // 将vlint转为一个int输出:需要判断size是不是小于4(1 or 3) - public Integer getVlIntValue2Int(){ + public int getVlIntValue2Int(){ if(this.SizeOfVarNumber()<4){ return VlIntValue.intValue(); } - return null; + return Integer.parseInt(null); } // 将vlint转为一个long输出:需要判断size是不是小于8(5) - public Long getVlIntValue2Long(){ + public long getVlIntValue2Long(){ if(this.SizeOfVarNumber()<8){ return VlIntValue.longValue(); } - return null; + return Long.parseLong(null); } // 将vlint转为一个biginteger输出:需要判断size是不是等于9(9) @@ -113,6 +119,15 @@ public class SizeT { // todo: 判断vlint是否与某个long值相等 + /** + * 增加VlInt + * @param vlInt + * @return + */ + public int add(SizeT vlInt){ + return this.VlIntValue.add(vlInt.VlIntValue).intValue(); + } + /** * 判断与另一个VlInt的数值孰大孰小 * @param vlInt diff --git a/src/main/java/encoding/TLV.java b/src/main/java/encoding/TLV.java index 6a87749..c6d89d0 100644 --- a/src/main/java/encoding/TLV.java +++ b/src/main/java/encoding/TLV.java @@ -1,7 +1,7 @@ -package main.java.encoding; +package encoding; -import main.java.util.ByteHelper; +import util.ByteHelper; /* * @Author: Wang Feng diff --git a/src/main/java/encoding/VlInt.java b/src/main/java/encoding/VlInt.java index ea5ab5f..08851d4 100644 --- a/src/main/java/encoding/VlInt.java +++ b/src/main/java/encoding/VlInt.java @@ -1,7 +1,7 @@ -package main.java.encoding; +package encoding; -import main.java.util.ByteHelper; +import util.ByteHelper; import java.math.BigInteger; @@ -171,6 +171,15 @@ public class VlInt { return this.VlIntValue.subtract(vlInt.VlIntValue).intValue(); } + /** + * 增加VlInt + * @param vlInt + * @return + */ + public int add(VlInt vlInt){ + return this.VlIntValue.add(vlInt.VlIntValue).intValue(); + } + /** * 将BigInteger转为byte[按照变长无符号整数方式转] * @param bigInteger diff --git a/src/main/java/encoding/VlInt_V1.java b/src/main/java/encoding/VlInt_V1.java index 1d74a4e..69e9f97 100644 --- a/src/main/java/encoding/VlInt_V1.java +++ b/src/main/java/encoding/VlInt_V1.java @@ -1,4 +1,4 @@ -package main.java.encoding; +package encoding; import static java.lang.Math.pow; diff --git a/src/main/java/util/ByteHelper.java b/src/main/java/util/ByteHelper.java index fa2856a..8132d72 100644 --- a/src/main/java/util/ByteHelper.java +++ b/src/main/java/util/ByteHelper.java @@ -1,7 +1,7 @@ -package main.java.util; +package util; -import main.java.encoding.VlInt; +import encoding.VlInt; /* * @Author: Wang Feng From 6fddbff83356c71e3da002c5b6c9281ab33060c6 Mon Sep 17 00:00:00 2001 From: free will <2647778488@qq.com> Date: Sat, 6 Mar 2021 16:20:17 +0800 Subject: [PATCH 2/2] finished encoder --- src/main/java/encoding/Block.java | 8 +-- src/main/java/encoding/Encoder.java | 79 ++++++++++++++++++++++++++++- src/main/java/encoding/SizeT.java | 24 ++++++--- src/main/java/encoding/VlInt.java | 36 +++++++++++-- 4 files changed, 131 insertions(+), 16 deletions(-) diff --git a/src/main/java/encoding/Block.java b/src/main/java/encoding/Block.java index 0b796bd..e3fb196 100644 --- a/src/main/java/encoding/Block.java +++ b/src/main/java/encoding/Block.java @@ -50,14 +50,14 @@ public class Block { } // 读取length - VlInt tlvLength=TLV.readVarNumber(buffer,new VlInt(tlvType.SizeOfVarNumber())); + VlInt tlvLength=TLV.readVarNumber(buffer,new VlInt(tlvType.size())); if(tlvLength==null){ return null; } return createBlockByTypeLengthBuffer(tlvType,tlvLength, - ByteHelper.getLenBytes(buffer,new VlInt(tlvType.SizeOfVarNumber()+tlvLength.SizeOfVarNumber()), - buffer.length-(tlvType.SizeOfVarNumber()+tlvLength.SizeOfVarNumber())),verifyLength); + ByteHelper.getLenBytes(buffer,new VlInt(tlvType.size()+tlvLength.size()), + buffer.length-(tlvType.size()+tlvLength.size())),verifyLength); } /** @@ -130,7 +130,7 @@ public class Block { if(!this.isValid()){ return null; } - return new SizeT(this.tlvType.SizeOfVarNumber()+this.length.SizeOfVarNumber()+this.value.length); + return new SizeT(this.tlvType.size()+this.length.size()+this.value.length); } /** diff --git a/src/main/java/encoding/Encoder.java b/src/main/java/encoding/Encoder.java index 2562083..cda4c63 100644 --- a/src/main/java/encoding/Encoder.java +++ b/src/main/java/encoding/Encoder.java @@ -162,6 +162,83 @@ public class Encoder { return 0; } - + /** + * 在前向插入一个可变长度的数字 + * @param varNumber + * @return + */ + public int prependVarNumber(VlInt varNumber){ + return this.prependByteArray(varNumber.getVlIntBytes(),new SizeT(varNumber.size())); + } + /** + * 在后向插入一个可变长度的数字 + * @param varNumber + * @return + */ + public int appendVarNumber(VlInt varNumber){ + return this.appendByteArray(varNumber.getVlIntBytes(),new SizeT(varNumber.size())); + } + + //todo: 在前向&后向插入一个非负整数 + + /** + * 根据TLV-TYPE和一个字节数组,在前向插入一个 TLV Block + * @param tlvType + * @param array + * @param size + * @return + */ + public int prependByteArrayBlock(VlInt tlvType,byte[] array,SizeT size){ + int totalLength=this.prependByteArray(array,size); + totalLength+=this.prependVarNumber(new VlInt(size)); + totalLength+=this.prependVarNumber(tlvType); + return totalLength; + } + + /** + * 根据TLV-TYPE和一个字节数组,在后向插入一个 TLV Block + * @param tlvType + * @param array + * @param size + * @return + */ + public int appendByteArrayBlock(VlInt tlvType,byte[] array,SizeT size){ + int totalLength=this.appendByteArray(array,size); + totalLength+=this.appendVarNumber(new VlInt(size.getVlIntValue2Long())); + totalLength+=this.appendVarNumber(tlvType); + return totalLength; + } + + /** + * 在前向插入一个 TLV Block + * @param block + * @return + */ + public int prependBlock(Block block){ + return this.prependByteArrayBlock(block.getTlvType(),block.getValue(),new SizeT(block.getLength())); + } + + /** + * 在后向插入一个 TLV Block + * @param block + * @return + */ + public int appendBlock(Block block){ + return this.appendByteArrayBlock(block.getTlvType(),block.getValue(),new SizeT(block.getLength())); + } + + /** + * 获取编码后的字节数组 + * @return + */ + public byte[] getBuffer() { + if((!this.isInitial)||this.isEstimator){ + return null; + } + int len=this.right-this.left-1; + byte[] res=new byte[len]; + System.arraycopy(this.buffer,this.left+1,res,0,len); + return res; + } } diff --git a/src/main/java/encoding/SizeT.java b/src/main/java/encoding/SizeT.java index 9a20daf..264e345 100644 --- a/src/main/java/encoding/SizeT.java +++ b/src/main/java/encoding/SizeT.java @@ -7,7 +7,7 @@ import static java.lang.Math.pow; /* * @Author: Wang Feng * @Description:变长无符号整型,用于表示TLV中的T和L - * todo: 本类需要在VlInt经过彻底测试之后,再进行完善。或可直接继承vlint + * todo: 本类需要在VlInt经过彻底测试之后,再进行完善。或可直接继承vlint,或可内包装一个VlInt. * @Version: 1.0.0 * @Date: 18:13 2021/3/1 * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 @@ -17,13 +17,15 @@ public class SizeT { private byte[] VlIntBytes; // 变长整数表示的真实数值 private BigInteger VlIntValue; + // 变长整数的长度: 1 3 5 9 ... + private int size; /** * 测量一个变长整型实际用几个字节表示 * @return */ - public int SizeOfVarNumber(){ - return SizeOfVarNumber(this.VlIntValue); + public int size(){ + return this.size; } private static int SizeOfVarNumber(BigInteger bigInteger){ if(bigInteger.compareTo(BigInteger.valueOf(Long.parseLong("241"))) < 0){ @@ -48,6 +50,12 @@ public class SizeT { this.VlIntValue=vlintBytes2bigInteger(bytes); } + public SizeT(VlInt vlInt){ + this.VlIntBytes=vlInt.getVlIntBytes(); + this.VlIntValue=vlInt.getVlIntValue(); + this.size = vlInt.size(); + } + public SizeT(BigInteger bigInteger){ this.VlIntValue=bigInteger; this.VlIntBytes=bigInteger2vlintBytes(bigInteger); @@ -63,6 +71,10 @@ public class SizeT { return new SizeT(bigInteger); } + public byte[] getVlIntBytes(){ + return this.VlIntBytes; + } + // todo:传入一个int,将它解析成一个VlInt public SizeT(int i){ this.VlIntValue=new BigInteger(String.valueOf(i)); @@ -78,7 +90,7 @@ public class SizeT { // 将vlint转为一个int输出:需要判断size是不是小于4(1 or 3) public int getVlIntValue2Int(){ - if(this.SizeOfVarNumber()<4){ + if(this.size()<4){ return VlIntValue.intValue(); } return Integer.parseInt(null); @@ -86,7 +98,7 @@ public class SizeT { // 将vlint转为一个long输出:需要判断size是不是小于8(5) public long getVlIntValue2Long(){ - if(this.SizeOfVarNumber()<8){ + if(this.size()<8){ return VlIntValue.longValue(); } return Long.parseLong(null); @@ -94,7 +106,7 @@ public class SizeT { // 将vlint转为一个biginteger输出:需要判断size是不是等于9(9) public BigInteger getVlIntValue(){ - if(this.SizeOfVarNumber()>=9){ + if(this.size()>=9){ return VlIntValue; } return null; diff --git a/src/main/java/encoding/VlInt.java b/src/main/java/encoding/VlInt.java index 08851d4..72ee337 100644 --- a/src/main/java/encoding/VlInt.java +++ b/src/main/java/encoding/VlInt.java @@ -20,6 +20,8 @@ public class VlInt { private byte[] VlIntBytes; // 变长整数表示的真实数值 private BigInteger VlIntValue; + // 变长整数的长度: 1 3 5 9 ... + private int size; // 一些int常量 // @Description: @@ -32,12 +34,17 @@ public class VlInt { public static final int VlIntExtend4=242; public static final int VlIntExtend8=243; + public static final int VlIntSize1=1; + public static final int VlIntSize3=3; + public static final int VlIntSize5=5; + public static final int VlIntSize9=9; + /** * 测量一个变长整型实际用几个字节表示 * @return */ - public int SizeOfVarNumber(){ - return SizeOfVarNumber(this.VlIntValue); + public int size(){ + return this.size; } private static int SizeOfVarNumber(BigInteger bigInteger){ if(bigInteger.compareTo(BigInteger.valueOf(241)) < 0){ @@ -54,27 +61,42 @@ public class VlInt { } //todo:判断bytes是否是一个合法的变长非负整型 + private boolean isValidVlIntBytes(){ + return true; + } //todo:判断biginteger是否合法 public VlInt(byte[] bytes){ this.VlIntBytes=bytes; this.VlIntValue=vlintBytes2bigInteger(bytes); + if(this.VlIntValue != null) { + this.size = SizeOfVarNumber(this.VlIntValue); + } } public VlInt(BigInteger bigInteger){ this.VlIntValue=bigInteger; this.VlIntBytes=bigInteger2vlintBytes(bigInteger); + this.size=SizeOfVarNumber(this.VlIntValue); + } + + public VlInt(SizeT sizeT){ + this.VlIntBytes=sizeT.getVlIntBytes(); + this.VlIntValue=sizeT.getVlIntValue(); + this.size = sizeT.size(); } public VlInt(int i){ this.VlIntValue=BigInteger.valueOf(i); this.VlIntBytes=bigInteger2vlintBytes(this.VlIntValue); + this.size=SizeOfVarNumber(this.VlIntValue); } public VlInt(long l){ this.VlIntValue=BigInteger.valueOf(l); this.VlIntBytes=bigInteger2vlintBytes(this.VlIntValue); + this.size=SizeOfVarNumber(this.VlIntValue); } // 传入一个变长无符号字节数组byte[],将它解析成一个VlInt @@ -87,12 +109,16 @@ public class VlInt { return new VlInt(bigInteger); } + public byte[] getVlIntBytes(){ + return this.VlIntBytes; + } + /** * 将vlint转为一个int输出:需要判断size是不是小于4(1 or 3) * @return */ public int getVlIntValue2Int(){ - if(this.SizeOfVarNumber()<4){ + if(this.size()<4){ return VlIntValue.intValue(); } return Integer.parseInt(null); @@ -103,7 +129,7 @@ public class VlInt { * @return */ public long getVlIntValue2Long(){ - if(this.SizeOfVarNumber()<8){ + if(this.size()<8){ return VlIntValue.longValue(); } return Long.parseLong(null); @@ -114,7 +140,7 @@ public class VlInt { * @return */ public BigInteger getVlIntValue(){ - if(this.SizeOfVarNumber()>=9){ + if(this.size()>=9){ return VlIntValue; } return null;