Files
min-dev-java/src/main/java/encoding/Block.java
T

334 lines
9.1 KiB
Java

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;
}
}