package encoding; import util.ByteHelper; import java.util.LinkedList; import java.util.List; /* * @Author: Wang Feng * @Description: * @Version: 1.0.0 * @Date: 14:19 2021/3/2 * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class Block { private VlInt tlvType; // TLV-TYPE private VlInt length; // TLV-LENGTH private byte[] value; // TLV-VALUE private ElementContainer elements; // TLV-sub-elements private byte[] raw; // TLV编码后的字节数组 public Block(){ this.tlvType=new VlInt(TLV.TlvInvalid); } /** * 从一个包含TLV的字节数组中构造一个 Block 对象 * @param buffer * @param verifyLength 是否要验证TLV的长度是否匹配,如果true, * 则会对比解析到的 TLV-LENGTH 与 TLV-VALUE的实际长度是否匹配 * @return */ public static Block createBlockByBuffer(byte[] buffer,boolean verifyLength){ if(buffer.length==0){ return null; } // 读取type VlInt tlvType=TLV.readType(buffer,new VlInt(0)); if(tlvType==null){ return null; } // 读取length VlInt tlvLength=TLV.readVarNumber(buffer,new VlInt(tlvType.size())); if(tlvLength==null){ return null; } return createBlockByTypeLengthBuffer(tlvType,tlvLength, ByteHelper.getLenBytes(buffer,new VlInt(tlvType.size()+tlvLength.size()), buffer.length-(tlvType.size()+tlvLength.size())),verifyLength); } /** * 传入 T、L、V 构造一个 TLV Block * @param tlvType * @param tlvLength * @param buffer * @param verifyLength * @return */ public static Block createBlockByTypeLengthBuffer(VlInt tlvType,VlInt tlvLength,byte[] buffer,boolean verifyLength){ return new Block(tlvType,tlvLength,buffer,verifyLength); } /** * 构造函数 * @param tlvType * @param tlvLength * @param buffer * @param verifyLength */ public Block(VlInt tlvType,VlInt tlvLength,byte[] buffer,boolean verifyLength){ this.tlvType=tlvType; this.length=tlvLength; // 检查长度是否正确 if(verifyLength && (!this.length.isEqual(buffer.length))){ //todo: 抛出异常 } // 设置 Raw Encoder encoder=new Encoder(); boolean resetBool=encoder.encoderReset(new SizeT(tlvType.size()+tlvLength.size()+buffer.length),new SizeT(0)); if(!resetBool){ //todo: 抛出异常 } if(encoder.prependByteArray(buffer,new SizeT(buffer.length))==0){ //todo: 抛出异常 } if(encoder.prependVarNumber(tlvLength)==0){ //todo: 抛出异常 } if(encoder.prependVarNumber(tlvType)==0){ //todo: 抛出异常 } byte[] encodedBuffer=encoder.getBuffer(); if(encodedBuffer==null){ //todo: 抛出异常 } this.raw=encodedBuffer; // 设置value this.value=buffer; } public Block(Block block){ this.tlvType=block.tlvType; this.length=block.length; this.value=block.value; this.elements=block.elements; this.raw=block.raw; } public VlInt getType() { return tlvType; } public void setType(VlInt tlvType) { this.tlvType = tlvType; } public VlInt getLength() { return length; } public void setLength(VlInt length) { this.length = length; } public byte[] getValue() { return value; } public void setValue(byte[] value) { this.value = value; } public byte[] getRaw() { return raw; } /** * 整个TLV编码后的大小,包含T和L * @return */ public SizeT Size(){ if(!this.isValid()){ return null; } return new SizeT(this.tlvType.size()+this.length.size()+this.value.length); } /** * 判断当前的 Block 对象是否含有 value * @return */ public boolean hasValue(){ return this.value.length!=0; } /** * 判断当前的 Block 对象是否含有 raw数组 * @return */ public boolean hasRaw(){ return this.raw.length!=0; } // ************** Sub-Elements ************** /** * 判断当前 TLV Block 是否包含子 TLV * 1. 每次通过 CreateBlockBy* 系列工厂方法构造出Block之后,需要手动调用 ParseSubElements 方法, * 才会去解析一级子TLV * @return */ public boolean hasSubElement(){ return this.elements.length()!=0; } /** * 获取所有的一级子TLV Block * * 1. 每次通过 CreateBlockBy* 系列工厂方法构造出Block之后,需要手动调用 ParseSubElements 方法, * * 才会去解析一级子TLV * @return */ public ElementContainer getSubElements(){ return this.elements; } /** * 从 value 字节数组中解析出所有的一级子 TLV Block * 1. 这要求这个TLV确实存在嵌套的子TLV,或者为空; * 2. 如果TLV的value不为空,且不存在嵌套的子TLV,则会抛出错误 * @return */ public boolean parseSubElements(){ if((this.value.length==0)||this.elements.length()!=0){ return true; } // 循环解析所有的一级子TLV for (int start = 0; start < this.value.length; start++) { // 读取 TLV-TYPE VlInt tlvType=TLV.readType(this.value,new VlInt(start)); if(tlvType==null){ this.clearElements(); return false; } start+=tlvType.size(); // 读取 TLV-LENGTH VlInt tlvLength=TLV.readVarNumber(this.value,new VlInt(start)); if(tlvType==null){ this.clearElements(); return false; } start+=tlvLength.size(); // 检查 buffer 中是否有足够的字节 if(tlvLength.add(start)>this.value.length){ this.clearElements(); return false; } // 创建一个子 TLV Block 并添加到elements当中 byte[] subBlockValue=new byte[tlvLength.getVlIntValue2Int()]; System.arraycopy(this.value,start,subBlockValue,0,tlvLength.getVlIntValue2Int()); Block block=createBlockByTypeLengthBuffer(tlvType,tlvLength,subBlockValue,true); if(block==null){ return false; } this.addElement(block); start+=tlvLength.getVlIntValue2Int(); } return true; } /** * 从 elements 中找到第一个指定type的子TLV * @param tlvType * @return */ public Block getElement(VlInt tlvType){ return this.elements.getElement(tlvType); } /** * 移除所有指定type的子tlv * @param tlvType */ public void removeElements(VlInt tlvType){ this.elements.removeElements(tlvType); } /** * 往 elements 中添加一个子tlv * @param block */ public void addElement(Block block){ this.elements.addElement(block); } /** * 清除 elements 中所有的子TLV */ public void clearElements(){ this.elements.clear(); } /** * 判断是否有效 * @return */ public boolean isValid(){ // return this.tlvType.isEqual(TLV.TlvInvalid); return !this.tlvType.isEqual(TLV.TlvInvalid); } /** * 将当前的 TLV Block 编码成字节数组,存放在 raw 当中 * @param encoder * @return */ public int encode(Encoder encoder){ // 如果已经有raw,则说明编码过,或者是解码而来的,不用在此Encode if(this.hasRaw()){ return encoder.prependByteArray(this.raw,new SizeT(this.raw.length)); } int len=0; // 编码 TLV-VALUE if(this.hasValue()){ // 如果设置了 value ,则直接使用 int tmplen=encoder.appendByteArray(this.value,new SizeT(this.value.length)); if(tmplen==0){ return 0; } len+=tmplen; }else{ // 如果 value 为空,则看 elements 中有没有子TLV Block,有则编码后插入 for(Block subBlock:this.elements.getElements()){ int tmplen=subBlock.encode(encoder); if(tmplen==0){ return 0; } len+=tmplen; } } // 编码 TLV-LENGTH int tmplen=encoder.prependVarNumber(new VlInt(len)); if(tmplen==0){ return 0; } len+=tmplen; // 编码 TLV-TYPE tmplen=encoder.prependVarNumber(this.tlvType); if(tmplen==0){ return 0; } len+=tmplen; return len; } }