package encoding; /* * @Author: Wang Feng * @Description: 一个工具类,用来便捷的实现TLV编码 * @Version: 1.0.0 * @Date: 20:21 2021/3/5 * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class Encoder { //TODO 便于测试暂时先将private属性改成public了 public byte[] buffer; public int left; // 左指针 => 指向 Prepend* 操作下一个可以插入的位置 public int right; // 右指针 => 指向 Append* 操作下一个可以插入的位置 public boolean isInitial; // 是否初始化 public boolean isEstimator;// 是否仅测量编码后的长度,而不实际进行编码 public SizeT totalReserve; // 编码缓存数组的大小 public static final int MaxPacketSize=8800; /** * 编码测量初始化 * @Description: * 1. 一旦调用这个函数进行初始化,则调用所有的编码函数只会测量编码后的长度,不会执行实际的编码 */ public void estimatorReset(){ this.left=0; this.right=1; this.isInitial=true; this.isEstimator=true; this.totalReserve=new SizeT(Long.MAX_VALUE); } /** * 编码初始化 * @Description: * @param totalReserve 总的存储编码结果的数组长度 * @param reserveFromBack 默认情况下,左右指针都指向数组的最右侧,表示totalReserve指定的所有空间都是预留给 Prepend* 操作的 * reserveFromBack 可以指定需要预留多少空间给 Append*操作 */ public boolean encoderReset(SizeT totalReserve,SizeT reserveFromBack) throws EncoderException{ if(reserveFromBack.compareTo(totalReserve)>0){ throw new EncoderException("encoderReset: reserveFromBack > totalReserve"); } this.isInitial=true; this.isEstimator=false; this.totalReserve=totalReserve; int len=0; try { len=totalReserve.getVlIntValue2Int(); } catch (VlIntException e) { throw new EncoderException("encoderReset: "+e.getMessage()); } this.buffer=new byte[len]; //todo: 特殊情况下,可能越界。 this.left= (int) (totalReserve.subtract(reserveFromBack)-1);//todo: 特殊情况下,可能越界。 this.right= (int) 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 -1; } } /** * @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 -1; } } /** * 编码一个非负整数到一个数组当中 * todo: 越界问题 * @param uint64 * @return */ public static byte[] buildNonNegativeIntegerArr(long uint64){ VlInt vlInt=new VlInt(uint64); int len=vlInt.getVlIntBytes().length; if(uint64<=255){ return new byte[]{(byte) uint64}; }else { byte[] res = new byte[len - 1]; System.arraycopy(vlInt.getVlIntBytes(),1,res,0,len-1); return res; } } /** * 在前向插入一个非负整数,最大为 uint64::Max * todo: 越界问题 * @param uint64_value * @return */ public int prependNonNegativeInteger(long uint64_value) throws EncoderException { byte[] bytes=buildNonNegativeIntegerArr(uint64_value); return this.prependByteArray(bytes,new SizeT(bytes.length)); } /** * 在后向插入一个非负整数,最大为 uint64::Max * todo: 越界问题 * @param uint64_value * @return */ public int appendNonNegativeInteger(long uint64_value) throws EncoderException { byte[] bytes=buildNonNegativeIntegerArr(uint64_value); return this.appendByteArray(bytes,new SizeT(bytes.length)); } /** * @param array * @param size * @return 返回插入成功的字节数 */ public int prependByteArray(byte[] array,SizeT size) throws EncoderException { if(check(size)&&(size.compareTo(array.length)<=0)){ if(this.isEstimator){ this.left-=array.length; try { return size.getVlIntValue2Int(); } catch (VlIntException e) { throw new EncoderException("prependByteArray: "+e.getMessage()); } }else{ try { System.arraycopy(array,0,this.buffer, this.left-size.getVlIntValue2Int()+1,size.getVlIntValue2Int()); } catch (VlIntException e) { throw new EncoderException("prependByteArray: "+e.getMessage()); } this.left-=array.length; try { return size.getVlIntValue2Int(); } catch (VlIntException e) { throw new EncoderException("prependByteArray: "+e.getMessage()); } } } return -1; } /** * @param array * @param size * @return 返回插入成功的字节数 */ public int appendByteArray(byte[] array,SizeT size) throws EncoderException { if(check(size)&&(size.compareTo(array.length)<=0)){ if(this.isEstimator){ this.right+=array.length; try { return size.getVlIntValue2Int(); } catch (VlIntException e) { throw new EncoderException("appendByteArray: "+e.getMessage()); } }else{ try { System.arraycopy(array,0,this.buffer, this.right,size.getVlIntValue2Int()); } catch (VlIntException e) { throw new EncoderException("appendByteArray: "+e.getMessage()); } this.right+=array.length; try { return size.getVlIntValue2Int(); } catch (VlIntException e) { throw new EncoderException("appendByteArray: "+e.getMessage()); } } } return -1; } /** * 在前向插入一个可变长度的数字 * @param varNumber * @return */ public int prependVarNumber(VlInt varNumber) throws EncoderException { return this.prependByteArray(varNumber.getVlIntBytes(),new SizeT(varNumber.size())); } /** * 在后向插入一个可变长度的数字 * @param varNumber * @return */ public int appendVarNumber(VlInt varNumber) throws EncoderException { 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) throws EncoderException { 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) throws EncoderException { int totalLength=0; // Append TLV-TYPE totalLength+=this.appendVarNumber(tlvType); // Append TLV-LENGTH totalLength+=this.appendVarNumber(new VlInt(size)); // Append TLV-VALUE totalLength+=this.appendByteArray(array,size); return totalLength; } /** * 在前向插入一个 TLV Block * @param block * @return */ public int prependBlock(Block block) throws EncoderException { return this.prependByteArrayBlock(block.getType(),block.getValue(),new SizeT(block.getLength())); } /** * 在后向插入一个 TLV Block * @param block * @return */ public int appendBlock(Block block) throws EncoderException { return this.appendByteArrayBlock(block.getType(),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; } }