mirror of
https://gitee.com/willfree/min-dev-java.git
synced 2026-10-04 19:42:01 +08:00
334 lines
9.1 KiB
Java
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;
|
|
}
|
|
}
|
|
|